Web Platform Team Blog

Adobe

decor

Making the web awesome

Defining Presentational Boxes with Shadow DOM

A while back I wrote about Generating Boxes in CSS where I suggested extending pseudo-element syntax in CSS to create presentational boxes. I proposed a new mechanism for adding an arbitrary number of ::before and ::after pseudo-elements to extend what we have now. This was intended as a first step towards more box generation in CSS – for wrapper elements, grouping, etc.

The main idea has been to separate content from its presentation. Say you want to vertically center an element. Flexible box layout gives you a very simple way to do this, but you need a wrapper around the element to turn on display:flex. That wrapper isn’t really part of the content, so it would be great not to have to litter your code with <div class="flex-wrapper"></div> elements. If there were a ::wrapper pseudo-element, you could keep the presentational code away from your content markup.

But what if you wanted to wrap two or more sibling elements in the same wrapper? Then you’d have to define how pseudo-elements could either wrap each sibling individually or group them together. You quickly get to the point of re-creating HTML structure in CSS syntax, and CSS was never meant to represent structure. I’ve now come to think that presentational boxes may be better defined in HTML Templates that are part of the Shadow DOM proposal. No new pseudo-elements are required, and you can still keep the presentational boxes out of your content markup.

As a result of this change of thinking, I have reworked all of the examples in CSS Regions to use Custom Elements and HTML Templates to define the boxes used to create CSS Regions.  The elements used to create region boxes can move from content markup to an HTML Template. Your content markup remains clean, and you have all the structural facilities of HTML to arrange your region boxes. This is all building on the ideas first expressed by Razvan Caliman in a blog post last year.

Here’s a simple example. In the content markup below, there is an article with an image element and a few paragraphs. If either Custom Elements or CSS Regions are not available, the image is displayed between the first and second paragraph. But if both features are available, then the top of the image will be placed four-fifths of the way down the viewport height. The article text will flow above and below the image, filling the space above the image with whatever text fits instead of breaking at a particular paragraph boundary.


<element name="two-regions" extends="body">
  <template>
    <style>
    article > p {
      flow-into: article-flow;
    }
    #region-1, #region-2 {
      flow-from: article-flow;
    }
    #region-1 {
      max-height: 80vh;
    }
    </style>
    <div id="region-1"></div>
    <content></content>
    <div id="region-2"></div>
  </template>
</element>

<body is="two-regions">
  <article>
    <p>...
    <img>
    <p>...
    <p>...
  </article>
</body>

The above (aside from some shadow boundary tweaks) is equivalent to the below. Either version works to flow content through two regions, but the HTML template version lets you separate the presentational markup from your content markup.


<style>
  article > p {
    flow-into: article-flow;
  }
  #region-1, #region-2 {
    flow-from: article-flow;
  }
  #region-1 {
    max-height: 80vh;
  }
</style>

<body>
  <div id="region-1"></div>
  <article>
    <p>...
    <img>
    <p>...
    <p>...
  </article>
  <div id="region-2"></div>
</body>

The difference between the example above laid out with or without CSS Regions is a bit subtle. Here’s a picture of what it might look like without CSS Regions in two different screen sizes. The image doesn’t appear in the smaller screen until you scroll:

layout above and below image in different screens with no regions

But with the 80vh region, you ensure that at least part of the image is visible before scrolling on any screen. The font size can change or the window can be resized, but the image will stick in place and the text will flow around it.

layout above and below image in different screens using regions

The declarative use of Custom Elements here and in the specification examples is still a bit cutting-edge. Currently browsers require a bit of JavaScript to get it all going. I expect that by the time this all works natively in the browsers I will need to update my HTML Template examples. I’m following what’s currently defined in the excellent Shadow DOM Explainer by the eternal optimist Dimitri Glazkov. If you want to dig deeper there is series of posts on html5rocks called Shadow DOM 101, Shadow DOM 201: CSS and Styling and Shadow DOM 301: Advanced Concepts & DOM APIs that provide more detail.

3 Comments

  1. April 03, 2013 at 10:22 pm, Martin Hlaváč said:

    It’s great that you can actually hide presentation elements from normal dom. This allows developers to really present only needed DOM that is not cluttered with all these elements.

    It’s a shame that shadow dom is still working draft and we will have to wait a much longer to use it. Meanwhile… there are templating engines like one in AngularJS which allow us to create custom elements which are rerendered as in this example (http://angularjs.org/).

  2. April 04, 2013 at 1:40 pm, Eric Bidelman said:

    Great post! Combining Shadow DOM with Regions is an interesting idea and makes a lot of sense to me. I threw together a quick prototype that works in Chrome Canary: http://jsbin.com/uqocat/2

  3. April 04, 2013 at 3:41 pm, Steve Orvell said:

    Polyfills for Custom Elements, HTML Imports, and ShadowDOM are available at https://github.com/toolkitchen.