Scoped style sheets

Scoped style sheets are a feature from HTML 5 (or the HTML Standard, if you prefer) that allows the effect of a style sheet to be limited to a subtree of the document. By placing a scoped attribute on a <style> element, the style sheet applies only to elements within the subtree rooted by the parent of the <style> element.

For example, consider this document:

<!DOCTYPE html>
<title>Scoped style example</title>
<body>
  <style>
    p { font-style: italic; }
  </style>
  <p>The first paragraph.</p>
  <p>
    <style scoped>
      p { color: crimson; }
    </style>
    The second paragraph.
  </p>
</body>

It would be rendered as follows:

The first paragraph.

The second paragraph.

Rules in the style sheet only match an element if all of the elements matched by a selector are within the style scope. Thus, if the rule were instead body > p { color: crimson; }, it would not match that second paragraph.

The CSS Cascading and Inheritance Level 3 specification defines that when there are nested style scopes, rules on inner scopes override those from outer scopes, regardless of the specificity of the rules. Using !important reverses this, and allows outer scopes to win over inner scopes. Global style sheets, including <style> elements without a scoped="" attribute or those loaded using a <link> element, are treated as if they are scoped to the root element.

One use case for scoped style sheets is to isolate a set of style rules that apply to a single article or comment within a page to ensure that they cannot affect the style of other elements on the page. On a web site that aggregates articles from different authors, this could allow the designer of the overall site to know that the elements of the page outside the article itself will not be affected by the article’s styles.

Another is to be able to specify style for a given element’s pseudo-element, or only when it matches a pseudo-class, which is not possible just by using the style="" on the element or without giving the element an ID and defining the style in a global style sheet. For example if you have an element styled like this:

<p>
  ...
  <span style="text-decoration: underline;">looks like a link</span>
  ...
</p>

and you decide you want the underline to be applied only when the element is hovered, then it’s not possible to use the :hover pseudo-class within the style="" attribute. A scoped style sheet can be used:

<p>
  ...
  <span>
    <style scoped>:hover { text-decoration: underline; }</style>
    looks like a link
  </span>
  ...
</p>

Implementation

Firefox 21, currently on the Nightly channel, supports scoped style sheets now that bug 508725 has landed. This feature is not prefixed or behind a pref. The scoped="" attribute can be placed on SVG <style> elements, too.

There are two aspects of the Firefox implementation that don’t match the specification yet:

  1. The @global at-rule, to allow all elements during selector matching except for the subject to be outside the style scope, is not implemented. The name “global” doesn’t quite convey the meaning it has, and given there are no other at-rules that can be used as a prefix to a list of selectors, some other syntax might be better. (Filed as bug 830058.)
  2. Other at-rules that have global effects, including @font-face and @keyframes, are not processed at all within scoped style sheets. The HTML specification states that these should have effects limited to the style scope. (Filed as bug 830056.)

[Edited 16 January 2013 – fixed the typo pointed out by Pablo]