What is the current state of the "scoped" attribute for the style element in HTML5?

It states here http://www.w3.org/TR/html-markup/style.html#style:

Permitted parent elements

any element that can contain metadata elements, div, noscript, section, article, aside

that <style> is more or less allowed every where (where <div> is allowed) but, on the other hand, I found a more detailed information here http://www.w3.org/TR/2012/WD-html5-20121025/the-style-element.html#attr-style-scoped

Contexts in which this element can be used: (annotation: style)

If the scoped attribute is absent: where metadata content is expected.
If the scoped attribute is absent: in a noscript element that is a child of a head element.
If the scoped attribute is present: where flow content is expected, but before any other flow content other than inter-element whitespace, and not as the child of an element whose content model is transparent.

and later in this document:

The scoped attribute is a boolean attribute. If present, it indicates that the styles are intended just for the subtree rooted at the style element's parent element, as opposed to the whole Document.

If the scoped attribute is present and the element has a parent element, then the style element must be the first node of flow content in its parent element other than inter-element whitespace, and the parent element's content model must not have a transparent component.

This reads like there are (or will be) "two different <style> elements": a

  • <style> - global - ~~only within <head>
  • <"scopestyle"> - only(!) with bool scope attr and ~~only at start of <div>

(pls. read "~~" like "more or less")

But the later link is more than 2 years old, and all Browsers (I tested Chrome, FF, IE, Opera) interpret the inflow <style> as if it was in header. (and ignore AFAIK the scope - yes - still no standard)

So my 3-part question

  1. Is my interpretation of the W3C documents (the 2 styles - logic) correct?

  2. What is the state now - 2015?

  3. And, is there probably someone out there, who knows whats on the horizon coming?


Many of the answers here have become somewhat obsolete, so here goes a brief summary of what happened with the scoped attribute.

Originally (before HTML5), <style> was not "valid" outside <head>, but was supported by most or all browsers. "not valid" means that validators would complain about it, and the specs (W3C's HTML 4 and XHTML 1 series) said it shouldn't be done. But it worked. And sometimes this was bad: no matter where the <style> element appeared in the document, its rules would apply to the entire document (based on the selectors used, of course). This could lead to authors writing a "local" stylesheet meant to apply only within an area of the document but could accidentaly restyle other areas.

HTML5's scoped attribute proposal was meant to address this: it would tell the browser that the styles in that sheet would only apply to the <style>'s parent element and its descendants. Also, at some point <style scoped> was also required to be the first child of its parent, making it very clear for anyone reading the HTML code what the scope was. The style element without the attribute remained valid only within the <head> element.

Time went by and not enough vendors implemented the new feature (Firefox and Chrome included some experimental support), so it was eventually dropped. The browser behaviour remains as it was before HTML 5, but the current spec at least documents it: <style> is now legal/valid throughout the document, but the spec warns about the potential side effects (restyling elements accidentally).

With current spec and browser behaviour, the best and safest way to implement ''scoped'' styles is to do so explicitly with the help of ID's, as in this snippet:

<div id="myDiv">
  <style>
    #myDiv p { margin: 1em 0; }
    #myDiv em { color: #900; }
    #myDiv whatever { /* ... */ }
  </style>
  <p>Some content here... </p>
</div>

The div has an id attribute, and all the rules in the stylesheet explicitly use an id selector to ensure they only apply within that div. Of course, this still requires to avoid id clashes across the document, but uniqueness is already a requirement of the id attribute.

Although the scoped attribute was dropped, this approach gets the job done, is reasonably readable (of course, like any code, it could be obfuscated, but that's not the point), should validate, and should work on pretty much every CSS-compatible browser.

PS: As per the spec, <style> within <body> should validate. However, the Nu validator (tagged as experimental) still complains about it. There is an open issue regarding this: https://github.com/validator/validator/issues/489


UPDATE. The scoped attribute no longer works in any browser and is now non-standard and deprecated.


Your interpretation of the specification appears correct. The MDN page on the style tag includes a description of the scoped attribute.

scoped If this attribute is present, then the style applies only to its parent element. If absent, the style applies to the whole document.


The scoped attribute:

Here is a working example of this that will work in Firefox 21 through 54 only.

Example:

<div>
  <p>Out of scope.</p>
  <div>
    <style scoped>
      p {
        background: green;
      }
    </style>
    <p>In scope (green background).</p>
  </div>
  <p>Out of scope.</p>
</div>

In browser that do not support the scoped attribute, these styles are applied globally.


The :scope pseudo-selector:

In addition to the scoped attribute, there is also the :scope pseudo-selector which can be used. This implementation offers the same support as the previous.

Example:

<div>
  <p>Outside scope.</p>
  <div>
    <style scoped>
      :scope p {
        background: green;
      }
    </style>
    <p>In scope (green background).</p>
  </div>
  <p>Outside scope.</p>
</div>

This option also adds the possible advantage that if the browser does not understand the scoped attribute, the styles will not be applied globally. The only problem is that Safari 7+ will recognize the :scope pseudo-selector, even though the scoped attribute is not supported, so the advantage is lost in Safari 7+.


Global Styles:

As before, using a style tag without the scoped attribute will create global styles, so it will only be scoped if you include the scoped attribute.


Compatibility Summary:

At this point, support for the feature looks bleak (UPDATE 2022: the proposal for this feature was completely dropped from standards). CSS scoping was supported only in Firefox 21 through 54. It is not currently supported in any major browser, Firefox, Chrome, Internet Explorer, Safari, or Opera. According to caniuse.com, from Chrome 20 to 36 it was possible to enable support with the experimental flag, but support was removed.


It appears the "scoped" attribute has been completely dropped from the HTML5 specification. The current and previous few versions all have no mention of it.


As of May 2016, <style scoped> has been dropped from whatwg specification.


Update from 2020

In current VueJs single file components, there is a style section with a "scoped" attribute that dynamically transforms the CSS classes at "compile" time so that they are limited to the scope of only that component.

How to correctly use "scoped" styles in VueJS single file components?

Personally, I like this approach as centralized CSS tends to get stale and brittle. New developers often just add new classes to a project as they don't want to break existing designs. Cleaning up old CSS never seems to be on anybody's to do list...