Saving the Day with Scoped CSS

Avatar of Arley McBlain
Arley McBlain on (Updated on )

Today’s post is by Arley McBlain (@ArleyM), a front end developer in Burlington Ontario at Thrillworks.

Over the last couple years HTML5 and CSS3 have rocked our worlds and the way we approach common website issues. Every few days it seems there is some new fangled snippet or approach that is a game changer. Today might just be another one of those days (kind of).

One little known feature of HTML5 is Scoped CSS. It’s an attribute for style blocks that may change the way we tackle certain styling challenges in the future.

Update: As best I can tell, <style scoped> has been removed from the specs and even browsers that were supporting it have pulled it. Even as I write this update (August 2017) scoped styles are arguably more popular and desirable than ever before. Vue files support the concept just like described here, and there are many other libraries popping up that support the concept. Native browsers are probably thinking of Shadow DOM as the likely replacement for this idea.

The implementation for scoping is simple. Let’s look at some code on an otherwise unstyled page where all text is the default black:

<div>
  <style scoped>
    h1 { color: FireBrick;   }
    p  { color: SaddleBrown; }
  </style>
  <h1>This is an H1 in a scoped div. Regardless of global styles the text should be "FireBrick".</h1>
  <p>This is a paragraph in a scoped div. The text should be "SaddleBrown".</p>
</div>

<p>This is another paragraph, that will unaffected by the scoped style and remain black.</p>

The style block with the scoped attribute will overwrite the global styles generally found in the head (whether in a style block or linked stylesheet), but only on the sibling/descendent elements inside the same parent. In this example, everything inside the wrapping div is going to get some new heading and paragraph coloring. As w3.org puts it “If the scoped attribute is present, then the user agent must apply the specified style information only to the style element’s parent element (if any), and that element’s child nodes.”

This is amazing! While all other text on the page may be black, within this div we can style freely without worrying about changing the styles of similar elements anywhere else on our site. This can be a very powerful tool.

Why is this cool?

“But Arley,” you say, using a conjunction to begin a sentence, “Why not just use a class or ID on that div and style like #foo h1 and #foo p? Isn’t this just organized inline styles?” There are a number of occasions I can think of when scoped CSS is a decent option under certain circumstances:

  • It may be desirable to keep the CSS of a particular interactive element together with the HTML. If the element in question is unique on the site (like a complex slider for example), there is no advantage to caching it with global styles.
  • Keeping the CSS with the HTML for organization may have value however.
  • When working with a team it can be a great way to allow for simultaneous development of various areas of the site without worrying about the state of the global CSS – I can see this as a short term solution.
  • If your article is getting aggregated by another site it’s possible to customize styles on another website that would otherwise be beyond the reach of your global stylesheet.
  • If you enable tags in the comment section of your site you can give your readers the ability to style their… nevermind this is probably a terrible idea.
  • For use in widgets on third-party sites where the CSS is unknown and the in-widget styles shouldn’t affect anywhere else. Although being able to reset the styles within the widget is the other half of that battle.
  • Finally (and most exciting to me), Scoped CSS is ideal for working within Content Management Systems where you have much less flexibility for adding unique markup to common templated areas, or no access to the existing stylesheets.

I would like to talk about the CMS advantages in more detail.

Working with a CMS

When we build a site in a CMS we are building constraints to ensure reusability of elements and templates, as well as maintaining consistency across the site. CMS are the perfect tool to let someone way less nerdy than you create and manage content without fear of breaking any site components. One limitation of a CMS can be the inability to do one-off tweaks for unique areas.

I had this problem working in an enterprise level CMS. Based on original comps and scope of the site we built the CMS to have a consistent uniform look and feel. A need for more flexibility rose a few months after launch: the addition of a second more verbose language, and special campaigns were introducing new challenges for styling.

My first challenge was to make a larger block of text (fun fact: the rule of thumb for designers when designing for bilingual in Canada is to allow for an extra 50% space when the design will need to be in French!). I looked at my pages, and I looked at my stylesheets: even any tiny change I made would mean hours of testing and QA across the entire site to ensure that no other areas were broken as a result. The ramifications were astronomical! Having no time for this I invented the poor-man’s Scoped CSS, or “code block” as it became known. Code Block was technically just wrapping divs with IDs around content, and then having an adjacent style block to make the necessary changes (while this sounds simple, it was a bit outside-the-box for this CMS work). Since this CSS would only apply to this page it made no sense to have these styles bloating up the global styles. It was perfect. The style block would not affect any other area of the site. Bilingual and campaign content became easy to develop and test.

Thankfully Scoped CSS will be even cleaner and easier to implement than my McGyvered solution. There will be no need for special IDs, and in fact the ability to have really simple selectors like “p” will keep your CSS looking very clean.

Getting Practical

Have you ever wanted to make one specific post in your stream stand out in some way? Even if your CMS doesn’t allow for coding in the editor, you may still have options thanks to Scoped CSS.

WordPress is an example of a CMS that will limit what code you can enter into the content area. Out of the box WordPress strips a lot of markup out of the wysiwyg editor, and this is actually a very very good thing, as it will clean up any stray code a n00b user may accidentally introduce. Giving users access to enter code into a CMS is to give them access to destroy the site! One too many closing div tags will mean a completely borked layout!

With a little work up front you can create a “Code Block” custom field that will allow you to inject scoped CSS directly into that post. If you really want to get fancy you could employ functionality from a plugin like Custom Field Template to make it easy for even the least savvy user to take advantage of this by making style choices with a simple form!

In the WordPress demo below I have created a Twenty Eleven Child Theme (meaning I’m completely relying on the default WordPress template, except for the three pages I’ve made small adjustments too). The changes I’ve made are few and simple (I should probably also mention that at the time of writing there is one other tiny problem to consider, but I’ll save that until later). To get Scoped CSS working I simply add a little bit of logic to content.php and content-single.php to look for the custom field “scopedcss” and then to pop that into a style block. I simply put this code within the <article> block of the relevant content loops:

<?php 
  $scopedcss = get_post_meta($post->ID, 'scopedcss', false); 

  foreach($scopedcss as $css) {
    echo '<style scoped>'.$css.'</style>';
  } 
?>

Then in my WordPress post I simply added the custom field “scopedcss” and wrote whatever styles I wanted for this post.

Easy cheezy. If you don’t see Custom Fields on your post editor screen, click the Screen Options tab at the top of the screen and make sure the checkbox for them is checked.

Note: if you are interested in this art direction on a per-post basis idea, but aren’t ready for scoped styles check out this plugin which gives you the meta box for declaring styles, but they won’t be scoped you’ll need to be as specific as regular CSS.

A word of warning

My own experience with my poor-man’s version of this wasn’t all sunshine and daisies; there is one major weakness to this approach and to scoped CSS: organization gets very hard – you end up with styles everywhere! Scoped CSS has the ability to save the day, but if it’s at all possible you should use ID selectors and linked stylesheets.

This is one of the major reasons we should avoid inline styles, they’re messy, they add to page weight something that maybe should be cached, they’re a pain to overwrite, they can complicate troubleshooting, and most importantly they’re hard to maintain. Like inline styles, Scoped styles do have their place and can be a powerful tool. Use them wisely.

An even bigger warning

Using scoped styles without a proper polyfill is dangerous. In a browser that doesn’t support them, the styles you declare will affect the entire page. Imagine you use a scoped style to use an image replacement technique on the h1 title inside an article on your site. Your logo is also an h1, and thus the logo is also replaced in unsupporting browsers. The result is a reverse-cascading style disaster.

Just be warned. Scoped styles are a very useful idea but the days of use using them without a polyfill are very far off.

A jQuery solution

Due to the lack of native browser support, this would be one disappointing demo today if it were not for this great jQuery Polyfill made by Simon Madine. To get my demo working in WordPress I also:

  1. Enqueued jQuery into my WordPress theme.
  2. Added the following code to the footer of the theme (footer.php in the theme folder).
<script src="<?php bloginfo( 'stylesheet_directory' ); ?>/jquery.scoped.js"></script>
<script>
  $.scoped();
</script>
It works!

Wanna play?

Chrome 20 is the only browser at the time of this writing that is supporting scoped styles. Chrome 20 is currently in Canary, which is a pre-beta release that you can run side-by-side with stable Chrome with no problems. To use it, you’ll need to enable a flag, which you do by:

  1. Go to the URL chrome://flags/
  2. Search page for “scoped”
  3. Click “Enable”
There’s a bunch of other fun stuff in here too.

Chrome moves quickly, so in around 12 weeks from the time of this writing (Mid-July 2012) Chrome 20 should be stable. Whether the feature will be shipped enabled is another matter (we just don’t know yet).

Demos

One day soon Scoped CSS will do all of the amazing things you’re seeing in these demos natively in the browser without extra JavaScript. Until then you can dream, read about it on the w3.org here, and check these demos:

Scoped styles, while delivering the functionality above, also will prove very powerful in Web Components, a proposal at the W3C for defining reusable widgets in next generation web apps. Exciting stuff.