ブログ

React use()とSuspense:ウォーターフォールなしのデータストリーミング

ダッシュボードに6枚のカード、6つのスピナー、それらは一緒に表示されません — ドミノ倒しのように一つずつ表示されます。各カードは上のカードが完了してからロードを開始したからです。これがウォーターフォールで、合計待ち時間は最も遅いリクエストではなく、すべての合計です。use()とSuspenseはその連鎖を断ち切ります — しかし面白いのは内部のメカニズムです:サスペンドされたコンポーネントが実際に何をスローするのか、そして間違った順序で届いたHTMLがどのように正しい場所に収まるのか。

スクロールアニメーション:IntersectionObserverの代わりにanimation-timeline

JavaScriptのパララックスがいつも少しおかしく見える理由があります — ちょっとずれていて、レイヤーがページの半フレーム遅れで泳いでいるような感じ。雑なコードではありません。スクロールイベントがブラウザがすでに描画した後にJavaScriptに届くからです。ブラウザはこれをかつて解決しました — 粘着的なヘッダーをposition: stickyに変えた時に。Scroll-driven animationsは同じ手法を、すべてのスクロールに連動したエフェクトに一度に適用したものです。

View TransitionsとNext.js:ライブラリなしのページアニメーション

10年間、サムネイルをヒーロー画像にアニメーションさせるには一つの技法しかなかった:前後の位置を測定し、transformでその差を偽り、再生する。FLIP。すべてのアニメーションライブラリがそれを行い、すべてが最悪のタイミングでメインスレッドのJavaScriptという代償を払ってきた。View Transitions APIはそのトリック全体をブラウザに移し、React 19.2とNext.js 16以降、契約全体はnameという一つのpropだけになった。

Core Web Vitals:INPが本当に測っているもの、そしてscheduler.yield()がメインスレッドを救う仕組み

マイクロインタラクションの記事では、transformとopacityがコンポジタースレッド上でアニメーションするので、重いページでもボタンのアニメーションがカクつくことはないはずだと書いた。それは今も真実だ——ただし、あの記事が触れていなかった一つの留保がある。メインスレッドが長いJSタスクによってブロックされていれば、アニメーションはそもそも起動する機会すら得られないかもしれない。クリックのハンドラ自体がキューで待たされているからだ。INPはまさにこのギャップを測る指標であり、scheduler.yield()はそれを実際に埋めるための数少ない手段の一つである。

content-visibility:リストの仮想化なしで実現するオフスクリーンレンダリング

千件のコメントを含むリストのレンダリングが遅いので react-window に手を伸ばす——すると、なめらかなスクロールと引き換えに、Ctrl+F、ページの印刷、そしてスクリーンリーダーのナビゲーションの一部を失うことになる。表示ウィンドウの外にある要素が、DOMから物理的に存在しなくなってしまうからだ。content-visibility はまったく別の角度から同じパフォーマンス問題を解決する。要素はDOMに残ったままで、ブラウザはただ、要素が表示領域の近くに来るまで、レイアウトや描画といったコストの高い処理をその要素に対して省略するだけだ。そして驚くべきことに、テキストを検索したときには一時的にその要素を『見える状態』に戻すことさえできる。

Popover APIとネイティブな`<dialog>`:ゼロから手作りするモーダルの終わり

アクセシビリティの記事で取り上げた、`display: none`で隠されているのにアクセシビリティツリーには残り続けていたモーダルは、divをゼロから組み立ててモーダルを作ることに起因するミスの一例でした。本当に問うべきなのは、そもそもなぜゼロから作らなければならなかったのか、ということです。ネイティブな`<dialog>`とpopover属性が無料で提供してくれるもの——top layer、フォーカストラップ、light dismiss——を確認し、この二つの仕組みがどこでどれほど違うのか、その違いを取り違えることがいかに簡単にアクセシビリティを欠いたインターフェースへの近道になるかを見ていきます。