fronx.github.io    //   also @fronx, @fronxer

A not so common way to think about CSS

10 Sep 2013

Here is how lots of people I've talked to conceptualize the relationship between CSS and HTML: you use HTML to structure information in a hierarchical way, and you attach styles to sets of elements, sort of from the outside.

 CSS    -----------> HTML
(styles)  "attach"  (document)

That's a valid way of looking at it, but it's not the only one. Also valid is the opposite:

 CSS    <---------- HTML
(styles)   <verb>  (document)

In this view, it's the document that does something to the styles. If you find it hard to see it that way, read on. If it's already totally clear to you, this is your chance to go and read something else.

Caution: this article assumes that you have some programming knowledge.

In more concrete terms

What is the verb in the above diagram? There are multiple names that fit: "use", "call", and "invoke" all work fine. Here is a rough sketch of what that relationship means: The document serves as the input to a list of structural patterns, and it can invoke the style declarations associated with a particular pattern by having a matching structure:

 CSS    <---------- HTML
(pattern)  invoke  (structure)

Here is a silly example:

CSS

.date { color: #aaa; }
.comment .date { font-size: 10px; }

HTML

<div class="comment">
  <div class="whatever">
    <span class="date">2013-09-10</span>
  </div>
</div>

(Note that this example is not a recommendation for how to write good CSS code or markup.)

And here is how the example translates into patterns and the structure of document fragments:

Patterns:

.date
.comment .date

Structure of document fragments (incomplete list):

span
div
.comment
.date
div div
div div span
div span
.whatever span
.comment .date
…

You can imagine the document as being the user of the style sheet who tries to get the parameters right in order to match the interfaces (or patterns) the style sheet exposes. It is analogous to a programmer who wants to use an API and looks up function signatures to find out what the expected arguments are.

Now what's that view useful for?

Learn from analogous models

If the document encodes something analogous to function calls, then things we know about function calls may also be valid for the document/style-sheet relationship.

When designing function signatures, common questions to ask are:

With the proposed model, you can design a style sheet as if it were a programming interface and ask very similar questions:

A similar design principle you can apply to style sheets is the Law of Demeter or "principle of least knowledge". (It is not really a law by any commonly used definition of "law", but that's what it's called anyway.) Let's look at a few (possibly terrible) selectors and see how much they know about more or less related document fragments:

a) #post-123
b) ul.comments li ul li
c) .foo .bar
d) .foo.bar
e) .tweet > .avatar
f) .post hr

Selector a knows about only one value. It's the equivalent of writing a function that only accepts one value:

def seven_times_two(x)
  if x == 7
    14
  else
    nil
  end
end

That's sort of a silly thing to do, but it doesn't violate the Law of Demeter.

Selector b aims to affect some set of list items, but in order to get at them, it takes quite a detour and mentions all kinds of landmarks along the way. Here is some analogous pseudo-code to illustrate that kind of interface:

def styles_for_special_list_item(li)
  if li.parent(:ul).parent(:li).parent(:ul, :class => :comments)
    {:color => 'black'}
  else
    nil
  end
end

That's clearly an example of a selector/function that violates the principle of least knowledge.

I'll leave the other examples as an exercise for the reader.

Okay, got it. What's next?

After this short tour through overlapping mental models, go and check out some of the suggestions people have made for how to write good CSS code and try to see how they make sense or how you could explain them in different terms if you think of a style sheet as a programming interface:

Also, go back to some code you're working with and answer the interface design questions above.

That's it for now. I am @fronx on Twitter.