Open14

normalize.css 今でも本当に必要なコードはどれだけあるのか仕分けしていくよ!

Jeffrey FrancescoJeffrey Francesco

ある理由により最近の新しいリセット系 CSS が使えないので相変わらず normalize.css を使っているのだけど、あらためてよく見ると最近のモダンブラウザだけをターゲットにするなら別になくてもよさそうなコードがいっぱいあるように思えてきたので、一度全部見渡して今でも必要そうなコードとそうでないものを仕分けしていこうと思います。

ただオリジナルはもう 7 年近く更新されていないので、それよりはまだ最近も多少アップデートはされている(それでも 2 年ほど前が最後だけど…)@csstools 版の方を見ていきます。ちなみにここは PostCSS Preset Env とかを開発しているところ。

https://github.com/csstools/normalize.css

Jeffrey FrancescoJeffrey Francesco

仕分けの基準

  1. 正規化であるかどうか
    これがないとブラウザ間で確実に表示差違が生まれ、かつ基準となるブラウザの挙動に寄せるるものを「要」とする。言い変えるとすでにブラウザ間で表示が統一されているものや、ただリセットしてるだけ…みたいなものは「不要」とする
  2. 予期しない挙動を抑制するものかどうか
    例えばフォーム部品などで普通に CSS を書いてもスタイルが反映されない場合があるが、そういった制作者の期待に沿わない・予期せぬ挙動を修正あるいは抑制するためのものは、1. に沿ってなくても「要」としておく
  3. サポートブラウザの範囲外は考慮しない
    @csstools 版のサポートブラウザは Chrome / Edge / Firefox / Opera が last 3・Safari は macOS・iOS とも last 2(おそらく major)となっている。この基準に従い、それより古いバージョンに関しては考慮しないものとする

とりあえずこんな感じでいきます。

Jeffrey FrancescoJeffrey Francesco

1. Document

ルート要素 (html) に適用されるスタイル。

/**
 * 1. Correct the line height in all browsers.
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 */

:where(html) {
  line-height: 1.15; /* 1 */
  -webkit-text-size-adjust: 100%; /* 2 */
  text-size-adjust: 100%; /* 2 */
}

line-height のこの 1.15 という数値はどこからきてるんや? と思ったら、lang 属性が英語とかの時の Safari の line-height が基準みたい。これは <p lang="en" style="font-size:100px">Hello</p> みたいな適当な HTML を開いて開発者ツールでボックスの高さを測って調べた。ちなみに Firefox は 1.2 で Chrome は 1.5 だった。

Normalize の観点でいえば必要な処理だとは思うけど、じゃあ Safari 基準の 1.15 が妥当かといわれるとちょっとってなるし、日本語だともっと間隔が欲しいところなので結局は上書きすることも考えると、なしにして各自が思うように設定するようにした方がいい気もする。まぁ一応残しておくことにするか。

残りはスマホのランドスケープモードで文字が拡大されるのを防ぐおなじみのやつ。この挙動は PC では行われないことを考えると、一応は正規化の範疇といえる。

結論:どちらも必要(だけど line-height の値は再考の余地あり)

Jeffrey FrancescoJeffrey Francesco

2. Sections

セクショニング系の要素に関するスタイル。昔は IE 対策のコードが色々あった(HTML5 の新要素を display:block する処理など)はずだが、そこから HTML5 の実装が進んだ結果今は↓だけ:

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Edge, Firefox, and Safari.
 */

:where(h1) {
  font-size: 2em;
  margin-block-end: 0.67em;
  margin-block-start: 0.67em;
}

これはセクショニング要素の中にある h1 要素を h2 要素相当の文字サイズとマージンにするというブラウザのデフォルト CSS を、本来の h1 要素のサイズに戻すためのコード。アウトライン・アルゴリズムが消滅した今となっては不必要な挙動なので、すでに Chrome と Firefox からは削除されているのだけど、Safari には最新の v26 でもまだ残っていた。あれ、どこかでもうすぐ削除される予定だと読んだ気もするんだけどなぁ…🤔

とりあえず削除されてないのは確かなので、当面はまだ残しておく必要がありそう。

結論:必要

Jeffrey FrancescoJeffrey Francesco

3. Grouping content

昔でいうところのブロックレベル要素およびリスト要素に関するもの。

/**
 * Remove the margin on nested lists in Chrome, Edge, and Safari.
 */

:where(dl, ol, ul) :where(dl, ol, ul) {
  margin-block-end: 0;
  margin-block-start: 0;
}

/**
 * 1. Add the correct box sizing in Firefox.
 * 2. Correct the inheritance of border color in Firefox.
 */

:where(hr) {
  box-sizing: content-box; /* 1 */
  color: inherit; /* 2 */
  height: 0; /* 1 */
}

ネストされたリストの上下マージンを取り除くコードと hr 要素のノーマライズをするコードだけど、前者は書き方の差こそあれ全ブラウザの UA CSS にすでに同等の記述がある。後者についても今は全ブラウザで ht 要素のデフォルト・スタイルに差はないし、color: inherit については単純にデフォルトを書き換える内容なので、必要と思う人もいるかもしれないけど今回の基準でいえば削除対象。

結論:不要

Jeffrey FrancescoJeffrey Francesco

4. Text-level semantics (pt.1)

昔でいうところのインライン要素。3 つに分ける。

/**
 * Add the correct text decoration in Safari.
 */

:where(abbr[title]) {
  text-decoration: underline;
  text-decoration: underline dotted;
}

/**
 * Add the correct font weight in Chrome, Edge, and Safari.
 */

:where(b, strong) {
  font-weight: bolder;
}

まず最初の abbr 要素の下線(点線)について。Chrome と Firefox はもうずいぶん前からデフォルトになっているので単純に Safari 対策のコードということになるけど、実は Safari って今でも -webkit- プレフィックスのない text-decoration は複数キーワードの記法に対応してないんで、このコードだと Safari で無視されて何のノーマライズにもなってへんのよね😇

:where(abbr[title]) {
    text-decoration-line: underline;
    text-decoration-style: dotted;
}

なので本当は例えば上のように書く必要がある…んだけど、実は Safari v18.4 ではこのコードが UA CSS に追加されてデフォルトとなった。@csstools 版のブラウザ・サポートは Safari については last 2 version となっているので、v26 がリリースされた今となってはもはや不要なコードであるというね…。もちろんもう少し古いバージョンもサポートしたいというのであれば入れておく必要があるけど、今回の基準でいえば削除でいいかと思う。

次の b, strong については全ブラウザのデフォルトがすでにそうなっているので、もう不要。

結論:どちらも不要(古いバージョンの Safari を考慮に入れるなら abbr のコードは修正版を入れる)

Jeffrey FrancescoJeffrey Francesco

5. Text-level semantics (pt.2)

4. の続き。
👇の部分はコードブロックなどの等幅フォントで表示される要素が、本文と同じフォントサイズで表示されるようにするというもの。

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

:where(code, kbd, pre, samp) {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

一見「あれ何? 何かの間違い?」ってなりそうになるこの妙なコード🤣にはちゃんと理由があって、おおむねどのブラウザもここに書かれている要素群に font-family: monospace だけが指定されている場合、たとえその要素に font-size: 1em が指定されていたとしてもベースのフォントサイズよりひと回り小さなフォントサイズで描画するという、ちょっとクセのある挙動をするようになっている[1]んだけど、これが monospace + 別のフォントファミリーが指定された場合には font-size: 1em がちゃんと本来の 1em で表示されるようになる…という仕組みになっている。

でも normalize.css というのはリセットのような扱いの CSS なので、あまりにも具体的なフォントファミリーを指定する訳にはいかない。なので、このように monospace を繰り返して指定するというという形になっている訳。ちなみに最初はこれ monospace, serif で、それは単に総称フォント名のなかで一番短いという理由で一度はそうなったけど、やっぱりそれはおかしいという指摘かなんかがあって、今の形になったような記憶がある(その辺は当時あまり追ってなかったのでよく分からない)。

…ちょっとブログ並に長くなってしまったけど😅 とりあえずそんな事情があり、なおかつこのクセのある挙動は今も一緒 & 今後も当面は修正されることはないと思うので、今後も欠かさず指定が必要かと思う。

結論:必要

脚注
  1. これはおそらく昔に書かれた古い HTML ページとの後方互換性が理由だと思うけど、違ってるかもしれないので詳しい人いたら指摘求む。 ↩︎

Jeffrey FrancescoJeffrey Francesco

6. Text-level semantics (pt.3)

このセクション最後。

/**
 * Add the correct font size in all browsers.
 */

:where(small) {
  font-size: 80%;
}

これについては現在、全ブラウザの small 要素のデフォルトが font-size: smaller で統一されていて、それを無駄に上書きしているだけなのでいらないですね。以上
上との差よ😇

結論:不要


今日はこれくらいにしといたるわ🤣

Jeffrey FrancescoJeffrey Francesco

パラグアイ戦見ながらぽちぽち。

7. Tabular data

table 関連。

/**
 * 1. Correct table border color in Chrome, Edge, and Safari.
 * 2. Remove text indentation from table contents in Chrome, Edge, and Safari.
 */

:where(table) {
  border-color: currentColor; /* 1 */
  text-indent: 0; /* 2 */
}

1. は Chrome だけが UA CSS で table 要素の border-color をハードコーディングしてて、親要素の側でどんな色が指定してあっても灰色になっちゃうのを Fix するためのもの。2. についてはブラウザ側ではすでに修正されてて、実は削除する Pull Request も上がっているんだけどまだマージされてない。とりあえずいらんやつなので詳細説明は省略🤣

結論:1. だけ必要

Jeffrey FrancescoJeffrey Francesco

8. Forms (pt.1)

フォームコントロール関係。たくさんあるのでひとつずつやっていきます。

/**
 * Remove the margin on controls in Safari.
 */

:where(button, input, select) {
  margin: 0;
}

要素周囲のマージンを取り除くやつだけど、この辺は最近はもう全ブラウザで 0 になってるか、もしくは統一(range スライダー)されているので、基本的にはもう不要なはず。例外はラジオボタンとチェックボックスで、Chrome & Firefox と Safari のマージンに差違がある。なので、やるとすればこれだけリセットするか

:where(input:is([type=checkbox], [type=radio])) {
    margin: 0;

Chrome & Firefox のマージンに寄せてあげる。

:where(input[type=checkbox]) {
    margin: 3px 3px 3px 4px;
}
:where(input[type=radio]) {
    margin: 3px 3px 0 5px;
}

今回の基準でいえば採用するなら後者かな。とりあえず

結論:ほぼ不要

Jeffrey FrancescoJeffrey Francesco

9. Forms (pt.2)

はい次。

/**
 * Remove the inheritance of text transform in Firefox.
 */

:where(button) {
  text-transform: none;
}

Chrome & Safari (none) と Firefox (initial) で差違がある状態なのは変わらないけど、別にどちらにしても継承しなくなってるのには変わりがないので、すでに統一されてるといっていいでしょ。

結論:不要

Jeffrey FrancescoJeffrey Francesco

10. Forms (pt.3)

事情によりひとつ飛ばして次の次に行きます。

/**
 * Add the correct vertical alignment in Chrome, Edge, and Firefox.
 */

:where(progress) {
  vertical-align: baseline;
}

/**
 * Remove the inheritance of text transform in Firefox.
 */

:where(select) {
  text-transform: none;
}

progress 要素の vertical-align については全ブラウザで -2px つまりベースラインより 2 ピクセル下げる形で統一されてるんで、これは単なるリセット。まぁ -2pxbaseline どっちでもアラインメントがテキストと合ってるかどうかと言われれば微妙やけど😅 今回の趣旨はそうじゃないので手を付けません。あと下のやつもひとつ前の 09. と一緒で解決済みなので、こっちもいらない。

結論:どちらも不要

Jeffrey FrancescoJeffrey Francesco

11. Forms (pt.4)

次これ。

/**
 * Remove the margin in Firefox and Safari.
 */

:where(textarea) {
  margin: 0;
}

textarea 要素は今でも Firefox だけはマージンが付いてるので、これは正規化しておく必要がある。

結論:必要

次の search のやつ…これもちょっと色々補足があるのと、これより後の方に関連する項目があるので、それと一緒にまとめて書くことにして、さらに次行く。

/**
 * Correct the cursor style of increment and decrement buttons in Safari.
 */

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
  height: auto;
}

これはちょっとよく分からなくて、コメント読むにおそらくあの小さい増減ボタンにマウスポインター持っていってもカーソルが適したものにならない…というバグがあったんですか? とまぁそんな感じだけど、今回チェックしてみたらもうそんなことなかったので、もういらんの違う? そうしとこ🤣

結論:不要

Jeffrey FrancescoJeffrey Francesco

12. Forms (pt.5)

だんだんしんどなってきたけど😅 次いくよ。

/**
 * Correct the text style of placeholders in Chrome, Edge, and Safari.
 */

::-webkit-input-placeholder {
  color: inherit;
  opacity: 0.54;
}

いわゆるプレースホルダーテキストのスタイルの正規化。この辺のスタイルは普通に CSS 書いててわざわざ毎回手を入れる人は多くない、つまりリセット系あるいはノーマライズ系 CSS のスタイルがそのまま使われる可能性が高いので、デフォルトに問題があるなら絶対にここで手を入れておきたいところよね。

さて、現バージョンの各ブラウザで確認する限り Chrome はダークモードで薄すぎて、Safari はライトモードでちょっと薄い。これは Firefox のスタイルが一番バランスが取れているので Firefox に寄せる感じになるけど(実際今の opacity を使ったスタイルは Firefox の UA CSS のものだった…はず)、その Firefox は最新バージョンだとここのスタイルが color-mix() を使ったものに変更されている。

::placeholder {
  -webkit-text-security: none;
  color: color-mix(in srgb, currentColor 54%, transparent);
}

で、この color-mix() 関数は少なくとも normalize.css がサポートするブラウザバージョンではサポートされているので、できればもうこっちにアップデートするのがいいと思う。もちろんそれより古いバージョンもサポートしたいというのなら今までと同じでいい。

結論:必要(だけどコードは更新した方がいい)