The intent behind the CSS Navigation spec is worth paying attention to. The idea is to apply styles when someone navigates from one specific page to another, making the sources for cross-document view transitions declarative in CSS rather than managing that in JavaScript.
Bramus has a hypothetical example as this feature is fleshed out:
- Define the
@location, i.e., the URLs involved in the transition. Bramus uses@routebut that appears to have changed since their post. - Query the
@navigationbetween routes. - Select the thing that’s transitioned on each route.
So:
/* Define the locations */
@location --contact-page {
pathname: ("/contact");
}
@location --contact-confirmation {
pathname: ("/contact/thanks");
}
That’s for when we know the exact pages we’re navigating from and to. There’s URL pattern matching as well for the times we don’t:
@location --article {
pattern: url-pattern("/article/:id");
}
/*
Where :id matches anything two levels deep like:
/article/25
/article/3785
/article/whatever
*/
There are additional ways to define the @location besides the pathname and url-pattern descriptors. You might want to match a hash-ed URL, a specific port, or a hostname. The spec also includes protocol and search descriptors, though their individual use cases become clearer with concrete examples.
Once locations are defined, you can query the @navigation between them using the custom idents registered in @location. If the navigation matches the two points, the rule applies:
/* Fire a transition when navigating between these two pages */
@navigation (from: --contact) and (to: --contact-confirmation) {
/* Apply transition */
}
A slightly cleaner alternative syntax uses between:
/* Fire a transition when navigating between these two pages */
@navigation (between: --contact and --contact-confirmation) {
/* Apply transition */
}
And there’s a not keyword to fire the rule when there is no match:
/* Fire a transition, but NOT when navigating between these two pages */
@navigation not (between: --contact and --contact-confirmation) {
/* Apply transition */
}
There’s also an at keyword to connect locations. The spec draft is vague on this at the moment, but Bramus demonstrates it like this:
@navigation (between: --home and --detail) {
@navigation (at: --home) {
/* Target the clicked link's image */
:nav-source img {
view-transition-name: image;
}
}
}
Reading that: “when you’re navigating between --home and --detail and you’re starting ‘at’ --home, select this element and give it this view transition name.” In other words, it applies at the very beginning (or end) of the navigation between pages rather than while it’s in progress.
As for the :nav-source pseudo (which may be renamed to :navigation-source) — if the interpretation is right, that matches the specific element that triggers the transition: the source of the navigation, whether it’s a link, image, div, or any other element. There doesn’t appear to be a corresponding pseudo for the element on the destination side of the transition, though there may not be a clear use case for one.
The spec also defines a pseudo called :link-to() that applies styles to a linked element targeting a certain location. Straight from the spec:
@location --homepage {
pattern: url-pattern("/");
}
:link-to(--homepage) {
font-weight: bold;
}
…which would match an element like:
<a href="/">Back to Home</a>
This is similar to styling links based on their targeted destination, though it may be more of a developer experience convenience when a location is already declared.
A couple of notes
One immediate limitation: these features would likely not work well for sites with flat URL structures where most URLs are a single level deep. If you want to match between a specific page (/about) and any article (/article-url), there’s no way to distinguish that route without more URL structure — which isn’t a trivial change. One possible workaround is appending a parameter like ?blog to URLs to gain URL pattern matching capabilities.
There’s also a potential use case where you’d want to apply styles to the destination page based on where the user is coming from. For example:
@navigation (between: --home and --article) {
@navigation (at: --article) {
/* Target the .article-header element */
.article-header {
background-image: url('/path-to-image.webp');
}
}
}
Though that raises possible security concerns worth considering.
There’s also a broader design observation worth noting: with so many new at-rules to learn — @color-profile, @position-try, @location, and others — anything that lowers the learning curve is worth considering, such as a unified at-rule for data infrastructure similar to how @property handles property-value pairs.
There’s a lot more to this
The spec draft goes deeper into areas like navigating based on navigation “type” (e.g., back, forward, reload) and navigation “phases” (e.g., loading, ready, committed). It’s a lot to absorb, but so are view transitions as a whole — and this proposal, if it matures, could meaningfully simplify how developers manage them across documents.