[css-regions][css-variables] CSS Nested Decorators Dream


Dear CSSWG Members,

Today, I would like to talk to the dreamer that lives in you. This week, I had a vision and writing down this vision is probably the only way I can clear my mind...

My vision started with a blog post, so I would encourage you to read it: 
http://blogs.adobe.com/webplatform/2013/04/03/defining-presentational-boxes-with-shadow-dom/ 

To sum up, the idea is that you can use the Shadow DOM and Regions to layout the content of document in pretty creative ways without transforming the document structure into a mess. 

The best way to characterize this idea is probably to make a comparison with the CSS Zen Garden contest where you had to propose a new design for whose structure was defined in HTML. Adobe’s proposal would be quite the same, except that this time you get a book or a magazine article to format, and not one of those very tree-structured documents that CSS handle so well.

My first reaction to the article has been very positive, but I immediately noticed it would be very difficult to use this technique intensively in practice, because it lacks a composition method. 

Let’s take the blog post’s sample as a starting point... Now, what if I want the #region2 element to be a multi-column element? Do I have to expose the #region2 element as a pseudo-element to the non-shadow CSS? Wouldn’t that break the decorator principle? What if I want the #region2 element to use himself the max-80vh-and-then-image decorator? 

Ultimately, I believe it’s the templates themselves that should be responsible of interpreting the author’s defined properties, and not just expose the key elements by default to all parent contexts.

Certainly, you can share information between the decorated object and its templates using CSS Custom Properties, but the information you can share is very limited because the shared value should be directly usable by CSS: it’s an atomic value and there’s no way to treat the information in CSS. 

As soon as you want to nest multiple decorators and you don’t want them to “know” about each other, there isn’t any option left to you.

My proposal would be to allow to treat the CSS Custom Property values in a non-atomic way, and use natural nesting as a way to give information to the nested decorators. For now, I’ll focus on object-like decomposition.

Because I think an example is worth thousands of words, I’m going to start with that:

// css facility for var-template
* { decorator: get(var-template.decorator || none); }

// styling of the article
article {
      var-template: {
            decorator: url('/templates/#paged-article');
            first-page: { 
                  decorator: url('/templates/#article-first-page');
                  image-height: 25vh;
            };
            page: {
                  url('/templates/#article-page');
                  display-quotes: true;
                  display-images: true;
            };
      };
}

// inside the paged-article template
.page:first-of-type { 
      var-template: get(
            parent var-template.first-page 
            || get(parent var-template.page || {})
      );
}

.page { 
      var-template: get(parent var-template.page || {});
}

// inside first-page template
img { max-height: get(parent var-template.image-height); }

// inside article-page template
.txt-quote { flow-into: current-quote replace contents; }
.img-quote { flow-into: current-image replace contents; }

// to show the images and the quotes, we need to make 
// the assumption there'll be something to show and
// we need to use a viewport (because it's a replaced 
// element) if we don't want to break layout.
viewport.txt-quote-container { 
    position: float; content: flow-from(current-quote); 
    width: ...; height: ...; ... 
}

// html document
<article>
      <header>
            <h1>Some article</h1>
            <p class=intro>The first paragraph is very important.</p>
            <img src="xyz.jpg" />
      </header>
      <main>
            <h2>First header</h2>
            <div class=txt-quote>
                  <p>I'm an important quote.</p>
            </div>
            <p>I'm the first paragraph...</p>
            <p>I'm the second paragraph...</p>
            <p>I'm the third paragraph...</p>
            
            <h2>Second header</h2>
            <div class=img-quote>
                  <figure>
                        <img src="break.jpg">
                        <figcaption>...</figcaption>
                  </figure>
            </div>
            <p>I'm the first paragraph...</p>
            <p>I'm the second paragraph...</p>
            <p>I'm the third paragraph...</p>
            
            <h2>Third header</h2>
            <div class=txt-quote>
                  <p>I'm an important quote.</p>
            </div>
            <p>I'm the first paragraph...</p>
            <p>I'm the second paragraph...</p>
            <p>I'm the third paragraph...</p>
            <p>I'm the first paragraph...</p>
            <p>I'm the second paragraph...</p>
            <p>I'm the third paragraph...</p>
      </main>
</article>



More concretely, my proposal is to allow to treat object-like values in custom property values in an object-like way. In details, get(var-foo.bar) returns the value of the bar property of the object defined by the value of the var-foo property, if the var-foo property has a valid value and that value is a valid object representation; if it’s not or if the representation doesn’t have any bar property, the property reference is invalid.

The second thing I’m using is pretty standard and has been used in the past by Daniel Glazman (and proposed in another form by Tab Atkins) and is the element’s context definition in the property reference (ie: get(parent var-template) and get(attr(for url) var-xyz) instead parent-var(template).

Naturally, I’ve some other things in mind, but I think a lot can already be achieved by combining those two things. Ultimately, I’m still envisioning a full data-manipulation subset for CSS like get(var-display-images ? block : none) and get(var-grid-pos * 1px || 0px) but I guess this is another story.

Well, this is all I have for now; let me know if you have thoughts ;-)
François

 

 

PS: Sorry Tab, I’m still using the unofficial syntax Brian & I developed for Custom Properties even though it’s not the main subject of the mail. I know I shouldn’t, but it seems like I just can’t accept the var() syntax for now, and I don’t think I’ll anytime soon but I promise I try really hard.

Received on Monday, 15 April 2013 23:19:14 UTC