How Web Components will change CSS best practices

Philip Walton / @philwalton

Disclaimer

I don't really know.  Nobody knows. 

Web Components haven't been around long enough to really get a feel for what works and what doesn't.

But we can learn from history and do our best to avoid repeating the mistakes of the past.

What has history taught us?

As it turns out, CSS is harder than it looks.

Why is CSS so hard?

It's not because:

CSS isn't hard because of the tricks and the hacks, or because it doesn't support X or Y.

There are two hard problems in CSS:

Hard problem #1

Getting your rules to match the elements you want without them accidentally matching the elements you don't.

Why is this hard?

All CSS rules are global

It’s hard to write predictable code when any rule you write could potentially conflict with another rule you didn’t know existed.

And, for whatever reason, most people who write CSS like to live dangerously!


        #main #content div div div {
          float: left;
          width: 50%;
        }
      

Hard problem #2

Accomplishing the first part without writing too much code.

Why is this hard?

Implementation details cannot be easily abstracted away


          
        

Are all these classes needed? What do they do?
If I remove one of them will everything break? Wtf is going on? #FML

Current best practices and methodologies:

BEM, SMACSS, OOCSS

All of these attempt to solve CSS's two hard problems:

My CSS history, in brief

How I wrote CSS in 2007:


            #sidebar ul li ul li a { }
          

            
          

How I write CSS today:


            .Sidebar-link { }
          

            
          

How will I write CSS in the future?


          /* CSS not found… */
        

          
            
          
        

Web Components
to the Rescue

Web Components actually solve
both of CSS's hard problems

New Specs

New Elements

A hello world element:

The main document:


            Newman
          
Newman

The element's shadow DOM:


            
            

Hello, ****

The rendered (composed) tree:


        
          ~~~~
          ~~

~~ ~~Hello, ~~ Newman ~~~~ ~~

~~

Let's see the code.


        // Create an object that will be the new element's prototype.
        var HelloWorld = Object.create(HTMLElement.prototype);

        // Add a callback to run whenever a new  tag is created.
        HelloWorld.createdCallback = function() {
          this.createShadowRoot().innerHTML =
            '' +
            '

Hello,

'; } // Register the element. document.registerElement('hello-world', { prototype: HelloWorld });
Callbacks reference  →

The Media Object

How it's done today (using BEM):


        
**
**

**
**

Notice how div.Media-body serves no semantic purpose.

How it could be done.

The main DOM:


            
              

Shadow DOM:


            
            
****
****

The composed tree


        
          ~~<style>…</style>~~
          ~~
~~ ~~
~~ ~~
~~

~~
~~
Media object demo  →

Extending elements

What if I don't like how the media object looks.
How can I make it better?

The Author Card

The <author-card> imports the <media-object> and composes it within its own shadow DOM.


        <link href="/path/to/media-object.html" rel="import">

        
      
Author card demo  →

Abstract Layout Components

The <flex-line> element:


            
              
Flex line demo  →

The <flex-grid> element:


            
              
Flex grid demo  →

Keeping hacks in the shadows

Sometimes CSS doesn't do exactly what you want, so you have to resort to hacks.

With shadow DOM, you can keep these hacks out of sight, where they belong.

Flex grid broken  |  Flex grid fixed

Building layouts from composable parts.

<flex-line> and <flex-grid> are very presentational, so you might not want to have them appear in your main document source.

Luckily, you don't have to. You can use <flex-line> to compose other layouts.

The main document:


            <body is="holy-grail">
              
</body>
Holy grid demo  →

Composed tree:


            <body>
              ~~~~
                ~~
~~
~~
~~ ~~~~ ~~
~~
~~
~~ ~~
~~ ~~
~~ ~~
~~ ~~
~~ ~~
~~ ~~
~~
~~
~~ ~~
~~ </body>

FAQs (anticipated)

When can I use this stuff? Are any sites currently using it?

Check out polymer-project.org as well as chromestatus.com. Both are built entirely with Polymer.

I've also put together a simple toy site that I was using to validate some of these concepts. You can find it on Github.

What browsers support these technologies?

With the platform.js polyfill you can get most of these features in all modern browsers (IE 10+).

Some features (like full style encapsulation) cannot be polyfilled, and so native support is required (Chrome 36+ only at this point).

Is it possible to style content in the shadow DOM from outside?

Yes, the selectors ::shadow and /deep/ allow you to do this.

But in general you should never use these selectors on your own elements, only on third-party components that aren't sufficiently extensible.

To quote the open/closed principle:

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

When should I put content in the shadow DOM vs the light DOM?

In general, dynamic content should be in the light DOM so your components can be static, bundleable, and cacheable.

Is content in the shadow DOM accessible to screen readers and search engines?

Yes. Screen readers see the rendered tree in the same way that you see it (visually) when using your browser.

And search engines that can run JavaScript have access to all content, including shadow content.

Summary

Key points:

Questions?

Twitter
@philwalton
Website
philipwalton.com
Github
github.com/philipwalton