[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"article-view-transitions-native-page-transitions":32,"code:css:true:1lpueyk":218,"code:css:true:1o7ohkd":219,"code:css:true:1e15qs6":220,"code:js:true:1mrq6co":221,"code:js:true:5xrbtv":222},[4,20],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[13,15,29],"es",{"courses":17,"paths":17,"articles":18,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":17},2,{"id":33,"slug":34,"title":35,"subtitle":36,"excerpt":37,"coverUrl":38,"locale":13,"readingMinutes":39,"publishedAt":40,"viewCount":39,"likeCount":19,"commentCount":19,"author":41,"vertical":46,"topic":47,"tags":50,"_count":62,"playground":36,"body":63,"bodyMd":209,"seo":210,"translationGroupId":212,"thread":213,"assessments":215,"translations":216,"quiz":36},"019fe65f-d8d6-73ed-b26b-18726a494914","view-transitions-native-page-transitions","The page transition you pay a library for is now free",null,"You reach for Framer Motion or GSAP to make navigation feel smooth. The View Transitions API does the same thing natively — and the starting price is a single CSS rule.","\u002Fmedia\u002Fcovers\u002Fview-transitions-native-page-transitions.png",5,"2026-07-03T09:26:36.534Z",{"id":42,"name":43,"username":44,"avatarUrl":36,"headline":45},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":48,"name":49},"css","CSS",[51,53,56,59],{"slug":48,"name":52,"color":36},"Css",{"slug":54,"name":55,"color":36},"webdev","Webdev",{"slug":57,"name":58,"color":36},"frontend","Frontend",{"slug":60,"name":61,"color":36},"javascript","Javascript",{"assessments":19},{"blocks":64,"version":208},[65,69,72,75,79,82,87,90,93,96,99,102,109,112,115,119,122,125,128,132,135,138,141,144,147,152,155,159,162,166,169,173,176,179,182,185,188,191,194,197,200],{"id":66,"html":67,"type":68},"b1","\u003Cp>Picture the last time you wired up a page transition. The leaving page&#39;s exit. The entering page&#39;s entrance. The awkward in-between where both exist at once. Maybe a \u003Ccode>getBoundingClientRect()\u003C\u002Fcode> here, a hand-tuned \u003Ccode>transform\u003C\u002Fcode> there, a library install to coordinate it all.\u003C\u002Fp>","paragraph",{"id":70,"html":71,"type":68},"b2","\u003Cp>That whole apparatus was for an effect a native app gets by existing.\u003C\u002Fp>",{"id":73,"html":74,"type":68},"b3","\u003Cp>Here&#39;s the part that&#39;ll annoy you: the browser does it now. The simplest version — a smooth cross-fade across your entire site — costs exactly one CSS rule. The fancy version, where a thumbnail morphs into a full hero image as you navigate, costs two. And neither one needs a single line of JavaScript. Let me show you the one-rule version first, then build up to the morph.\u003C\u002Fp>",{"id":76,"html":77,"text":77,"type":78,"level":31},"b4","One rule. The whole site cross-fades.","heading",{"id":80,"html":81,"type":68},"b5","\u003Cp>If you&#39;ve got a regular multi-page app — separate HTML documents per page — opt into automatic transitions with this:\u003C\u002Fp>",{"id":83,"code":84,"type":85,"language":48,"highlight":86},"b6","@view-transition {\n  navigation: auto;\n}","code",[],{"id":88,"html":89,"type":68},"b7","\u003Cp>Drop it in your stylesheet. Navigate. Every page change is now a gentle cross-fade. No JS, no library, no event listeners, no coordination.\u003C\u002Fp>",{"id":91,"html":92,"type":68},"b8","\u003Cp>What&#39;s the browser actually doing? It screenshots the outgoing page, runs the navigation, then animates from that screenshot to the new page — a 300ms opacity cross-fade by default. Exactly the baseline you&#39;d have built by hand. And it&#39;s strictly opt-in: without that rule, navigation stays instant, same as always.\u003C\u002Fp>",{"id":94,"html":95,"type":68},"b9","\u003Cp>That&#39;s the freebie. But &quot;everything cross-fades&quot; isn&#39;t why this API matters. Hold that thought.\u003C\u002Fp>",{"id":97,"html":98,"text":98,"type":78,"level":31},"b10","The mental model that makes the rest click",{"id":100,"html":101,"type":68},"b11","\u003Cp>Every view transition is the same three beats:\u003C\u002Fp>",{"id":103,"type":104,"items":105,"ordered":17},"b12","list",[106,107,108],"\u003Cstrong>Capture\u003C\u002Fstrong> — the browser snapshots the current page.","\u003Cstrong>Change\u003C\u002Fstrong> — your navigation (or DOM update) runs.","\u003Cstrong>Animate\u003C\u002Fstrong> — the browser builds two pseudo-elements, \u003Ccode>::view-transition-old\u003C\u002Fcode> and \u003Ccode>::view-transition-new\u003C\u002Fcode>, and tweens between them.",{"id":110,"html":111,"type":68},"b13","\u003Cp>This is the opposite of how a motion library thinks. A library makes you \u003Cem>describe the motion\u003C\u002Fem>: this exits left, that enters right, here&#39;s the easing. View Transitions make you describe \u003Cem>what should transition\u003C\u002Fem> — the browser figures out \u003Cem>how\u003C\u002Fem> by diffing before against after.\u003C\u002Fp>",{"id":113,"html":114,"type":68},"b14","\u003Cp>Want something other than a cross-fade? Style those pseudo-elements like anything else:\u003C\u002Fp>",{"id":116,"code":117,"type":85,"language":48,"highlight":118},"b15","::view-transition-old(root) {\n  animation: 250ms ease-in both fade-out, 250ms ease-in both slide-out;\n}\n::view-transition-new(root) {\n  animation: 250ms ease-out both fade-in, 250ms ease-out both slide-in;\n}\n@keyframes slide-out { to   { transform: translateX(-30px); } }\n@keyframes slide-in  { from { transform: translateX(30px);  } }",[],{"id":120,"html":121,"type":68},"b16","\u003Cp>Now every navigation is a subtle directional slide. Still zero JavaScript.\u003C\u002Fp>",{"id":123,"html":124,"text":124,"type":78,"level":31},"b17","The trick worth the price of admission",{"id":126,"html":127,"type":68},"b18","\u003Cp>Here&#39;s the thought you parked earlier. The real payoff isn&#39;t the cross-fade — it&#39;s telling the browser \u003Cem>&quot;this element on page A is the same element as that one on page B.&quot;\u003C\u002Fem> Give them a shared name and the browser morphs one into the other.\u003C\u002Fp>",{"id":129,"code":130,"type":85,"language":48,"highlight":131},"b19","\u002F* list page *\u002F\n.product-card[data-id=\"42\"] img { view-transition-name: product-hero-42; }\n\n\u002F* detail page *\u002F\n.product-hero-image { view-transition-name: product-hero-42; }",[],{"id":133,"html":134,"type":68},"b20","\u003Cp>Navigate from the list to the detail page and the thumbnail flies into place as the full hero — position, size, shape, all interpolated. You wrote no animation. You declared an \u003Cem>identity\u003C\u002Fem>, and the browser handled every pixel of geometry.\u003C\u002Fp>",{"id":136,"html":137,"type":68},"b21","\u003Cp>Be honest: how much code did this take last time? \u003Ccode>getBoundingClientRect()\u003C\u002Fcode> on both elements, the delta math, a \u003Ccode>transform\u003C\u002Fcode> to fake the start position, timing to undo it. A few hundred lines, easy. Here it&#39;s two rules whose names match.\u003C\u002Fp>",{"id":139,"html":140,"type":68},"b22","\u003Cp>One gotcha: \u003Ccode>view-transition-name\u003C\u002Fcode> must be unique in the DOM at any instant. Rendering a list of cards? Set the name dynamically so only the card being navigated carries it, or scope it with \u003Ccode>:has()\u003C\u002Fcode> to the active state.\u003C\u002Fp>",{"id":142,"html":143,"text":143,"type":78,"level":31},"b23","SPAs get the same engine, behind a function",{"id":145,"html":146,"type":68},"b24","\u003Cp>If you own navigation programmatically, the JS API exposes that same capture-change-animate cycle:\u003C\u002Fp>",{"id":148,"code":149,"type":85,"language":150,"highlight":151},"b25","\u002F\u002F before:\nupdatePageContent();\n\n\u002F\u002F after:\ndocument.startViewTransition(() => updatePageContent());","js",[],{"id":153,"html":154,"type":68},"b26","\u003Cp>Pass a callback that mutates the DOM. The browser captures before, runs your function, captures after, plays the transition. Your update logic doesn&#39;t change — you wrap it. React Router and the Next.js App Router are threading this into their navigation primitives, but underneath, the primitive never changes: snapshot, update, animate.\u003C\u002Fp>",{"id":156,"html":157,"text":158,"type":78,"level":31},"b27","Adding it can&#39;t break anything","Adding it can't break anything",{"id":160,"html":161,"type":68},"b28","\u003Cp>This is the part that should make you comfortable shipping it today: it&#39;s purely additive. Browsers without support — and the holdouts are thinning, with Chrome, Firefox, and Safari all shipping it — just navigate instantly, like they always did. The guard is a one-liner:\u003C\u002Fp>",{"id":163,"code":164,"type":85,"language":150,"highlight":165},"b29","if (document.startViewTransition) {\n  document.startViewTransition(() => updatePageContent());\n} else {\n  updatePageContent();\n}",[],{"id":167,"html":168,"type":68},"b30","\u003Cp>No polyfill, no fallback CSS, no broken state. The browser plays the transition or it doesn&#39;t.\u003C\u002Fp>",{"id":170,"html":171,"text":172,"type":78,"level":31},"b31","Where it fits — and where it doesn&#39;t","Where it fits — and where it doesn't",{"id":174,"html":175,"type":68},"b32","\u003Cp>Reach for View Transitions on \u003Cstrong>navigational context changes\u003C\u002Fstrong>: moving between pages, opening a detail from a list, expanding an inline panel. &quot;You&#39;re going from here to there&quot; maps onto the API naturally.\u003C\u002Fp>",{"id":177,"html":178,"type":68},"b33","\u003Cp>Don&#39;t reach for it on \u003Cstrong>micro-interactions inside a view\u003C\u002Fstrong>: hovers, spinners, a toggle&#39;s state change, a choreographed timeline. Those want CSS \u003Ccode>transition\u003C\u002Fcode>\u002F\u003Ccode>animation\u003C\u002Fcode> or a real motion library where you control every keyframe.\u003C\u002Fp>",{"id":180,"html":181,"type":68},"b34","\u003Cp>The line: animation driven by \u003Cem>navigation between views\u003C\u002Fem> → View Transitions. Animation driven by \u003Cem>interaction within a view\u003C\u002Fem> → regular CSS or a library.\u003C\u002Fp>",{"id":183,"html":184,"text":184,"type":78,"level":31},"b35","Back to that library you were about to install",{"id":186,"html":187,"type":68},"b36","\u003Cp>The honest scope: View Transitions won&#39;t replace intricate choreography — that still needs more. What they replace is the \u003Cem>default\u003C\u002Fem> case. The clean cross-fade. The hero morph. The transition every multi-page app should have and usually skips, because nobody wanted to pull in Framer Motion for something that basic.\u003C\u002Fp>",{"id":189,"html":190,"type":68},"b37","\u003Cp>Takeaway for tomorrow: \u003Cstrong>before you add an animation library for navigation, ask what one CSS rule already buys you.\u003C\u002Fstrong> Often it&#39;s most of what you needed — and the rest is two matching names.\u003C\u002Fp>",{"id":192,"html":193,"type":68},"b38","\u003Cp>What&#39;s the page transition you abandoned because wiring it up wasn&#39;t worth it? Try the one-rule version on it tonight and tell me how close it got in the comments.\u003C\u002Fp>",{"id":195,"type":196},"b39","divider",{"id":198,"html":199,"type":68},"b40","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":201,"type":104,"items":202,"ordered":18},"b41",[203,204,205,206,207],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","💼 \u003Cstrong>LinkedIn\u003C\u002Fstrong> — \u003Ca href=\"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F\">linkedin.com\u002Fin\u002Fparsa-jiravand\u003C\u002Fa>","✉️ \u003Cstrong>Email\u003C\u002Fstrong> (work &amp; contract inquiries): \u003Ca href=\"mailto:bestpractice2026@gmail.com\">bestpractice2026@gmail.com\u003C\u002Fa>",1,"Picture the last time you wired up a page transition. The leaving page's exit. The entering page's entrance. The awkward in-between where both exist at once. Maybe a `getBoundingClientRect()` here, a hand-tuned `transform` there, a library install to coordinate it all.\n\nThat whole apparatus was for an effect a native app gets by existing.\n\nHere's the part that'll annoy you: the browser does it now. The simplest version — a smooth cross-fade across your entire site — costs exactly one CSS rule. The fancy version, where a thumbnail morphs into a full hero image as you navigate, costs two. And neither one needs a single line of JavaScript. Let me show you the one-rule version first, then build up to the morph.\n\n## One rule. The whole site cross-fades.\n\nIf you've got a regular multi-page app — separate HTML documents per page — opt into automatic transitions with this:\n\n```css\n@view-transition {\n  navigation: auto;\n}\n```\n\nDrop it in your stylesheet. Navigate. Every page change is now a gentle cross-fade. No JS, no library, no event listeners, no coordination.\n\nWhat's the browser actually doing? It screenshots the outgoing page, runs the navigation, then animates from that screenshot to the new page — a 300ms opacity cross-fade by default. Exactly the baseline you'd have built by hand. And it's strictly opt-in: without that rule, navigation stays instant, same as always.\n\nThat's the freebie. But \"everything cross-fades\" isn't why this API matters. Hold that thought.\n\n## The mental model that makes the rest click\n\nEvery view transition is the same three beats:\n\n1. **Capture** — the browser snapshots the current page.\n2. **Change** — your navigation (or DOM update) runs.\n3. **Animate** — the browser builds two pseudo-elements, `::view-transition-old` and `::view-transition-new`, and tweens between them.\n\nThis is the opposite of how a motion library thinks. A library makes you *describe the motion*: this exits left, that enters right, here's the easing. View Transitions make you describe *what should transition* — the browser figures out *how* by diffing before against after.\n\nWant something other than a cross-fade? Style those pseudo-elements like anything else:\n\n```css\n::view-transition-old(root) {\n  animation: 250ms ease-in both fade-out, 250ms ease-in both slide-out;\n}\n::view-transition-new(root) {\n  animation: 250ms ease-out both fade-in, 250ms ease-out both slide-in;\n}\n@keyframes slide-out { to   { transform: translateX(-30px); } }\n@keyframes slide-in  { from { transform: translateX(30px);  } }\n```\n\nNow every navigation is a subtle directional slide. Still zero JavaScript.\n\n## The trick worth the price of admission\n\nHere's the thought you parked earlier. The real payoff isn't the cross-fade — it's telling the browser *\"this element on page A is the same element as that one on page B.\"* Give them a shared name and the browser morphs one into the other.\n\n```css\n\u002F* list page *\u002F\n.product-card[data-id=\"42\"] img { view-transition-name: product-hero-42; }\n\n\u002F* detail page *\u002F\n.product-hero-image { view-transition-name: product-hero-42; }\n```\n\nNavigate from the list to the detail page and the thumbnail flies into place as the full hero — position, size, shape, all interpolated. You wrote no animation. You declared an *identity*, and the browser handled every pixel of geometry.\n\nBe honest: how much code did this take last time? `getBoundingClientRect()` on both elements, the delta math, a `transform` to fake the start position, timing to undo it. A few hundred lines, easy. Here it's two rules whose names match.\n\nOne gotcha: `view-transition-name` must be unique in the DOM at any instant. Rendering a list of cards? Set the name dynamically so only the card being navigated carries it, or scope it with `:has()` to the active state.\n\n## SPAs get the same engine, behind a function\n\nIf you own navigation programmatically, the JS API exposes that same capture-change-animate cycle:\n\n```js\n\u002F\u002F before:\nupdatePageContent();\n\n\u002F\u002F after:\ndocument.startViewTransition(() => updatePageContent());\n```\n\nPass a callback that mutates the DOM. The browser captures before, runs your function, captures after, plays the transition. Your update logic doesn't change — you wrap it. React Router and the Next.js App Router are threading this into their navigation primitives, but underneath, the primitive never changes: snapshot, update, animate.\n\n## Adding it can't break anything\n\nThis is the part that should make you comfortable shipping it today: it's purely additive. Browsers without support — and the holdouts are thinning, with Chrome, Firefox, and Safari all shipping it — just navigate instantly, like they always did. The guard is a one-liner:\n\n```js\nif (document.startViewTransition) {\n  document.startViewTransition(() => updatePageContent());\n} else {\n  updatePageContent();\n}\n```\n\nNo polyfill, no fallback CSS, no broken state. The browser plays the transition or it doesn't.\n\n## Where it fits — and where it doesn't\n\nReach for View Transitions on **navigational context changes**: moving between pages, opening a detail from a list, expanding an inline panel. \"You're going from here to there\" maps onto the API naturally.\n\nDon't reach for it on **micro-interactions inside a view**: hovers, spinners, a toggle's state change, a choreographed timeline. Those want CSS `transition`\u002F`animation` or a real motion library where you control every keyframe.\n\nThe line: animation driven by *navigation between views* → View Transitions. Animation driven by *interaction within a view* → regular CSS or a library.\n\n## Back to that library you were about to install\n\nThe honest scope: View Transitions won't replace intricate choreography — that still needs more. What they replace is the *default* case. The clean cross-fade. The hero morph. The transition every multi-page app should have and usually skips, because nobody wanted to pull in Framer Motion for something that basic.\n\nTakeaway for tomorrow: **before you add an animation library for navigation, ask what one CSS rule already buys you.** Often it's most of what you needed — and the rest is two matching names.\n\nWhat's the page transition you abandoned because wiring it up wasn't worth it? Try the one-rule version on it tonight and tell me how close it got in the comments.\n\n---\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)\n- 💼 **LinkedIn** — [linkedin.com\u002Fin\u002Fparsa-jiravand](https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F)\n- ✉️ **Email** (work & contract inquiries): [bestpractice2026@gmail.com](mailto:bestpractice2026@gmail.com)",{"title":35,"canonical":211,"description":37},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fview-transitions-native-page-transitions","019fe65f-d8d6-73ed-b26b-1d46904e12a3",{"id":214,"locked":18},"019fe65f-dfd3-718a-9f38-852b484bb77e",[],[217],{"locale":13,"slug":34},"\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">@view\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">-transition\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">navigation\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">auto\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-var\">::view-transition-old\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">root\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">animation\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">250\u003C\u002Fspan>ms \u003Cspan class=\"shj-num\">ease-in\u003C\u002Fspan> \u003Cspan class=\"shj-num\">both\u003C\u002Fspan> \u003Cspan class=\"shj-num\">fade-out\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">250\u003C\u002Fspan>ms \u003Cspan class=\"shj-num\">ease-in\u003C\u002Fspan> \u003Cspan class=\"shj-num\">both\u003C\u002Fspan> \u003Cspan class=\"shj-num\">slide-out\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-var\">::view-transition-new\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">root\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">animation\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">250\u003C\u002Fspan>ms \u003Cspan class=\"shj-num\">ease-out\u003C\u002Fspan> \u003Cspan class=\"shj-num\">both\u003C\u002Fspan> \u003Cspan class=\"shj-num\">fade-in\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">250\u003C\u002Fspan>ms \u003Cspan class=\"shj-num\">ease-out\u003C\u002Fspan> \u003Cspan class=\"shj-num\">both\u003C\u002Fspan> \u003Cspan class=\"shj-num\">slide-in\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">@keyframes\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">slide-out\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">to\u003C\u002Fspan>   \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">transform\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">translateX\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>-\u003Cspan class=\"shj-num\">30\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-kwd\">@keyframes\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">slide-in\u003C\u002Fspan>  \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">from\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">transform\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">translateX\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">30\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F* list page *\u002F\u003C\u002Fspan>\n\u003Cspan class=\"shj-var\">.product-card\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">data-id\u003C\u002Fspan>=\u003Cspan class=\"shj-str\">\"42\"\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">img\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">view-transition-name\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">product-hero-\u003C\u002Fspan>\u003Cspan class=\"shj-num\">42\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-cmnt\">\u002F* detail page *\u002F\u003C\u002Fspan>\n\u003Cspan class=\"shj-var\">.product-hero-image\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">view-transition-name\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">product-hero-\u003C\u002Fspan>\u003Cspan class=\"shj-num\">42\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F before:\n\u003C\u002Fspan>\u003Cspan class=\"shj-func\">updatePageContent\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\n\u003Cspan class=\"shj-cmnt\">\u002F\u002F after:\n\u003C\u002Fspan>document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">startViewTransition\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-func\">updatePageContent\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>startViewTransition\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">startViewTransition\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-func\">updatePageContent\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">else\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-func\">updatePageContent\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>"]