Behind the Scenes: Dive into View Transition
Browser & UI #1 CSS
saku🌸 / @sakupi01
saku
Design Technologist / ex-Web Frontend @Cybozu
Goolgle Developer Expert for Web Technologies
🍏 / ☕ / 🌏 >
Behind the Scenes: Dive into View Transition
Same-Document
View Transition
for SPA!
Mozilla is positive!
Selected to Interop 2025 Focus Area!
const { matches:motionIsOk } = window.matchMedia('(prefers-reduced-motion: no-preference)')
document.addEventListener("click", (e) => {
if (!document.startViewTransition || !motionIsOk) {
helloWorld.next();
return;
}
document.startViewTransition(() => {
helloWorld.next();
});
});
どういうしくみ?????????
どういうしくみ?????????
UAデフォルトのView Transition (mac 54.56fps)
イベント:click / ブラウザ:スクショ撮る
document.addEventListener("click", (e) => {
document.startViewTransition(() => {
// helloWorld.next();
// });
});
イベント:DOMの変更完了 / ブラウザ:LIVEスクショ撮る
// document.addEventListener("click", (e) => {
document.startViewTransition(() => {
helloWorld.next();
});
});
Once complete, the callback passed to .startViewTransition() is called. That's where the DOM is changed. Then, the API captures the new state of the page.
::view-transition-old() / ::view-transition-new()
document.addEventListener("click", (e) => {
document.startViewTransition(() => {
helloWorld.next();
});
});
Setup transition pseudo-elements
html::view-transition // Rendered on top of the document (over Top Layer)
└─ ::view-transition-group(root) // Position + Size
└─ ::view-transition-image-pair(root) // Blend Mode Isolation
├─ ::view-transition-old(root) // 📸 Old Snapshot
└─ ::view-transition-new(root) // 📸 New Live Snapshot
::view-transition: documentをoriginating elementとして持つ擬似要素。(snapshot containing blockの領域を指す)view-transition-group(root):view-transition-nameが同じ要素をグループ化する擬似要素::view-transition-image-pair(root): 新旧のスクリーンショットのペア。VTのUAデフォルトBlend Mode を正しく適用するため、isolation: isolateが指定されている。::view-transition-old(root): DOM変更前のスクリーンショット。デフォルトではmix-blend-mode: plus-lighterが指定されている。::view-transition-new(root): DOM変更後のスクリーンショット。デフォルトではmix-blend-mode: plus-lighterが指定されている。
Set up Default Animation
/* If capturedElement’s old image is null, then: */
html::view-transition-new(transitionName) {
animation-name: -ua-view-transition-fade-in;
}
/* If capturedElement’s new element is null, then: */
html::view-transition-old(transitionName) {
animation-name: -ua-view-transition-fade-out;
}
/* If both of capturedElement’s old image and new element are not null, then: */
@keyframes -ua-view-transition-group-anim-transitionName {
from {
transform: transform;
width: width;
height: height;
}
}
html::view-transition-group(transitionName) {
animation-name: -ua-view-transition-group-anim-transitionName;
}
...
/* ref: https://www.w3.org/TR/css-view-transitions-1/#setup-transition-pseudo-elements-algorithm */
- すべてのアニメーションはCSSアニメーションで行われるため、CSSでカスタマイズ可能。
::view-transitionツリーがクリーンアップされる
〜完〜
アニメーションのカスタマイズ
view-transition-nameview-transition-classview-transition-types
Cross-Document
View Transition
for MPA!
ネットワークめっちゃ遅延させた時、画像が読み込まれながらVTするので、LIVEスクショということもわかる
Cross-Document View Transition
- View Transition without JavaScript!
/* ✅ Opt-in to cross-document view transitions! */
@view-transition {
navigation: auto;
}
Cross-Document View Transition
- View Transition without JavaScript!
/* ✅ Opt-in to cross-document view transitions! */
@view-transition {
navigation: auto;
}
- Available in Main frame or Nested iframe
Cross-Document View Transition
- View Transition without JavaScript!
/* ✅ Opt-in to cross-document view transitions! */
@view-transition {
navigation: auto;
}
- Available in Main frame or Nested iframe
- Same-Origin Navigation
Regulation of Cross-Document View Transition
- ① WebKitベースブラウザをタッチデバイスで使った時のVTがダブる/できない
- ② Cross-Document VTは宣言的なので、DOMの変更を明示できない
- Same-Document VTでは、
document.startViewTransitionのコールバックでDOMの変更を命令的に示すことができた
- Same-Document VTでは、
Regulation of Cross-Document View Transition
- ① WebKitベースブラウザをタッチデバイスで使った時のVTがダブる/できない
- ② Cross-Document VTは宣言的なので、DOMの変更を明示できない
- Same-Document VTでは、
document.startViewTransitionのコールバックでDOMの変更を命令的に示すことができた
- Same-Document VTでは、
WebKitベースブラウザをタッチデバイスで使った時のNavigation
- ジェスチャーでナビゲーションすると、デフォルトで、ブラウザが前ページのプレビューを表示する
- ブラウザのアニメーションとVTのアニメーションがダブる...
hasUAVisualTransition Property
- ブラウザ:「こっちでアニメーションしといたから、もうやらなくていいよ」
- アニメーションのダブりは防げるんだけど、そうじゃない...
const { matches:motionIsOk } = window.matchMedia('(prefers-reduced-motion: no-preference)')
document.addEventListener("click", (e) => {
if (!document.startViewTransition || !motionIsOk || e.hasUAVisualTransition) {
helloWorld.next();
return;
}
document.startViewTransition(() => {
helloWorld.next();
});
});
Regulation of Cross-Document View Transition
- ① WebKitベースブラウザをタッチデバイスで使った時のVT
- ② Cross-Document VTは宣言的なので、DOMの変更を明示できない
- Same-Document VTでは、
document.startViewTransitionのコールバックでDOMの変更を命令的に示すことができた
- Same-Document VTでは、
Regulation of Cross-Document View Transition
- ① WebKitベースブラウザをタッチデバイスで使った時のVT
- ② Cross-Document VTは宣言的なので、DOMの変更を明示できない
- Same-Document VTでは、
document.startViewTransitionのコールバックでDOMの変更を命令的に示すことができた - CDVTはrender-blocking mechanismを利用してView Transitionを行なっている
- Same-Document VTでは、
ブラウザは基本的にインクリメンタルなレンダリングをする
- render-blocking mechanism により、以下(など)の場合にレンダーがブロックされている
- bodyがnullのとき
- ブラウザエンジンのtimeoutを超えていないとき etc
- +scriptとstylesheetで
block=renderingを指定して制御もできる
Document Render-Blocking
- VTでは、「DOMの状態」が作成されるTransitionに影響を与える
- → render-blockingをNodeによって制御できるといい
- Nodeをrender-blockingの対象に指定できるように
< !-- Wait until the main-article element is seen and fully parsed before activating the transition -->
<link rel="expect" href="#main-article" blocking="render">
ref: https://www.w3.org/TR/css-view-transitions-2/#example-ece69f12
Speculation Rules API
- 投機的にページをpre-renderingする
- CDVTと併用するとGood
- Chromiumのみ
<script type="speculationrules">
{
"prerender": [
{
"urls": ["next.html", "next2.html"]
}
]
}
</script>
⬆️ Upcoming View Transition Features ?!
Same-Site Cross-Origin View Transition
https://a.thing.com/ -> https://b.thing.com/
Same-origin (for now)
Cross-document view transitions are only enabled for same-origin navigations without a cross-origin redirect. In the future we could examine relaxing this restriction in some way to same-site navigations.
view-transitions/cross-doc-explainer.md at main · WICG/view-transitions
プライバシーの懸念があるので、慎重に検討されている
view-transition-name: match-element;, view-transition-name: auto;
view-transition-nameを自動生成してほしい!view-transition-name: match-element;,view-transition-name: auto;の提案view-transition-name: match-element;: DOMid属性に関係なく、自動で「Element を参照した Identity」を生成するview-transition-name: auto;:attr(id ident, match-element)のシンタックスシュガーみたいなもの
view-transition-name: auto;に関しては反対意見もある中、Safari 18.2で先立って実装された
Nested View Transition
- DOMの構造がどれだけ複雑でも、
::view-transitionツリーはフラットに生成される - clippingやtransform、animationなど、DOM構造がスタイルに影響する場合に対する提案
<section class="container">
<img class="icon">
</section>
...
<style>
.container {
clip-path: circle();
view-transition-name: container;
}
.icon {
view-transition-name: icon;
}
</style>
// container does not clip icon
::view-transition
::view-transition-group(container)
::view-transition-image-pair(container)
::view-transition-group(icon)
::view-transition-image-pair(icon)
Nested View Transition
- DOMの構造がどれだけ複雑でも、
::view-transitionツリーはフラットに生成される - clippingやtransform、animationなど、DOM構造がスタイルに影響する場合に対する提案
<section class="container">
<img class="icon">
</section>
...
<style>
::view-transition-group(container) {
clip-path: circle();
}
.icon {
view-transition-group: container; // or `nearest`
}
</style>
// container clips icon
::view-transition
::view-transition-group(container)
::view-transition-image-pair(container)
::view-transition-group(icon)
::view-transition-image-pair(icon)
Scoped View Transition
- document直下にのみ
::view-transitionは生成されていたが、任意のHTML要素に対して::view-transitionを生成できるようにする提案- VTの範囲を限定できる
- VTの間、ページ全体がinertにならない(inertになる範囲を限定できる)
- 親要素のclipやtransform, animationを考慮してVTが実行できる
z-indexを考慮してVTが実行できるので、ドロップダウンなどのVT領域をオーバーレイするUIに影響を与えない- 複数のVTを並行して実行できる
element.startViewTransition(() => {
// Update the DOM somehow.
});
Reactがunstable_ViewTransitionを実験的に提供
Add <ViewTransition> Component by sebmarkbage · Pull Request #31975 · facebook/react

まとめ
着実に進化を続けるView Transitionの今後に期待!
※ スポンサートークですが、弊社はView Transitionを使用しておりません
ご清聴ありがとうございました!
Thank you!
Appendix
- CSS View Transition Module Level 1
- CSS View Transition Module Level 2
- Misconceptions about view transitions | Blog | Chrome for Developers
- Smooth transitions with the View Transition API | View Transition | Chrome for Developers
- Same-document view transitions for single-page applications | View Transition | Chrome for Developers
- Cross-document view transitions for multi-page applications | View Transition | Chrome for Developers
- View transitions: Handling aspect ratio changes - JakeArchibald.com
- https://lists.w3.org/Archives/Public/www-archive/2024Feb/att-0000/scoped-transitions.pdf
- View Transition: Scoped Transitions - Google スライド
- 'blocking=rendering' attribute on scripts and style sheets - Chrome Platform Status
- Improvements to the Speculation Rules API | Blog | Chrome for Developers
When .startViewTransition() is called, the API captures the current state of the page. This includes taking a snapshot.