Chrome 156で使えるCSSのrandom()と、失敗したimport()の再試行|Chrome 155と比べて検証

Chrome 156が10月20日に安定版になり、CSSのrandom()などが使えるようになった

Googleは2026年10月20日、Chrome 156をWindows、Mac、Linuxの安定版として公開しました。数日から数週間かけて、順に利用者のChromeへ配信されます。

Chromeの新機能を一覧にしたChrome Platform Statusのリリースノートには、Webページを作る人に関係する変更がいくつか並んでいます。この記事ではそのうち、CSSだけで乱数を使える random() と、読み込みに失敗したJavaScriptのモジュール(機能ごとに分けたJavaScriptのファイル)を import() でもう一度読み込める変更の2つを取り上げます。

手元のMacにはChrome 156と、1つ前のChrome 155(動作確認用の「Chrome for Testing」)があったので、同じページを両方で開いて動きを比べました。書き方、実際に出た値、Chrome 155以前を使う閲覧者への備えまでを順に説明します。

検証で分かったこと

Chrome 156では、乱数を使った配置をCSSだけで書け、失敗したモジュールの読み込みをやり直せる

CSSのrandom()

156で使える

要素ごと、開くたびに別の値になる。Chrome 155では使えない。

値をそろえる

名前を付ける

random(--size, …) のように同じ名前を付けると、別の要素でも同じ値になった。

import()の再試行

156は2回目で成功

Chrome 155は1回目の失敗を覚えていて、2回目も通信せずに失敗した。

155以前への備え

@supportsとURLの工夫

対応していないブラウザ向けの表示と、URLを変えて読み込み直す方法を確かめた。

random()は、CSSの中で範囲を決めて乱数を取り出す関数

これまで、要素をランダムに散らす、角度や大きさを少しずつばらつかせる、といった表現にはJavaScriptで乱数を作る必要がありました。Chrome 156からは、CSSの値を書く場所に random(最小値, 最大値) と書くだけで、その範囲の値が入ります。リリースノートによると、Safariはすでにこの関数に対応しており、Firefoxは対応に前向きな立場を示しています。

値の決まり方を確かめるため、幅と高さに random() を使う次のCSSを用意しました。どの書き方も、Chrome 156の CSS.supports()(ブラウザがその書き方に対応しているかを調べる関数)で「対応している」と返りました。.b と .c は別の要素で、同じ名前 --shared を付けています。

.a { width: random(10px, 300px); }              /* 何も付けない */
.b { width: random(--shared, 10px, 300px); }    /* 名前を付ける */
.c { width: random(--shared, 10px, 300px);      /* .b と同じ名前 */
     height: random(--shared, 10px, 300px); }
.d { width: random(10px, 300px, 50px); }        /* 第3引数で刻む */
.e { width: random(fixed 0.5, 10px, 300px); }   /* fixed(主にテスト用) */

このCSSを当てた要素(.a を3つ、.b を2つ、.c を1つ、.d を4つ、.e を1つ)を並べ、Chrome 156でページを2回開いて、実際の幅と高さを取り出しました(表は抜粋)。

                         1回目       2回目
.a(1つ目)の幅          105.781px    42.2344px
.a(2つ目)の幅          204.062px   115.047px
.b(1つ目)の幅          188.203px   241.828px
.b(2つ目)の幅          188.203px   241.828px
.c の幅と高さ            188.203px   241.828px
.d(4つ)の幅            210/60/210/210px   160/110/160/210px
.e の幅                  155px       155px

何も付けない

同じクラスの要素でも1つずつ別の値。ページを開くたびに値が変わる。

--名前を付ける

同じ名前どうしは、別の要素・別のプロパティでも同じ値(.b と .c がすべて同じ値)。

第3引数で刻む

10pxから50pxずつ増える値(10px、60px…260px)のどれかになる。今回は60px〜210pxの値が出た。

fixedで固定

fixed 0.5 は範囲のちょうど中間(155px)になり、2回とも同じ値だった。仕様では、主にテストで値を固定したいときの書き方とされている。

名前を付けたときに値を共有する範囲は、仕様の議論の中で変わってきました。2025年8月のWebKit(Safariの描画エンジン)のブログでは、名前で値がそろうのは同じ要素の中だけで、要素をまたぐには element-shared を付けると説明されていました。その後、仕様が改められ、名前を付けると別の要素とも同じ値を共有する形になりました。SafariもSafari 26.5(2026年5月)でこの形に変わり、element-shared は削除されています。上の表で .b と .c がそろったのも、この新しい仕様どおりの動きです。

要素ごとに別の値にしつつ、同じ要素の中では幅と高さをそろえたいときは、名前に element-scoped を付けます。Chrome 156で試すと、2つの要素がそれぞれ正方形になり、大きさは要素ごとに違いました。element-shared を含む書き方は、Chrome 156では「対応していない」と返ります。

/* 要素ごとに別の値。同じ要素の中では幅と高さがそろう */
.s {
  width: random(--k element-scoped, 10px, 300px);
  height: random(--k element-scoped, 10px, 300px);
}
.s(1つ目): 109.109px x 109.109px
.s(2つ目): 113.609px x 113.609px

Chrome 155では、random()を書いた指定がまるごと無視される

同じページをChrome 155で開くと、random() を含む指定は使われませんでした。CSS.supports() も「対応していない」を返します。CSSは解釈できない値を含む宣言を読み飛ばすので、ほかに位置の指定がなければ、要素は top や left を指定しなかったときと同じ位置に重なって表示されます。

そこで、@supports(ブラウザが対応しているときだけ中のCSSを当てる書き方)で分けておきます。対応していないブラウザ向けの位置を先に書き、@supports の中で random() を使います。

.dot { top: 10px; left: 10px; } /* 対応していないブラウザ向け */

@supports (top: random(0%, 100%)) {
  .dot {
    top: random(0%, calc(100% - 26px));
    left: random(0%, calc(100% - 26px));
    scale: random(0.4, 1.4);
  }
}
濃紺の枠に20個の丸を置いた同じページの表示。Chrome 156で1回目と2回目に開いた画面では丸の位置と大きさがばらばらで、2回で配置が違う。Chrome 155の画面では丸が左上の1か所に重なっている
20個の丸に上の@supportsのCSSを当てたページ。Chrome 156は開くたびに配置が変わり、Chrome 155は対応していないブラウザ向けの位置(左上)に重なった。2026年10月23日、macOS 27.0.1のヘッドレス実行で撮影。

左上に重なった状態が見た目として困る場合は、対応していないブラウザ向けには規則的な並びを用意しておくと、どちらのブラウザでも内容が読める表示になります。

Chrome 156では、失敗したimport()をもう一度呼ぶと読み込み直す

もう1つの変更は、JavaScriptのモジュールを読み込むときの動きです。import() は、必要になったときにモジュールを読み込む書き方です。リリースノートによると、これまでのChromeは読み込みに失敗した結果を覚えていて、同じモジュールをもう一度 import() しても、すぐに失敗を返していました。Chrome 156からは、もう一度呼ぶと実際に読み込み直します。この動きはFirefoxとSafariがすでに採り入れています。

手元では、1回目の要求にだけ「503」(サーバーが一時的に応答できない)を返し、2回目からは正常に返すテスト用のサーバーを用意しました。ページでは import() が失敗したら、もう一度だけ呼びます。

# Chrome 156
1回目: 失敗 (TypeError: Failed to fetch dynamically imported module: http://127.0.0.1:8765/flaky.js)
2回目: 成功 (loaded)
サーバーへのリクエスト: 2回

# Chrome 155
1回目: 失敗 (TypeError: Failed to fetch dynamically imported module: http://127.0.0.1:8766/flaky.js)
2回目: 失敗 (TypeError: Failed to fetch dynamically imported module: http://127.0.0.1:8766/flaky.js)
サーバーへのリクエスト: 1回

Chrome 156は2回目の import() でサーバーにもう一度要求を出し、読み込みに成功しました。Chrome 155は2回目の要求をサーバーに出さないまま失敗しています。Chrome 156では、読み込み直す処理を書いておけば、電波の弱い場所で一度失敗しても、ページを再読み込みせずにその機能を使えるようになります。

import()が失敗したら少し待って読み込み直す関数

Chrome 156の変更を生かすには、import() が失敗したときに読み込み直す処理を自分で書きます。次の関数は、失敗したら0.5秒、1秒と待ち時間を延ばしながら、最大2回読み込み直します。

async function importWithRetry(url, retries = 2, waitMs = 500) {
  for (let i = 0; ; i++) {
    try {
      return await import(url);
    } catch (e) {
      if (i >= retries) throw e;
      await new Promise((r) => setTimeout(r, waitMs * (i + 1)));
    }
  }
}

const mod = await importWithRetry('./feature.js');

最後の行の await は、<script type="module"> の中でそのまま使えます。import() に渡す相対URLは、この関数を書いたファイルの場所を基準に決まるので、関数を別のファイルに移すときは注意します。

同じテスト用のサーバーで、この関数はChrome 156で2回目に成功し、Chrome 155では最後まで失敗しました。Chrome 155以前の閲覧者にも再試行を効かせたい場合は、関数の return await import(url); の行を次のように書き換え、2回目以降の読み込みでURLに retry という値を付けます。ブラウザは別のURLとして扱うので、Chrome 155でも2回目で読み込めました。

// Chrome 155以前でも再試行できるように、2回目以降はURLに retry を付ける
const u = new URL(url, import.meta.url);
if (i > 0) u.searchParams.set('retry', i);
return await import(u.href);

URLを変える方法では、同じファイルが別のモジュールとして読み込まれます。ほかの場所で同じモジュールを元のURLで読み込んでいる場合は、中の変数や状態が2つに分かれます。また、URLを変えて読み込み直せるのは import() で指定したファイルだけで、そのファイルがさらに読み込むモジュールで失敗した場合、Chrome 155ではその失敗が記憶されたままです。この方法は旧版への備えとして必要な場合に限るのがよさそうです。

そのほかのChrome 156の変更

リリースノートには、ほかにも次の変更が並んでいます。どれもChrome 156で既定で有効になりました。

:navigation-source

ページの移動を始めたリンクやボタンを、CSSで選べる。移動中もその要素が選ばれたまま。手元では156で対応、155で非対応を確認。

片方の軸だけのスクロール

overflow: scroll clip のように片方の軸だけをスクロールにできる。position: sticky の基準を縦と横で別のスクロール領域にでき、大きな表の行見出しと列見出しの固定に使える。

scroll-snap-type: pair

縦と横のスクロールで、同じ要素にぴたりと止まるようにできる。

IndexedDBの保存方式

ブラウザ内のデータベースを、新しく作られるデータからSQLiteで保存する。既存のデータの移行は今後の段階で、JavaScriptからの使い方は同じ。

出典:Chrome Platform Statusの「Chrome 156 release notes」。:navigation-source の対応状況は手元のChrome 156・155で確認。

random()とimport()の再試行を取り入れるときの3つのポイント

Chrome 156の配信は数日から数週間かけて進み、古い版のChromeを使い続ける閲覧者もいます。ここまでの検証をもとに、取り入れるときのポイントを3つにまとめます。

1. random()は飾りの部分から使う

背景の模様や、カードの傾きなど、値がそろわなくても内容が読める部分から使う。@supportsで、対応していないブラウザ向けの表示を必ず用意する。

2. 名前は要素をまたいで共有される前提で使う

名前だけなら、すべての要素が同じ値になる。要素ごとに変えたいときは element-scoped を付ける。古い版のSafariでは共有の範囲が違う場合があるので、正方形のように値がそろわないと崩れる表現はSafariでも表示を確かめる。

3. import()には読み込み直す処理を付ける

あとから読み込む機能(エディタ、地図、グラフなど)に、待ち時間つきの再試行を付ける。Chrome 155以前の閲覧者が多いサイトでは、URLを変える方法も検討する。

random() は、これまでJavaScriptで書いていた「毎回少しずつ違う見た目」をCSSだけで作れる便利な関数です。まずは自分のページの飾りの部分に記事のCSSを当て、Chrome 156とそれ以外のブラウザで表示を見比べてみるのがおすすめです。