Mar 24, 2015

tl;dr

One thing I really enjoyed about Polymer was using attributes for layout (via flexbox). The Angular Material library provides a very similar approach.

Layout Attributes?

I’m obviously talking about html. Layout attributes provide an interesting way to give the html an extra job. Essentially we extract layout from our CSS, using classes for theme or skin, but letting the HTML itself describe the basic layout. The Angular Material library has already done the grunt work for this, I believe taking its cue from Polymer. The two libraries are subtly different in the layout attributes provided, but in the end they meet the same goals.

But… semantic HTML?!?!

I’m all for semantics html in the appropriate context. Back in the day when I was first getting into web development, CSS Zen Garden was the greatest site out there. It showcased a single html file with over a hundred different css files that completely changed the look and feel of the page. Having this kind of separation of html & is extremely valuable… if the product of your website is content (text) and you need to freshen up the skin every year or two.

Application Development Isn’t About Text

Application development is a whole different animal. The product is typically a service, not content. In this world, the html is throw away, markup that mainly serves the purpose of gluing functionality together. The JavaScript and CSS are the components that take the most time to develop. Finding ways to make the HTML meaningful, reducing JavaScript & CSS to maintain is a big win.

A Simple Layout

Simply getting a few divs to line up in a row has been historically far trickier than it should be. It can be accomplished with floats, inline-block styles, and other tricks, but flex based layout is finally making it simple to get html to do what we’ve always wanted it to do. Take this example, adding only the Angular Material CSS file:

<div layout="row">
    <div> left block </div>
    <div flex> center block </div>
    <div>right block </div>
</div>

It produces this (with some outlines added to the divs):

left block
center block
right block

Its not pretty yet, but with two simple attributes on our HTML we have the standard website layout with a center, left and right column. How does this work? Well, the layout="row" attribute on the outer div changes everything. Using flexbox, the css rule flex-direction: row; (vendor prefixes ignored) is applied. This sets up the main axis to be horizontal, causing the child divs to line up left to right.

The flex attribute added to the div in the center is pretty neat. It applies flex: 1 to this div, which basically just says “fill up the extra space”. No width set. Its a “blocky” kind of element, will not collapse but also will not expand to take up the whole area. It “knows” how to expand enough to swallow up all the extra pixels left over by it’s siblings (which take up only the space needed by their content).

But what about the spacing? In the old float days, adding padding or margin to a floated div would break the layout. The simplest way to do this was to nest divs or p tags within the parent layout, applying styles to these components. With flexbox, the math is taken care of for us. i’m going to add a class that will add an arbitrary 10px of padding to all of the divs:

<style>
.p10 {
    padding: 10px;
}
</style>

<div layout="row" class="p10">
    <div class="p10"> left block </div>
    <div flex class="p10"> center block </div>
    <div class="p10">right block </div>
</div>

Which produces:

left block
center block
right block

Whoa. No math. No need to figure out width + padding + margin (don’t forget to add padding and margin px twice since they are added to both sides) to ensure your floats don’t explode. Flexbox allows us to trust the browser to do the math. The padding is applied to the divs, and then the browser simply adjust everything to fit the given space. Even the padding on the parent is taken into account! This is so much less brittle.

Adding Our Own Attributes

So far, the attributes used are those provided by Angular Material. But it could be argued that the 10 pixel padding is really for layout purposes. Therefore, we can change .p10 { padding: 10px} to [p10] { padding: 10px} to make it a layout attribute as well. The markup would look like:

<style>
[p10] {
    padding: 10px;
}
</style>

<div layout="row" p10>
    <div p10> left block </div>
    <div flex p10> center block </div>
    <div p10>right block </div>
</div>

And the results:

left block
center block
right block

When we drop the class="p10" and replace it with the p10 attribute, the markup becomes much more readable, and our HTML is now clearly declaring the layout to us. This is very simple, and very powerful.

This post really only scratches the surface of flexbox and attributes. I’m sure many will still hate the idea of dirtying up HTML by marrying it to the layout, but in my app development experience, it is much more satisfying to tweak a few layout attirbutes to make subtle changes to components than it is to fuss with the cascade of CSS. CSS has its place, certainly, but I like the approach because it leaves the framing in the html and lets the CSS control the paint job.

This is a rather trivial example, but I’m going to try to keep my posts short to ensure I regularly post. Stay tuned for a part 2 in the future where I’ll attempt to something sufficiently complex to make this convincing.