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