◆ 気になる新機能が多め
◆ CSS 系が多い
◆ Import Attributes の with 構文に対応

Chrome 123 の新機能を見てたら気になる機能が多かったです
最近 Chrome の新機能は Short の方に書いてることが多かったですが 分量多めなのでたまにはこっちのブログに書きます

CSS 系が多いです

リリース日

Early Stable Release
2024/03/13

Stable Release
2024/03/19

align-content

https://chromestatus.com/feature/5159040328138752

display: block などでも align-content を使えるようになります
grid に使うみたいに簡単に中央揃えできます
中央揃えのためだけに grid にする必要がなくなりました

これの 2 つの表示が同じになります
Chrome 122 時点だと 上側は左上に TEXT が表示されて 下側は中央左に TEXT が表示されています

<!doctype html>

<style>
.box {
width: 100px;
height: 100px;
background: pink;
align-content: center;
margin: 10px;
}
.grid {
display: grid;
}
</style>

<div class="box">
TEXT
</div>
<div class="box grid">
TEXT
</div>

field-sizing

https://chromestatus.com/feature/5176596826161152

デフォルトでは input 系要素のサイズは固定ですが field-sizing: content を設定することで 要素のサイズが内部のコンテンツに応じて自動で変わるようになります
input だと特別嬉しくないですが textarea の改行に応じて高さが変わるのは使いどころがありますね

type が number や password も内容に応じて変わりますが date などは固定です

<!doctype html>

<style>
.switch:has(:checked) ~ div :is(input, textarea) {
field-sizing: content;
}
</style>

<div class="switch">
<label>
<input type="checkbox">
field-sizing: content;
</label>
</div>
<hr />
<div>
<input type="text">
</div>
<div>
<input type="number">
</div>
<div>
<input type="password">
</div>
<div>
<input type="date">
</div>
<div>
<input type="datetime-local">
</div>
<div>
<input type="color">
</div>
<div>
<input type="checkbox">
</div>
<div>
<input type="radio">
</div>
<div>
<input type="range">
</div>
<div>
<input type="file">
</div>
<div>
<textarea></textarea>
</div>

paint-order

https://chromestatus.com/feature/5178467903864832

SVG 用の CSS プロパティの paint-order が HTML でも使えるようになったようです
-webkit-text-stroke を使うことで文字にストロークをつけられます(縁取りできます)
そのとき描画する順番を指定できます
ストロークの太さによってどっちのほうが適してるかは変わります
デフォルトだと fill → stroke の順ですが paint-order: stroke fill とすることで stroke → fill の順にできます

paint-order-example

<!doctype html>

<style>
.text {
font-size: 60px;
margin: 20px;
color: white;
}
.stroke-fill {
paint-order: stroke fill;
}
.stroke-light {
-webkit-text-stroke: black 1px;
}
.stroke-heavy {
-webkit-text-stroke: black 8px;
}
</style>

<div class="text stroke-light">ABCDあいうえお</div>
<div class="text stroke-light stroke-fill">ABCDあいうえお</div>
<div class="text stroke-heavy">ABCDあいうえお</div>
<div class="text stroke-heavy stroke-fill">ABCDあいうえお</div>

light-dark()

https://chromestatus.com/feature/4909742688567296

color-scheme の設定に応じて light のときと dark のときの色を返す関数です
ダークテーマをサポートするときには便利そうです

radio の切り替えで light/dark を切り替えるページです
TEXT の部分の文字色と背景色を light-dark() を使って指定しています

<!doctype html>

<style>
:root:has([value="1"]:checked) {
color-scheme: light;
}
:root:has([value="2"]:checked) {
color-scheme: dark;
}
p {
color: light-dark(darkred, pink);
background: light-dark(pink, darkred);
}
</style>

<div>
<label>
<input type="radio" name="color-scheme" value="1" checked>
light
</label>
<label>
<input type="radio" name="color-scheme" value="2">
dark
</label>
</div>
<p>TEXT</p>

こんな感じになります

css-light-dark-example

(Chrome 122 といいつつ実際は Edge 122 でスクショしてます)

display-mode: picture-in-picture

https://chromestatus.com/feature/5198101675769856

ピクチャインピクチャ表示のときだけ有効になるメディアクエリが追加されました

<!doctype html>

<script type="module">
document.getElementById("button").onclick = async () => {
const pip_window = await window.documentPictureInPicture.requestWindow({
width: 400,
height: 300,
})

pip_window.document.body.innerHTML = `
<link rel="stylesheet" href="page.css" />
<h1>H1</h1>
`
}
</script>
<link rel="stylesheet" href="page.css" />

<p>Picture in Picture</p>
<button id="button">Open</button>

[page.css]
body {
color: red;
}

@media (display-mode: picture-in-picture) {
body {
color: blue;
}
}

メインのページとピクチャインピクチャのページの両方で page.css をロードしていて メインページでは文字色が赤 ピクチャインピクチャのページでは文字色が青になります

ただ ピクチャインピクチャのページって完全に別のページに分かれていて window オブジェクトも別物です
URL (HTML) を指定して開くことはできなそうなので DOM は JavaScript で作ります
そうなると CSS ファイルもメディアクエリで分岐せずピクチャインピクチャ用の CSS をロードすれば良いのであまり使うことなさそうに感じてます

これも本題からずれますが ピクチャインピクチャを開いたことは検知できても閉じてタブに戻ってきたことを検知できなさそうなので ピクチャインピクチャ画面の要素をタブ側に復元ってどうするのでしょうね

Import Attributes

https://chromestatus.com/feature/5205869105250304

やっと Import Attributes の with 構文が使えるようになりました
昔からの assert 構文でも動いたのですが 廃止がすでに決まってるものなので あまり assert で書く箇所を増やしたくなかったのですよね
現状は単純に assert を with に置き換えるだけで JSON や CSS のロードができます

<script type="module">
import data from "./page.json" with { type: "json" }
import css from "./page.css" with { type: "css" }
console.log(data, css)
</script>

[page.json]
{
"value": 1
}

[page.css]
body {
color: red;
}

{value: 1}  CSSStyleSheet {…}

assert の方ですが Chrome 123 で使うとこんな警告がでるようになっていました

'assert' is deprecated in import statements and support will be removed in V8 v12.6 and Chrome 126; use 'with' instead

Chrome 126 で削除される予定らしいです
たった 3 ヶ月先とは思ったより早いですね

ちなみにこの Import Attributes ですが Bun では SQLite の db ファイルをインポートすることで データベースを操作できるオブジェクトを取得できるようです
https://bun.sh/blog/bun-v1.0.23

import db from './my.db' with {type: "sqlite"};

const {id} = db
.query("SELECT id FROM users LIMIT 1")
.get();

console.log(id); // 1

さすがにこれはやりすぎなように思いますし なんか違うと思います
内部的にはこれと同じだそうですが これを素直に書く方いいと思うのですけどね

import { Database } from "bun:sqlite";
const db = new Database("./my.db");

NavigationActivation

https://chromestatus.com/feature/5076557983121408

navigation.activation で NavigationActivation オブジェクトが参照できるようになりました
どうやって今のページが開かれたかに関する情報を持っています
NavigationActivation オブジェクトには entry と from と navigationType のプロパティがあります
entry には新しい NavigationHistoryEntry で from には古い NavigationHistoryEntry が入っています

新しいものは現在の entry なので navigation.currentEntry と一致しそうなものですし 仕様的にも Document がアクティブ化されたときの currentEntry とあるのですが一致しないときもありました

entry の index が -1 になってたりもしましたし バグなのか正常動作なのかよくわかってません

from は移動してくる前のページの entry です

navigationType にはどうやって移動したかが入っていて 通常のページ遷移なら push で リロードなら reload で 戻るや進むなら traverse といった感じです
SPA の制御がしやすくなりますね

一応これまででも currententrychange イベントで entry の変更は監視できたので 進むや戻るの検出はできたのですがもう少しやりやすくなりそうです

pagereveal イベント

https://chromestatus.com/feature/5205586941837312

pagereveal イベントが追加されたようです
ページをロードしたり BF キャッシュから復元したりしたときに起きるらしいですが pageshow との違いがあまりわかってません
イベントのプロパティに viewTransition があって ViewTransition 機能と関係するようですけど

ドキュメントを超えた ViewTransition に使われるようなことも書かれてます

Back/forward cache NotRestoredReason API

https://chromestatus.com/feature/5684908759449600

BF キャッシュが使われなかったときの理由をプログラム上で把握することができるようになったようです
取得方法は PerformanceNavigationTiming API を使います

performance.getEntriesByType("navigation")
// [PerformanceNavigationTiming]

という感じで PerformanceNavigationTiming オブジェクトを取得できます
これ自体は以前からありますが このオブジェクトのプロパティに notRestoredReasons が追加されました
オブジェクトのフォーマットの例はここに書かれてます
https://github.com/WICG/bfcache-not-restored-reason/blob/main/NotRestoredReason.md#examples

blocking="render" のインラインモジュール対応

https://chromestatus.com/feature/5200457540829184

これはいまいちよく分からなかったものなのですが script タグの blocking 属性がインラインのスクリプトでも有効になったようです
これまでは src 属性を使って外部からロードするもののみだったのが 直接 script タグにソースコードを書く場合でも使えるようになったようです

レンダリングをブロックしてくれるなら こう書くとスクリプトの実行中には body タグがないのでエラーか空文字列かなと思ったのですが div タグが表示されます

<script type="module" blocking="render">
console.log(document.body.innerHTML)
</script>

<div>a</div>

現状でも src 属性を使えば blocking 属性が有効なはずなのですが 使ったこと無いですし これ自体がどう使うものかよくわからないです

text-spacing-trim (追記)

https://chromestatus.com/feature/5170044014690304

最初に記事を書いたときはリストに無かったと思うのですが Chrome 123 リリース後に見てみると増えてたので追加します

ブラウザ上の表示だと 日本語はフォントがプロポーショナルでも固定幅になります
font-feature-settings で日本語もいい感じにできるらしいですが 今回は関係ないのでこれは置いておきます
固定幅になるせいで記号を書くときに変な隙間が出て気持ち悪かったりします
特に記号が連続する場所などは目立つと思います

それに対応するための機能で 記号の余分な余白を削ってくれます
ただ この機能の追加でデフォルト値が変わるので Chrome 123 にアップデートするとこれまでと表示が変わる場合があります

<!doctype html>
<meta charset="utf-8"/>

<style class="">
p {
margin: 0;
font-family: yu gothic;
width: 140px;
font-size: 16px;
background: lavender;
}

.switch {
display: flex;
flex-flow: column;
}

.switch:has([value=normal]:checked) ~ .text p {
text-spacing-trim: normal;
}

.switch:has([value=trim-start]:checked) ~ .text p {
text-spacing-trim: trim-start;
}

.switch:has([value=space-all]:checked) ~ .text p {
text-spacing-trim: space-all;
}

.switch:has([value=space-first]:checked) ~ .text p {
text-spacing-trim: space-first;
}
</style>

<div class="switch">
<label>
<input type="radio" name="switch" value="normal" checked>
normal (Chrome 123 default)
</label>
<label>
<input type="radio" name="switch" value="trim-start">
trim-start
</label>
<label>
<input type="radio" name="switch" value="space-all">
space-all (Chrome 122)
</label>
<label>
<input type="radio" name="switch" value="space-first">
space-first
</label>
</div>

<hr />

<div class="text">
<p>あ</p>
<p>「あ」</p>
<p>(あ)</p>
<p>「(あ)」</p>
<p>「(あ)」「(あ)」「(あ)」</p>
</div>

css-text-spacing-trim

normal だと連続するところの余白が削られるみたいです
space-all (Chrome 122 までの動き) だと余白はすべてそのままの等幅で表示されます
trim-start にすると連続する部分以外に 1 文字目の開始部分の余白も削られます
space-first は trim-start を基準に文の最初のみスペースを追加したものになっています
normal を基準に 自動で折り返されたときに 行頭に記号が来ると余白が削られると考えたほうがわかりやすいかもしれません

この機能を使うのにフォント側にも情報が必要みたいで対応してるフォントである必要があります
メイリオだと Chrome 122 と同じ見た目でした
游ゴシックや游明朝などだと有効になります