CSS Route Matching

Unofficial Proposal Draft,

More details about this document
This version:
https://wicg.github.io/declarative-partial-updates/css-route-matching/
Issue Tracking:
GitHub
Inline In Spec
w3c/csswg-drafts#12594
Editors:
L. David Baron (Google)
Noam Rosenthal (Google)

Abstract

This module contains conditional CSS rules for styling based on routes declared in HTML. This allows styles to be conditioned on the current URL or conditioned on the status of navigating between particular URLs.

Status of this document

1. Route queries: the @route rule

The @route rule is a conditional group rule whose condition tests characteristics of the current URL or of the state of navigation between two URLs. These queries are called route queries.

Authors can use it to:

The syntax of the condition in the @route rule is similar to that defined for <supports-condition> in [CSS-CONDITIONAL-3]. Negation, conjunction, and disjunction are all needed so that authors can specify the interaction of multiple styles in ways that are most intuitive and require the simplest code.

The syntax of the @route rule is:

@route <route-condition> {
  <rule-list>
}

with <route-condition> defined as:

<route-condition> = not <route-in-parens>
                     | <route-in-parens> [ and <route-in-parens> ]*
                     | <route-in-parens> [ or <route-in-parens> ]*
<route-in-parens> = ( <route-condition> ) | ( <route-test> ) | <general-enclosed>
<route-test> = <route-location> | <route-keyword> : <route-location>
<route-keyword> = at | from | to
<route-location> = <route-name> | <urlpattern()>
<route-name> = <custom-ident>

The above grammar is purposely very loose for forwards-compatibility reasons, since the <general-enclosed> production allows for substantial future extensibility. Any @route rule that does not parse according to the grammar above (that is, a rule that does not match this loose grammar which includes the <general-enclosed> production) is invalid. Style sheets must not use such a rule and processors must ignore such a rule (including all of its contents).

A <route-name> is a reference to a route named in a <script type=routemap> in the document. This should be defined more formally once routemaps are.

Many of these grammar terms are associated with a boolean result, as follows:

<route-condition>
not <route-in-parens>

The result is the negation of the <route-in-parens> term.

<route-in-parens> [ and <route-in-parens> ]*

The result is true if all of the <route-in-parens> child terms are true, and false otherwise.

<route-in-parens> [ or <route-in-parens> ]*

The result is false if all of the <route-in-parens> child terms are false, and true otherwise.

<route-in-parens>

The result is the result of the child subexpression.

<route-test>
<route-location>
at: <route-location>

The result is true if the document’s URL matches the route location URL pattern of <route-location>.

from: <route-location>

The result is true if the document’s navigation API of the document is non-null, and either:

to: <route-location>

The result is true if the document’s navigation API of the document is non-null, and either:

The above definitions of from and to apparently don’t work right if you start a same-document navigation (e.g., with pushState) in the middle of a cross-document navigation.

Improve integration with has been revealed rather than monkeypatching it.

<general-enclosed>

The result is false.

Authors must not use <general-enclosed> in their stylesheets. It exists only for future-compatibility, so that new syntax additions do not invalidate too much of a <route-condition> in older user agents.

The route location URL pattern of a <route-location> depends on the type of <route-location>:

<route-name>

the URL pattern of a route named <route-name> declared in a <script type=routemap>.

Once routemaps are defined more formally, this should be defined in terms of the routemap definition instead of referring directly to URLPattern.

<urlpattern()>

The URL pattern represented by the function; see create a URL pattern for urlpattern().

A document’s navigation API is the result of the following steps on document:

  1. Let window be the Window whose associated Document is document, or null if there is no such Window.

  2. If window is null, return null.

  3. Return window’s navigation API.

The condition of the @route rule is the result of the <route-condition> in its prelude.

2. The urlpattern() function

The urlpattern() function represents a URL pattern, which can be used to match URLs.

<urlpattern()> = urlpattern( <string> )

This function represents a URL pattern that can be created using the steps of the create a URL pattern for urlpattern() algorithm:

  1. Let arg be the <string> argument to the urlpattern() function.

  2. Let baseURL be the style resource base URL of the rule or declaration block containing the urlpattern() function.

    Do we really want this to be the base URL? For this particular use of urlpattern(), it’s likely more useful for the base URL to be the document URL rather than the style sheet URL. However, it would be very awkward for urlpattern() to be inconsistent with url(). Should we introduce document-urlpattern()? Should we do something similar to CSS Images 3 § 2.1.1 Ambiguous Reference-or-Image URLs (see w3c/csswg-drafts issue #383)?
  3. Return the result of create a URL pattern given arg, baseURL, and an empty map.

NOTE: This function requires that its argument is quoted. This differs from the url() function, which allows its argument to be quoted or unquoted.

3. The route() function for @when

This specification defines an additional function for the @when rule:

route() = route( <route-condition> )

The route() function is associated with the boolean result that its contained condition is associated with.

4. The route() function for if()

This specification defines an additional function for the if() function’s <if-test> production:

route() = route( <route-condition> )

This should probably have a more formal definition of the function, but I can’t find the formal definitions of the existing if() functions to model it after.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-CONDITIONAL-3]
Chris Lilley; David Baron; Elika Etemad. CSS Conditional Rules Module Level 3. URL: https://drafts.csswg.org/css-conditional-3/
[CSS-CONDITIONAL-5]
Chris Lilley; et al. CSS Conditional Rules Module Level 5. URL: https://drafts.csswg.org/css-conditional-5/
[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 3. URL: https://drafts.csswg.org/css-images-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. URL: https://drafts.csswg.org/css-syntax/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. URL: https://drafts.csswg.org/css-values-4/
[CSS-VALUES-5]
Tab Atkins Jr.; Elika Etemad; Miriam Suzanne. CSS Values and Units Module Level 5. URL: https://drafts.csswg.org/css-values-5/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[MEDIAQUERIES-5]
Dean Jackson; et al. Media Queries Level 5. URL: https://drafts.csswg.org/mediaqueries-5/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URLPATTERN]
Ben Kelly; Jeremy Roman; 宍戸俊哉 (Shunya Shishido). URL Pattern Standard. Living Standard. URL: https://urlpattern.spec.whatwg.org/

Issues Index

This should be defined more formally once routemaps are.
This assumes that the ongoing navigate event and the transition have the same lifetime, but this isn’t really true if the event is intercepted. After whatwg/html#11690 / whatwg/html#11692. we could probably define this more like "from" above. But which lifetime is the one we want?
The above definitions of from and to apparently don’t work right if you start a same-document navigation (e.g., with pushState) in the middle of a cross-document navigation.
Improve integration with has been revealed rather than monkeypatching it.
Once routemaps are defined more formally, this should be defined in terms of the routemap definition instead of referring directly to URLPattern.
Do we really want this to be the base URL? For this particular use of urlpattern(), it’s likely more useful for the base URL to be the document URL rather than the style sheet URL. However, it would be very awkward for urlpattern() to be inconsistent with url(). Should we introduce document-urlpattern()? Should we do something similar to CSS Images 3 § 2.1.1 Ambiguous Reference-or-Image URLs (see w3c/csswg-drafts issue #383)?
This should probably have a more formal definition of the function, but I can’t find the formal definitions of the existing if() functions to model it after.