UIT Meetup vol.15
Relearn Modern Web Standard
今までああ書いてたアレ、これからはこう書けそう
よしこ@yoshiko_pg
Google Developer Experts for Web
2022.03.25

About Speaker
よしこ - @yoshiko_pg
株式会社ナレッジワーク
フロントエンドエンジニア
2021年10月からWebのGDEになりました。
SPAでGUIツールを作るのが好きです。

About Session
このセッションについてWebフロントエンド開発で頻出するパターンの中で、専用の仕様がなかったために既存の仕様を使って工夫して実現していたようなものがありました。
日々新しく提案・実装されていくWebの仕様の中で、モダンブラウザでの実装も進んでおり、利用したくなる機会も多そうなものについてbefore/afterのコードを軸に紹介していきます。
実際に使えるかどうかは各アプリケーションのサポート環境次第ですが、IE11のサポート終了も近付いており、一般的なサポート環境の水準にも変化が予想されるので状況がマッチしたときに引き出せる、知識の引き出しのひとつになれば幸いです。

サポート環境次第で今から使えそうなもの
最新モダンブラウザで実装済み

/* before *//* childにmarginをつけ、外側の不要なmarginをparentのnegative marginで相殺している */.parent {display: flex;
flex-wrap: wrap;
margin: -10px;}.child {flex: 0 0 100px;
margin: 10px;}

CSS Propertygap
CSS Box Alignment Module Level 3

特定のレイアウト内で隣接するボックス間の間隔を指定できる（間隔なので外側にはみ出ない）
flex, grid, multi-column で利用可能
row-gap column-gapのshorthand

ChromeFirefox

Safari

EdgeAndroid
ChromeiOS
Safari

99

99

1599

99

15

/* after */.parent {display: flex;
flex-wrap: wrap;
gap: 10px;}.child {flex: 0 0 100px;}

CSS Property/* before *//* paddingの100%が親の横幅と等しいことを利用して疑似要素のpadding-topで4:3に比率固定している。
高さベースの比率固定はできない。
子要素を置きたい場合はabsoluteなどで配置する */.box {}.box::before {content: '';display: block;
padding-top: 75%;}

aspect-ratio
CSS Box Sizing Module Level 4

要素のアスペクト比率を指定できる。値は「幅 / 高さ」で記述 (ratio)（余談）画像などのLayout Shiftに対するブラウザでの改善のための提案にも登場していたりしました。

/* after *//* 高さベースの比率固定も可能（heightを指定） */.box {
aspect-ratio: 4 / 3;}

標準化の経緯が面白いです。詳しい日本語記事：
https://www.mizdra.net/entry/2020/05/31/192613

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

15

99

99

15

CSS Property

Scroll Snap/* before *//* 何らかのJS実装を利用していたのではないでしょうか */CSS Scroll Snap Module Level 1/* after */.parent {overflow: auto;
scroll-snap-type: y;/* y mandatory と指定するとさらに厳密にsnapする */}.child-scrollable-item {scroll-snap-align: start;}

カルーセルやLPなどで求められることのある、子要素の始点や中央にスクロールのポイントを合わせる実装がCSSだけで可能に親要素に scroll-snap-type, 子要素に scroll-snap-alignを指定Chrome

Firefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

1599

99

15

CSS Property/* before *//* デフォルトのcheckboxは非表示にし、自分でスタイリングしたcheckboxの見た目の要素を表示していた */.checkbox input[type=checkbox] {visibility: hidden;}.checkbox span {/* 好きな色のcheckboxな見た目の実装 */}accent-color 🎉
CSS Basic User Interface Module Level 4

一部のform control要素のアクセン
トカラーを変更できる
アクセントカラーの上に重なる要素（チェックボックスのチェックなど）の/* after */input[type=checkbox] {accent-color: pink;}

色はブラウザがコントラストを保ってくれる

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

9999

1599

99

15

CSS Selector/* before *//* クリックしたときにも線が出てしまい、うるさい。
が、消すとタブキーでの移動が困難になってしまう */:focus {outline: 2px solid blue;}:focus-visible 🎉Selectors Level 4

フォーカスの場所を伝えたほうがよ
いとブラウザが判断した場合に適用/* after *//* クリックしたときには線が表示されず、タブキーでフォーカス移動しているときだけ表示される */:focus-visible {outline: 2px solid blue;}

される。たとえば、クリックしたときはoutlineが出ないがタブキーで移動したときはoutlineが出る、という振る舞いを期待できる

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

15

99

99

15

HTML

<!-- before --><!-- CSSとJSを用いた何らかの実装 -->dialog 🎉HTML Living Standard<!-- after --><dialog>
開く前のダイアログ</dialog>

ダイアログ用の要素がHTMLに追加される。フォーカス可能位置が適切にハンドリングされる、アクセシブルなモーダルを楽に作れるようになる<dialog open>
開いているダイアログ</dialog>

ことが期待できる

ChromeFirefox

SafariEdgeAndroid
ChromeiOS
Safari

99

99

1599

99

15Web API// before
const targetElement =window.document.getElementById('target')const containerElement =window.document.getElementById('container').scrollIntoView()
CSSOM View Module

containerElement.scrollTo({top: targetElement.offsetTop});

所属するスクロールコンテナを知らなくても、子要素側からスクロール位置を操作できる。

// afterconst targetElement =window.document.getElementById('target'){ behavior: 'smooth' } を渡すことでアニメーションも可能 🎉targetElement.scrollIntoView()
ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

9999

1599

99

15

JavaScript

Optional Chaining
ECMAScript 2020// before
const name = user ? user.name : undefined

nullやundefinedに . を繋げてしまうとエラーになるが、 ?. を繋げることで// after
const name = user?.name「nullかundefinedならundefinedが返り、そうでなければ値が返る」挙動にできる

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

15

99

99

15

JavaScript

Nullish Coalescing
ECMAScript 2020// before// 0が入っていてもempty判定されてしまうバグがある
const value = nullableNum || 'num is empty'|| は左側がfalsyの場合に右側を返すが、??は左側がnullish（nullまた// after// nullishのときだけ正しくempty判定される
const value = nullableNum ?? 'num is empty'

はundefined）の場合に右側を返す。0や空文字やfalseを選り分けた
い場合に便利ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

1599

99

15

JavaScript.replaceAll()

const str = 'BANANA'

ECMAScript 2021// before
str.replace('A', 'B') // BBNANA
str.replace(/A/g, 'B') // BBNBNB

今までString.prototype.replaceでマッチするすべての対象を置換した
い場合には正規表現にした上でgオ// after
str.replaceAll('A', 'B')

プションを付けなければならなかったが、replaceAllを使うことで文字列のまま渡せる

ChromeFirefox

Safari

EdgeAndroid
ChromeiOS
Safari

999915999915// BBNBNBJavaScript.at() 🎉
ECMAScript 2022// before
array[array.length - 1]

配列の末尾の要素を取得したいと
き、今まではlength から1を引いた// afterarray.at(-1)

添字で取得していたが、at()に-1を渡すことで末尾の要素を取得できるようになる

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari99

99

15999915今後使えるようになりそうなもの
各モダンブラウザで実装中

CSS Property/* before */.big-box {transform: scale(2);}translate, scale, rotate.bigBox.downward {transform: scale(2) rotate(180deg);}

CSS Transforms Module Level 2

これら3つのアクションがプロパティとして指定できるようになるので、個別/* after */.big-box {scale: 2;}に上書きやアニメーションができるようになる
Chromeにもフラグ付きでは実装されているので有効化に期待.big-box.downward {rotate: 180deg;}

ChromeFirefox

Safari

EdgeAndroid
ChromeiOS
Safari

9999

1599

9915

CSS Property/* before *//* スクロールを止めたい領域のoverflowに一時的にhiddenを指定することでスクロールできなくしている。
スクロール位置がリセットされてしまう問題がある */.overwrap-scroll-area {overflow-y: auto;}
body {
overflow: hidden;}

overscroll-behavior
CSS Overscroll Behavior Module Level 1

スクロール可能な領域同士が重なっている場合、スクロール操作中の領域のスクロール終点まで辿り着いた
ときに後ろのスクロール領域がスク/* after */.overwrap-scroll-area {overflow-y: auto;
overscroll-behavior-y: contain;}

ロールされはじめてしまう問題をCSSで解消できる

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

15

99

99

15

Web API

userAgentData
User-Agent Client Hints// before
const uaString = navigator.userAgent
const isMobile = /* uaStringのparse等 */UserAgentをobject形式で取得可能.getHighEntropyValues()でさらに詳// afterconst uaData = navigator.userAgentData
const isMobile = uaData.mobile // false

細な情報も取得可能
文字列のUserAgentは様々な問題により情報が減らされていく方針なので、どこかで置き換える必要がある

ChromeFirefox

Safari

Edge

Android
ChromeiOS
Safari

99

99

15

99

99

15

最後に・・・

ナレッジワーク

名前だけでも来月まで覚えていてください🌟

Thank You!
よしこ
Google Developer Experts for Web@yoshiko_pg