CSS random()がChrome 156に到達──JSなしで「毎回違う配置」を作る
ktkt約12分で読めますNEW

CSS random()がChrome 156に到達──JSなしで「毎回違う配置」を作る

技術メモ

カードを少しだけ傾けたい、背景に星を散らしたい、要素ごとにアニメーションの開始をずらしたい。こうした「少しずつ違う見た目」は、これまでJavaScriptで乱数を振ってstyleを書き換えるか、ビルド時に複数パターンを生成するのが定番でした。CSSのrandom()は、その揺らぎをスタイルシートの中だけで完結させます。

Safari 26.2が2025年12月12日に先行実装し、2026年10月20日にstableとなったChrome 156が追随しました。Firefoxはまだ既定で無効で、Baselineにも入っていません。この記事では、構文と「値の共有」の考え方、実装例、名前変更という落とし穴、そして実務で使うかどうかの判断までを整理します。

30秒でわかる結論

  • Chrome 156(2026年10月20日 stable)でrandom()が利用可能になった。Safariは26.2(2025年12月12日)が先行。
  • random(最小, 最大)とrandom(最小, 最大, 刻み)の形で、長さ・角度・色相などに乱数を埋め込める。
  • 同じ乱値を複数のプロパティで共有するかは、第1引数の<random-key>で決める。省略時は呼び出しごとに新しい値になる。
  • Safari 26.5で名前付きの共有範囲が変わり、element-sharedは削除、element-scopedが追加された。2025年の解説記事のコードはそのままでは動かない。
  • Firefoxは未対応(158時点では実験フラグ)。装飾用途に限定し、@supportsでフォールバックを置くのが現実的。

何が起きたのか:Safari先行、Chromeが追随

Chrome 156のリリースノートにrandom()が記載されました。例として、絶対配置した要素のtopとleftにrandom(0%, 100%)を指定するコードが示されています。仕様はCSS Values and Units Module Level 5です。

時系列で見ると、Safari 26.2が2025年12月12日にいち早く実装しました。その後、CSS Working Groupでの議論を経て、Safari 26.5(2026年5月)で名前付き乱値の扱いが変更されています。Chromeはそれに合わせた形でstableに到達しました。つまり、この機能は「出た瞬間の仕様」と「今の仕様」が異なる過渡期にあります。

Firefoxは158の時点でlayout.css.random.enabledという実験フラグの内側にあり、既定では無効です。MDNはLimited availability、つまりBaseline未到達として扱っています。

2025年8月のWebKitブログはelement-sharedというキーワードを紹介しています。これは後の議論で削除され、現在はelement-scopedに置き換わりました。ネット上のサンプルをコピーするときは、どちらの世代の仕様かを確認してください。

基本構文と「値の共有」

もっとも単純な形はrandom(最小, 最大)です。3つ目の引数は刻み幅で、random(0, 100, 10)なら0から100まで10刻みの値になります。最小・最大・刻みは同じデータ型である必要があり、長さなら長さ、角度なら角度で揃えます。

クセがあるのは任意の第1引数<random-key>です。これは乱数の種をどの範囲で共有するかを決めます。主な値を整理します。

キー

共有される範囲

使いどころ

省略 / auto

呼び出しごとに独立

星を散らす、要素ごとに違う色にする

element-scoped

同じ要素の複数プロパティで共有

幅と高さを揃えて正方形にする

property-scoped

同じプロパティなら全要素で共有

カード全体を同じサイズに揃える

property-index-scoped

プロパティと記述位置ごとに共有

ショートハンドの各辺を別々に固定

--name

同じ識別子を使う全要素・全プロパティ

ページ全体で1つの乱値を再利用

fixed 0.5

乱数を固定値として扱う

テスト・スクリーンショットの再現

この表で重要なのは、--nameだけを書いた場合の共有範囲が「文書全体」だという点です。Safari 26.5より前は要素単位でした。マイナーな変更に見えますが、同じCSSでも見た目が変わります。

JS乱数との比較

JavaScriptで乱数を振る場合と、CSSで振る場合の違いを整理します。どちらが優れているという話ではなく、責務の置き場所が変わります。

観点

JavaScript

CSS random()

実行タイミング

マウント後。ハイドレーション待ちが出る

スタイル解決時。初期表示から反映される

SSRとの相性

サーバーとクライアントで値がずれやすい

サーバー生成のHTMLにそのまま乗る

再現性

シードを渡せば制御できる

基本は毎回変わる。fixedで固定可能

テスト

乱数関数をモックできる

ビジュアルリグレッションとは相性が悪い

向く用途

業務ロジック、抽選、ID生成

装飾、配置の揺らぎ、生成的な見た目

迷ったときの基準は単純です。「その乱数がユーザーにとって意味を持つか」がYesならJavaScript、「見た目の揺らぎでしかない」ならCSSに置く。抽選結果やA/Bテストの割り当てをCSSで決めてはいけません。値が再現できず、計測もできません。

使い方・最小実装

まずは星空の背景です。各要素の位置とサイズをrandom()で決めます。位置はパーセント、サイズはピクセルで、それぞれ独立した乱数になります。

CSS
.star {
  position: fixed;
  width: random(2px, 10px, 1px);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: #fff;
  top: random(0%, 100%);
  left: random(0%, 100%);
}

3つ目の引数1pxは刻み幅です。これがないと3.4271pxのような半端なサイズになり、ぼやけた印象になります。刻みを指定すると、意図した粒度でばらつきます。

次に、幅と高さを揃えて「正方形のまま」ランダムにしたい場合です。単にrandom()を2回書くと、幅と高さが別々の値になり、長方形になります。ここでelement-scopedと名前付き識別子を使います。

CSS
.particle {
  border-radius: 50%;
  background: #fff;
  position: fixed;
  width: random(--particle-size element-scoped, 4px, 16px, 1px);
  height: random(--particle-size element-scoped, 4px, 16px, 1px);
  top: random(0%, 100%);
  left: random(0%, 100%);
}

--particle-sizeが同じ値を指し、element-scopedが「要素ごとに別の値」を保証します。要素Aは8px四方、要素Bは13px四方、といった具合です。element-scopedを外すと、全要素が同じサイズの正方形になります。

カードの一覧などで「全部同じランダムサイズ」にしたい場合はproperty-scopedが便利です。

CSS
.card {
  width: random(property-scoped, 160px, 240px);
  min-height: random(property-scoped, 120px, 200px);
  rotate: random(-2deg, 2deg);
}

widthとmin-heightはプロパティが違うため、property-scopedでは別々の乱数になります。すべてのカードで幅は同じ、高さも同じ、しかし回転はカードごとに違う、という組み合わせが作れます。

カスタムプロパティにrandom()を入れて使い回せる?→ 単純なvar()では値は保存されません。カスタムプロパティはテキスト置換のように展開されるため、参照のたびに新しい乱数になります。計算済みの値を保持したい場合は@propertyで登録してください。

アニメーションへの応用

random()は@keyframesの中でも使えます。ルーレットのように、毎回止まる位置が変わる演出はその代表例です。

CSS
@keyframes spin {
  from {
    rotate: 0deg;
  }
  to {
    rotate: 10turn; /* 未対応ブラウザ向けのフォールバック */
    rotate: random(2turn, 10turn, 20deg);
  }
}

同じプロパティに対して2回toを書いています。CSSのカスケードでは、未対応の値は無効として捨てられ、直前の有効な宣言が残ります。@supportsを書かなくても、この順序だけでフォールバックになります。

アニメーションの遅延をランダムにしたい場合も同じです。animation-delay: random(0s, 2s, 0.1s)のように指定すれば、要素が一斉に動き出す機械的な印象を消せます。

prefers-reduced-motion: reduceの環境では、ランダムな動きを止める配慮が必要です。装飾目的のアニメーションは、メディアクエリの中でanimation: noneに落としてください。

落とし穴:名前と共有範囲が変わった

実装でつまずきやすいのは、乱数の生成そのものより「どの値が共有されるか」です。とくに次の3点は、古い情報と現在の挙動が食い違います。

  • 名前付きの既定がグローバルに変わった。Safari 26.5以降、random(--size, 100px, 200px)は全要素で同じ値になります。以前は要素ごとに別の値でした。
  • element-sharedは削除された。代わりにelement-scopedを使います。2025年のデモをそのまま持ってくると、意図と違う結果になります。
  • autoの自動キーはプロパティ名と位置から生成される。MDNは、:hoverで同じプロパティに同じrandom()を書くと値が変わらない例を挙げています。状態ごとに変えたい場合は、明示的な識別子を渡します。

「思ったより全部同じサイズになる」「ホバーしても位置が変わらない」という症状が出たら、まず第1引数を疑ってください。乱数が壊れているのではなく、共有範囲が想定と違うだけです。

実務への影響

効果がわかりやすいのは、装飾のためのJavaScriptを減らせる点です。パーティクル、紙吹雪、星座、写真の山積み、付箋の貼り付け風レイアウトなど、これまでライブラリを入れていた表現がCSSだけで済みます。サーバーサイドレンダリングのページでも、初期HTMLの時点で配置が決まるため、ハイドレーション後のちらつきもありません。

一方で、業務要件には向きません。商品の並び順、抽選、パーソナライズ、A/Bテストの割り当てをrandom()で決めると、再現性がなくなり、問い合わせ対応も検証もできません。あくまで「見た目の揺らぎ」に限定するのが安全です。

ビジュアルリグレッションを運用しているチームは注意が必要です。スクリーンショットを撮るたびに配置が変わるため、差分が常に出ます。テスト対象のページではrandom(...)をfixed 0.5に置き換えるか、@supportsで無効化する切り替えを用意しておくと運用が破綻しません。

注意点

  • Baseline未到達。Firefoxは既定で無効です。対応表を確認せずに主要UIのレイアウトへ組み込むのは危険です。
  • アクセシビリティ。MDNは、ランダムな文字色が背景と低コントラストになる可能性を明示しています。色に使う場合は、明度や彩度の範囲を狭めるなどの制約を設けてください。
  • 再現性。ページを再読み込みするたびに結果が変わります。ユーザーが「さっきと違う」と感じる演出かどうかを一度立ち止まって確認します。
  • 印刷。印刷時にも乱数が解決されるため、意図しない配置になることがあります。必要なら@media printで固定します。
  • 過剰な要素数。乱数計算そのものは軽量ですが、要素を大量に生成すれば描画負荷は上がります。星空なら数十個程度に留めるのが無難です。

対応状況と使う判断

ブラウザ

対応

備考

Chrome / Edge 156以降

対応

2026年10月20日 stable

Safari 26.2以降 / iOS 26.2以降

対応

2025年12月12日。26.5で共有範囲の仕様が変更

Firefox 158

未対応

layout.css.random.enabledが実験フラグ

Baseline

未到達

MDNはLimited availability

自分なら使うか:条件付きで使う。 装飾用の背景やパーティクルなど「壊れても情報が失われない」箇所に限定し、@supports (order: random(1, 2))で囲んだうえで、静的なフォールバックを必ず用意します。逆に、ナビゲーションやフォームの配置など、崩れると操作に影響する箇所には使いません。対応が揃うまでは「遊びのレイヤー」の道具として扱うのがちょうどよいと感じています。

まとめ

  • CSS random()はChrome 156(2026年10月20日)でstableに到達。Safari 26.2が先行した。
  • 構文はrandom(最小, 最大)とrandom(最小, 最大, 刻み)。第1引数で値の共有範囲を制御する。
  • 名前付き乱値の既定は文書全体に共有され、element-sharedはelement-scopedに置き換わった。
  • JS乱数と違い、SSRでも初期表示から反映される。ただし再現性はない。
  • 装飾に限定し、@supportsとprefers-reduced-motionのフォールバックを用意する。

参考リンク

シェア
ktkt
ktkt運営者

フルスタックWebエンジニア。モダンなフロントエンドとAPI開発が得意。 Next.jsを中心にWebアプリ制作、AI活用支援、動画編集など活動中。 複雑な技術を、使える道具にデコードする。

タグで探す

関連記事

同じタグ・カテゴリの記事から選んでいます。