Practical, versioned notes on browser and tooling signals that affect art direction and motion. Every claim below links to an authoritative source cited in research.
- Chrome (Mar 27, 2026)
+ - Element-scoped view transitions (Chrome 147) — Chrome 147 exposes element-scoped transitions via Element.startViewTransition(), which lets you start a view transition on a DOM subtree instead of the whole document. Key behavior:
+ - Scope roots are self-participating by default and automatically become transition roots.
+ - Scoped transitions use nested view transition groups so nested pseudos participate predictably.
+ - The ::view-transition-group-children() pseudo is available inside scoped transitions and will clip its contents when the scope root clips overflow.
+ - During the transition the user agent applies contain: layout and view-transition-scope: all onto the scope root to avoid layout leakage and layering issues with position:fixed content.
+ These changes enable concurrent and nested transitions, fix many z-index and clipping issues from document-scoped transitions, and keep the rest of the page interactive. Read the Chrome guide and see copy-pasteable demos at the View Transitions demo site: https://view-transitions.chrome.dev/. (Chrome blog: Mar 27, 2026)
− - Element-scoped view transitions (Chrome 147) — Chrome 147 exposes element-scoped transitions via Element.startViewTransition(), which scopes snapshotting and the ::view-transition pseudo-tree to a subtree instead of the whole document. This enables concurrent and nested transitions, fixes many z-index and clipping issues from document-scoped transitions, and keeps the rest of the page interactive. See the Chrome blog announcement (Mar 27, 2026) and the developer guide and live demos for copy-pasteable examples.
+ - Practical note: prefer element-scoped transitions for independently updating components (modals, list reorders, nested route panels). When nesting, follow the docs for view-transition-name, containment, and clipping to avoid visual leakage.
− - Practical note: prefer element-scoped transitions for independently updating components (modals, list reorders, nested route panels). When nesting, follow the docs for view-transition-name, containment, and clipping to avoid visual leakage. Live demos and additional guidance: https://view-transitions.chrome.dev/.
- Feature detection pattern (copy-pasteable, robust):
```js
− // Support both Element.startViewTransition and document.startViewTransition
+ // Support Element.startViewTransition and document.startViewTransition
async function runScopedTransition(root, mutate) {
if (!root) return mutate();
@@ −52 +57 @@
```
- Chrome (Apr 20, 2026)
+ - Soft Navigations origin trial (Chrome 147→149) — Chrome is running a final origin trial for the Soft Navigations API. A "soft navigation" is when JavaScript updates page content and the URL without unloading the document (typical SPA navigation). The API introduces two new PerformanceEntry types:
+ - SoftNavigationEntry: emitted when the soft navigation completes. Contains navigationId, interactionId, name (new URL), and paint timings useful to compute first/meaningful-content timings.
+ - InteractionContentfulPaint: emitted for contentful paints tied to an interaction; useful to measure LCP-like signals for SPA navigations.
+ Both entries can be observed with PerformanceObserver using the "soft-navigation" and "interaction-contentful-paint" types. This is important for RUM: browsers only emit LCP on full navigations, so SPAs need these entries to capture equivalent metrics. See the Chrome origin trial announcement for details and registration: https://developer.chrome.com/blog/final-soft-navigations-origin-trial?hl=en.
+
− - Soft Navigations origin trial (Chrome 147→149) — Chrome is running a final origin trial for the Soft Navigations API that detects SPA-style navigations where the URL changes but the document is not unloaded. The API emits SoftNavigationEntry and InteractionContentfulPaint performance entries which RUM and analytics can observe via PerformanceObserver to measure Core Web Vitals (for example, LCP for soft navigations). This is particularly relevant when you use client-side routing with view transitions or when you need browser-level timing for SPAs. See the Chrome blog announcement (Apr 20, 2026) for details and origin trial registration: https://developer.chrome.com/blog/final-soft-navigations-origin-trial?hl=en.
+ Example RUM snippet (copy-pasteable):
− - Practical note: add SoftNavigationEntry handling to your RUM instrumentation if your app uses client-side routing. Example RUM snippet (copy-pasteable):
```js
− // Observe browser soft navigation and interaction contentful paint entries
if (typeof PerformanceObserver !== 'undefined') {
− const handleEntry = (entry) => {
− // Send to your RUM backend or log for debugging
− // Example: convert to a shape your RUM expects and beacon it
− console.log('soft-navigation entry', entry);
− };
−
try {
− const obs = new PerformanceObserver((list) => {
+ const obs = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'soft-navigation') {
− // entry.navigationId, entry.name (url), entry.interactionId, paint timings
navigator.sendBeacon('/rum', JSON.stringify({
type: 'soft-navigation',
navigationId: entry.navigationId,
url: entry.name,
+ timing: {
+ startTime: entry.startTime,
+ paintTiming: entry.paintTiming || null
− timing: entry
+ }
}));
}
if (entry.entryType === 'interaction-contentful-paint') {
− // Use this to approximate LCP for SPA navigations
navigator.sendBeacon('/rum', JSON.stringify({
type: 'interaction-contentful-paint',
interactionId: entry.interactionId,
size: entry.size,
− time: entry.startTime
+ startTime: entry.startTime
}));
}
}
@@ −92 +95 @@
obs.observe({ type: 'soft-navigation', buffered: true });
obs.observe({ type: 'interaction-contentful-paint', buffered: true });
} catch (e) {
− // Some browsers may not yet support these entry types — fallback to framework hooks
console.warn('Soft navigation PerformanceObserver not available', e);
}
}
```
−