CSSだけで関数が書ける? @functionの衝撃

CSSプリプロセッサ(Sass、Less)に依存せず、CSSだけで関数を定義できる時代が到来しました。それが@function at-ruleです。この機能はCSS Custom Functions and Mixins Module Level 1仕様で定義されており、Sassの@functionと似ていますが、ブラウザが直接ランタイムで評価する点が決定的に異なります。

Sass @functionとの違い: Sassはコンパイル時に評価されるため静的な値しか返せませんが、CSS @functionはビューポートサイズやコンテナクエリなどの動的な環境に応じて結果を変えられます。

この記事では、QiitaやZennでよく見られる実践的なコード例を交えながら、CSS @functionのすべてを解説します。併せて、Azure IaaSの多層防御アーキテクチャをSFI原則で実現するガイドもご参照ください。

基本構文:関数名から戻り値まで

関数名は必ず--(ダッシュ2つ)で始めます。CSSカスタムプロパティと同じ命名規則で、大文字小文字を区別します。

/* 最もシンプルな関数:引数の半分を返す */
@function --half(--size) {
  result: calc(var(--size) / 2);
}

.container {
  margin-inline: --half(20px); /* 10px と評価 */
}

関数の構成要素

  • --function-token: --halfのように2つのダッシュで始まる識別子
  • (): 引数リスト(省略可能、複数指定可)
  • returns: 戻り値の型を指定(省略可能。省略時は任意の型を許可)
  • result: 実際の戻り値を定義する必須ディスクリプタ

型チェックで安全な関数を

JavaScriptと同様、CSS関数でも引数と戻り値の型を指定できます。@propertyと似た記法で、山括弧< >を使用します。

/* 数値のみ受け付け、パーセントを返す関数 */
@function --progression(--current, --total) returns {
  result: calc(var(--current) / var(--total) * 100%);
}

.progress-bar {
  width: --progression(3, 5); /* 60% */
}

複数の型を許可するにはtype()関数と|セパレータを使います。

@function --transparent(--color, --alpha type(|)) {
  result: rgb(from var(--color) r g b / var(--alpha));
}

実務のコツ: 型チェックは大規模プロジェクトでのバグ早期発見に役立ちます。特にデザインシステムのトークン値計算で真価を発揮します。

高度な機能:リスト、デフォルト値、ネスト、カスケード

カンマ区切りリストの処理

CSS関数の呼び出しではカンマが引数の区切りとして機能します。リストそのものを1つの引数として渡すには、中括弧{}で囲み、パラメータに#サフィックスを付けます。

@function --get-range(--list#, --n) {
  result: calc(max(var(--list)) - min(var(--list)) + var(--n));
}

div {
  padding-block: --get-range({10px, 100px, 50px, 25px}, 200px); /* 290px */
}

デフォルト値の設定

関数の引数にデフォルト値を指定できます。コロン(:)の後にデフォルト値を記述します。

@function --brand-glass(--opacity: 0.5) returns {
  result: rgb(10 120 255 / var(--opacity));
}

.header {
  background: --brand-glass();       /* 0.5 が適用 */
}
.header:hover {
  background: --brand-glass(0.8);    /* 0.8 でオーバーライド */
}

関数のネストとローカル変数

関数の中で別の関数を呼び出したり、ローカルスコープのカスタムプロパティを使用できます。ローカル変数は関数の外に漏れないため安全です。

@function --square(--n) {
  result: calc(var(--n) * var(--n));
}

@function --circle-area(--radius) {
  --pi: 3.14159;
  result: calc(var(--pi) * --square(var(--radius)));
}

.blob {
  width: calc(--circle-area(10) * 1px); /* 314.159px */
}

CSSカスケードと条件分岐

resultディスクリプタはCSSカスケードのルールに従います。そのため、@media@container@supportsの中にresultをネストして条件付きの戻り値を実現できます。

@function --suitable-font-size() returns {
  result: 16px;
  @media (width > 1000px) {
    result: 20px;
  }
}

body {
  font-size: --suitable-font-size(); /* 1000px超なら20px、それ以外は16px */
}

注意: 最後に宣言されたresultが優先されます。上記の例で@mediaブロックの外にresult: 16pxを先に書き、メディアクエリの中にresult: 20pxを書くと、常に16pxだけが返ります。

ブラウザサポート状況とフォールバック戦略

現時点(2025年)では、@functionは**Chrome 148+**でのみ実験的にサポートされています。Firefox、Safari、Edgeは未サポートです。そのため、プロダクションで使用するにはフォールバックが必須です。

/* @supports で機能検出 */
@supports (at-rule(@function)) {
  .container {
    margin-inline: --half(20px);
  }
}

/* フォールバック: @function非対応時はデフォルト値を使用 */
.container {
  margin-inline: 10px; /* フォールバック */
}

皮肉な話: @supports自体もすべてのブラウザで完全にサポートされているわけではありません。CSS Drafts Issue #2463で議論が続いているため、実際に使う前にCan I Useなどで必ず確認してください。

CSS @functionの制限と注意点

  1. 副作用(Side Effect)不可: 関数は1つの値しか返せません。複数のプロパティを一度に生成したりスタイルを変更したりすることはできません。この課題は提案中の@mixin at-ruleが解決する予定です。
  2. 循環参照禁止: 関数AがBを、BがAを呼び出すと、ブラウザが検出して両方の関数を無効にします。カスタムプロパティを介した間接的な循環も同様です。
  3. ブラウザサポートが極めて限定的: プロダクションでの使用は時期尚早です。学習目的で先行体験しつつ、実際のサービスには必ずフォールバックを含めてください。

日本市場における適用コンテキスト

日本のWeb開発現場では、依然としてSassの利用が主流です。しかし、CSS @functionがブラウザサポートを拡大すれば、以下のような場面で強力なツールになります。

  • デザインシステムのトークン計算: レスポンシブなタイポグラフィスケールやスペーシングシステムをCSS関数で定義し、ビルドツールなしで動的計算が可能に
  • ランタイムテーマ切り替え: ユーザー設定(ダークモードなど)に応じて関数の結果が変化するように設計
  • CDN配布の軽量CSSライブラリ: ビルドステップ不要でそのまま使えるユーティリティCSS

次のステップ

  1. 公式仕様 CSS Custom Functions and Mixins Module Level 1 を読む
  2. @mixin at-ruleの提案を追跡する(関数と違い複数のスタイルを生成可能)
  3. Chrome Canaryで実際に実験し、CSS Tricksの@functionアルマナック を参照(本記事の元ネタ)

併せて、従来のソフトウェアテストは終わった:エージェンティック開発時代のJiTTest革命もご一読ください。CSSのパラダイムシフトとソフトウェア開発方法論の変化は、意外なほど深く結びついています。

CSS custom function @function at-rule syntax example on code editor Algorithm Concept Visual

実践例:CSS関数でレスポンシブグリッドシステムを作る

以下は@functionを活用したレスポンシブグリッドシステムの例です。コンテナ幅とカラム数を引数に受け取り、各カラムの幅を計算します。

/* グリッドカラム幅計算関数 */
@function --grid-column-width(--container-width, --columns) returns {
  result: calc(var(--container-width) / var(--columns));
}

/* デフォルト値を持つギャップ計算関数 */
@function --grid-gap(--base-gap: 16px) returns {
  result: var(--base-gap);
}

.grid {
  display: grid;
  grid-template-columns: 
    --grid-column-width(1200px, 12) 
    var(--grid-gap()) 
    --grid-column-width(1200px, 12);
  
  /* 1200px / 12 = 100px, gapは16px */
  /* 結果: 100px 16px 100px */
}

/* レスポンシブ: コンテナクエリと組み合わせ */
@container (min-width: 800px) {
  .grid {
    grid-template-columns: repeat(3, --grid-column-width(100%, 3));
  }
}

この例は現在のブラウザでは動作しませんが、未来のCSSアーキテクチャがどのように進化するかを示しています。今から概念を身につけておけば、ブラウザサポートが拡大したときにすぐに活用できます。

Developer testing native CSS @function on browser developer tools Technical Structure Concept

CSS @function vs Sass @function 比較表

項目CSS @functionSass @function
評価タイミングランタイム(ブラウザ)コンパイルタイム
動的環境への応答可能(メディアクエリ、コンテナクエリなど)不可(静的)
型チェックreturnsディスクリプタで明示的型検証なし(JavaScript関数のように動的)
副作用不可(値のみ返す)不可(値のみ返す)
循環参照検出ブラウザが自動検出・無効化コンパイラが検出(エラー発生)
ブラウザサポートChrome 148+(実験的)全環境(プリプロセッサ使用時)
エコシステム仕様初期段階、ライブラリ不足成熟(Bourbon、Compassなど)

注意点まとめ

  • プロダクション利用禁止: 現在はChrome 148+でしか動作しません。学習目的に限定してください。
  • フォールバック必須: @supportsで検出するか、プリプロセッサとの併用を検討してください。
  • 循環参照に注意: 関数間の呼び出しグラフを常にチェックしてください。
  • 名前の衝突: --で始まる名前はカスタムプロパティと同じ名前空間を共有します。意図しないオーバーライドに注意。

Modern CSS architecture with custom functions and cascade layers IT Technology Image

まとめ:CSSの未来は今から準備しよう

CSS @functionは単なる構文追加ではありません。これはCSSが静的な宣言言語から動的計算が可能なプログラミング言語へと進化する合図です。現時点ではブラウザサポートが限定的ですが、1~2年以内に主要ブラウザに搭載される可能性は高いでしょう。

今から@functionの概念と構文を身につけておけば、未来のCSSアーキテクチャ設計に大いに役立ちます。特にデザインシステム、レスポンシブコンポーネント、テーマ管理で強力な武器になるでしょう。

一行まとめ: CSS @functionはまだ実験段階ですが、「CSSで関数を書く」というパラダイムシフトを理解することが重要です。フォールバック戦略とともに、ゆっくり学習を始めてみてください。

合わせて読みたい記事:

本コンテンツは、信頼性の高い情報源をもとにAIツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。