仕組みから学ぶ Web

ブラウザ

画面が描かれる仕組みと、その上の制約

ブラウザは HTML を受け取ってから描画するまでに決まった工程を通る。どの CSS プロパティを触ると工程のどこからやり直しになるか、なぜ非同期処理が「詰まる」のか。そして、そこに被さる同一オリジンという安全装置。

読み終わると、これに答えられるようになります

  • ?top を書き換えると重く、transform だと軽いのはなぜか
  • ?重い処理中にクリックが効かなくなるのはなぜか
  • ?CORS エラーはサーバーとブラウザのどちらが出しているのか
応用13分

レンダリングパイプライン — どのCSSが重いかは工程で決まる

ブラウザが HTML を受け取ってから画面を描くまでの工程。どのプロパティを触ると、どの工程からやり直しになるのか。

スクロール連動アニメーションで top を毎フレーム書き換え、スマホで完全に固まった

応用14分

イベントループ — 1本のスレッドで待たずに捌く

JavaScript が1スレッドなのに、なぜ複数の処理を同時に進められるのか。そして、なぜ「重い処理」が画面ごと止めるのか。

10万件の配列を同期でループし、その間ボタンもスクロールも一切反応しなくなった

基礎12分

同一オリジンポリシー — ブラウザが最初から持っている壁

なぜ他のサイトの JavaScript から自分のページのデータを読めないのか。この制約がなければ Web はどうなっていたか。

iframe で埋めた別ドメインの画面を JS から操作しようとして、原因不明のエラーで1日溶かした

応用14分

CORS — 壁に穴を開けるのは「読まれる側」

プリフライトはなぜ飛ぶのか。ワイルドカードと Cookie が同時に使えないのはなぜか。エラーメッセージから原因を逆算する。

CORS エラーを直そうとフロント側の fetch オプションを1日いじり続けた

応用14分

ブラウザのストレージ — 読めるか、と、送られるかは別の話

Cookie / localStorage / sessionStorage / IndexedDB を容量ではなく「誰が読めて、いつ送られるか」で分ける。認証情報の置き場所を決めるための判断軸。

アクセストークンを localStorage に置き、外部スクリプト経由で持ち出されて8時間なりすまされた

応用14分

Core Web Vitals — 数字を上げるのではなく、何が遅いかを特定する

LCP・INP・CLS は原因ではなく症状の分類。3つが何の代理指標なのかを知ると、直す場所が工程の中で決まる。

LCP の数字だけを追って画像を軽くしたが、遅さの原因は別の工程にあった

応用15分

Service Worker — 直したのに、利用者の画面だけ古い

修正をデプロイしたのに、一部の利用者だけ古い画面のまま壊れた API を叩き続ける。ブラウザとネットワークの間に、自分で書いたプロキシがもう1枚挟まっている。

修正をデプロイしたのに、一部の利用者だけ3日間、古い画面のまま消えた API を叩き続けた

応用15分

画像と動画の配信 — 軽くしたはずの画像が、ページを遅くしている

全部の画像を WebP にして遅延読み込みを付けたら、LCP が悪化した。効くのは形式より画素数で、遅延読み込みは付ける場所を間違えると逆に遅くする。

画像を全部 WebP にして遅延読み込みを付けたら、商品ページの LCP が 2.1秒から 3.4秒に悪化した

応用15分

アクセシビリティ — div にクリックを付けた日から、誰かが使えなくなる

見た目は完璧なボタンを作った。キーボードでは押せず、読み上げでは「何か」としか読まれない。button と書けば全部付いてきたものを、自分で捨てていた。

div で作ったボタンが、キーボードでも読み上げでも操作できなかった

発展16分

描画をどこでするか — HTML を作る時と場所を、データごとに選ぶ

初回の表示が遅いので、全ページをサーバーで描画するようにした。セールの日、1 日 1 回しか変わらない商品説明を、アクセスのたびに描き直してサーバーが落ちた。方式はアプリ単位ではなく、データの鮮度と、誰のものかで決まる。

初回表示の遅さを直すため全ページをサーバー描画にしたら、セールの日に 1 日 1 回しか変わらないページまで毎回描き直してサーバーが落ちた

発展15分

再描画はなぜ起きるか — 1 文字打つたびに、表ぜんぶが描き直されていた

検索欄に 1 文字打つたびに、画面が 0.4 秒固まった。メモ化を全部の部品に付けても変わらなかった。描き直される範囲は、状態を持つ場所で決まる。

検索欄に 1 文字打つたびに 5,000 行の表が描き直され、入力が 0.4 秒ずつ遅れた。メモ化を全部に付けても直らなかった

発展15分

データをどこで取るか — 取得が一列に並ぶと、画面は足し算で遅くなる

注文の詳細画面が 2.4 秒かかっていた。API はどれも 0.8 秒で返っていた。部品がそれぞれ、自分が描かれてからデータを取りに行っていたので、3 回の待ちが順番に並んでいた。

3 つの API はどれも 0.8 秒で返るのに、部品ごとに順番に取りに行っていたため、注文の詳細画面が 2.4 秒かかった

応用15分

フォームと入力の検証 — 画面の検証は親切、サーバーの検証は守り

申し込みフォームで、送信ボタンを 2 回押した人に申し込みが 2 件でき、エラーで戻った人の入力は全部消えていた。画面の検証を足しても、サーバーを通る値は守れない。役割の違う 2 つの検証を、別のものとして設計する。

申し込みフォームで二重送信の申し込みが月 40 件でき、エラーで戻ると入力がすべて消えていた。画面の検証をすり抜けた不正な値も DB に入っていた