Illustration by

Axiomatic CSS and Lobotomized Owls

At CSS Day last June I introduced, with some trepidation, a peculiar three-character CSS selector. Called the “lobotomized owl selector” for its resemblance to an owl’s vacant stare, it proved to be the most popular section of my talk.

Article Continues Below

I couldn’t tell you whether the attendees were applauding the thinking behind the invention or were, instead, nervously laughing at my audacity for including such an odd and seemingly useless construct. Perhaps I was unwittingly speaking to a room full of paid-up owl sanctuary supporters. I don’t know.

The lobotomized owl selector looks like this:

* + *

Despite its irreverent name and precarious form, the lobotomized owl selector is no mere thought experiment for me. It is the result of ongoing experimentation into automating the layout of flow content. The owl selector is an “axiomatic” selector with a voracious purview. As such, many will be hesitant to use it, and it will terrify some that I include it in production code. I aim to demonstrate how the selector can reduce bloat, speed up development, and help automate the styling of arbitrary, dynamic content.

Styling by prescription#section1

Almost universally, professional web interface designers (engineers, whatever) have accustomed themselves to styling HTML elements prescriptively. We conceive of an interface object, then author styles for the object that are inscribed manually in the markup as “hooks.”

Despite only pertaining to presentation, not semantic interoperability, the class selector is what we reach for most often. While elements and most attributes are predetermined and standardized, classes are the placeholders that gift us with the freedom of authorship. Classes give us control.

.my-module {
	/* ... */
}

CSS frameworks are essentially libraries of non-standard class-based ciphers, intended for forming explicit relationships between styles and their elements. They are vaunted for their ability to help designers produce attractive interfaces quickly, and criticized for the inevitable accessibility shortcomings that result from leading with style (form) rather than content (function).


<a class="ui-button">press me</a>

Whether you use a framework or your own methodology, the prescriptive styling mode also prohibits non-technical content editors. It requires not just knowledge of presentational markup, but also access to that markup to encode the prescribed styles. WYSIWYG editors and tools like Markdown necessarily lack this complexity so that styling does not impede the editorial process.

Bloat#section2

Regardless of whether you can create and maintain presentational markup, the question of whether you should remains. Adding presentational ciphers to your previously terse markup necessarily engorges it, but what’s the tradeoff? Does this allow us to reduce bloat in the stylesheet?

By choosing to style entirely in terms of named elements, we make the mistake of asserting that HTML elements exist in a vacuum, not subject to inheritance or commonality. By treating the element as “this thing that needs to be styled,” we are liable to redundantly set some values for the element in hand that should have already been defined higher in the cascade. Adding new modules to a project invites bloat, which is a hard thing to keep in check.

.module-new {
	/* So... what’s actually new here? */
}

From pre-processors with their addition of variables to object-based CSS methodologies and their application of reusable class “objects,” we are grappling with sandbags to stem this tide of bloat. It is our industry’s obsession. However, few remedies actually eschew the prescriptive philosophy that invites bloat in the first place. Some interpretations of object-oriented CSS even insist on a flattened hierarchy of styles, citing specificity as a problem to be overcome—effectively reducing CSS to SS and denying one of its key features.

I am not writing to condemn these approaches and technologies outright, but there are other methods that just may be more effective for certain conditions. Hold onto your hats.

Selector performance#section3

I’m happy to concede that when some of you saw the two asterisks in * + * at the beginning of this article, you started shaking your head with vigorous disapproval. There is a precedent for that. The universal selector is indeed a powerful tool. But it can be good powerful, not just bad powerful. Before we get into that, though, I want to address the perceived performance issue.

All the studies I’ve read, including Steve Souders’ and Ben Frain’s, have concluded that the comparative performance of different CSS selector types is negligible. In fact, Frain concludes that “sweating over the selectors used in modern browsers is futile.” I’ve yet to read any compelling evidence to counter these findings.

According to Frain, it is, instead, the quantity of CSS selectors—the bloat—that may cause issues; he mentions unused declarations specifically. In other words, embracing class selectors for their “speed” is of little use when their proliferation is causing the real performance issue. Well, that and the giant JPEGs and un-subsetted web fonts.

Contrariwise, the * selector’s simultaneous control of multiple elements increases brevity, helping to reduce file size and improve performance.

The real trouble with the universal sector is that it alone doesn’t represent a very compelling axiom—nothing more intelligent than “style whatever,” anyway. The trick is in harnessing this basic selector and forming more complex expressions that are context-aware.

Dispensing with margins#section4

The trouble with confining styles to objects is that not everything should be considered a property of an object per se. Take margins: margins are something that exist between elements. Simply giving an element a top margin makes no sense, no matter how few or how many times you do it. It’s like applying glue to one side of an object before you’ve determined whether you actually want to stick it to something or what that something might be.

.module-new {
	margin-bottom: 3em; /* what, all the time? */
}

What we need is an expression (a selector) that matches elements only in need of margin. That is, only elements in a contextual relationship with other sibling elements. The adjacent sibling combinator does just this: using the form x + n, we can add a top margin to any n where x has come before it.

This would, as with standard prescriptive styling, become verbose very quickly if we were to create rules for each different element pairing within the interface. Hence, we adopt the aforementioned universal selector, creating our owl face. The axiom is as follows: “All elements in the flow of the document that proceed other elements must receive a top margin of one line.”

* + * {
	margin-top: 1.5em;
}

Completeness#section5

Assuming that your paragraphs’ font-size is 1 em and its line-height is 1.5, we just set a default margin of one line between all successive flow elements of all varieties occurring in any order. Neither we developers nor the folks building content for the project have to worry about any elements being forgotten and not adopting at least a standard margin when rendered one after the other. To achieve this the prescriptive way, we’d have to anticipate specific elements and give them individual margin values. Boring, verbose, and liable to be incomplete.

Instead of writing styles, we’ve created a style axiom: an overarching principle for the layout of flow content. It’s highly maintainable, too; if you change the line-height, just change this singular margin-top value to match.

Contextual awareness#section6

It’s better than that, though. By applying margin between elements only, we don’t generate any redundant margin (exposed glue) destined to combine with the padding of parent elements. Compare solution (a), which adds a top margin to all elements, with solution (b), which uses the owl selector.

Diagram showing elements with margins, with and without the owl selector.
The diagrams in the left column show margin in dark grey and padding in light gray.

Now consider how this behaves in regard to nesting. As illustrated, using the owl selector and just a margin-top value, no first or last element of a set will ever present redundant margin. Whenever you create a subset of these elements, by wrapping them in a nested parent, the same rules that apply to the superset will apply to the subset. No margin, regardless of nesting level, will ever meet padding. With a sort of algorithmic elegance, we protect against compound whitespace throughout our interface.

Diagram showing nested elements with margins using the owl selector.

This is eminently less verbose and more robust than approaching the problem unaxiomatically and removing the leftover glue after the fact, as Chris Coyier reluctantly proposed in “Spacing The Bottom of Modules”. It was this article, I should point out, that helped give me the idea for the lobotomized owl.

.module > *:last-child,
.module > *:last-child > *:last-child,
.module > *:last-child > *:last-child > *:last-child {
	margin: 0;
}

Note that this only works having defined a “module” context (a big ask of a content editor), and requires estimating possible nesting levels. Here, it supports up to three.

Exception-driven design#section7

So far, we’ve not named a single element. We’ve simply written a rule. Now we can take advantage of the owl selector’s low specificity and start judiciously building in exceptions, taking advantage of the cascade rather than condemning it as other methods do.

Book-like, justified paragraphs#section8

p {
	text-align: justify;
}

p + p {
margin-top: 0;
text-indent: 2em;
}

Note that only successive paragraphs are indented, which is conventional—another win for the adjacent sibling combinator.

Compact modules#section9

.compact * + * {
	margin-top: 0.75em;
}

You can employ a little class-based object orientation if you like, to create a reusable style for more compact modules. In this example, all elements that need margin receive a margin of only half a line.

Widgets with positioning#section10

.margins-off > * {
	margin-top: 0;
}

The owl selector is an expressive selector and will affect widgets like maps, where everything is positioned exactly. This is a simple off switch. Increasingly, widgets like these will occur as web components where our margin algorithm will not be inherited anyway. This is thanks to the style encapsulation feature of Shadow DOM.

The beauty of ems#section11

Although a few exceptions are inevitable, by harnessing the em unit in our margin value, margins already adjust automatically according to another property: font-size. In any instances that we adjust font-size, the margin will adapt to it: one-line spaces remain one-line spaces. This is especially helpful when setting an increased or reduced body font-size via a @media query.

When it comes to headings, there’s still more good fortune. Having set heading font sizes in your stylesheet in ems, appropriate margin (leading whitespace) for each heading has been set without you writing a single line of additional code.

Diagram showing automatically adjusted margins based on font-size.

Phrasing elements#section12

This style declaration is intended to be inherited. That is how it, and CSS in general, is designed to work. However, I appreciate that some will be uncomfortable with just how voracious this selector is, especially after they have become accustomed to avoiding inheritance wherever possible.

I have already covered the few exceptions you may wish to employ, but, if it helps further, remember that phrasing elements with a typical display value of inline will inherit the top margin but be unaffected in terms of layout. Inline elements only respect horizontal margin, which is as specified and standard behavior across all browsers.

Diagram showing inline elements with margin.

If you find yourself overriding the owl selector frequently, there may be deeper systemic issues with the design. The owl selector deals with flow content, and flow content should make up the majority of your content. I don’t advise depending heavily on positioned content in most interfaces because they break implicit flow relationships. Even grid systems, with their floated columns, should require no more than a simple .row > * selector applying margin-top: 0 to reset them.

Diagram showing floated columns with margins.

Conclusion#section13

I am a very poor mathematician, but I have a great fondness for Euclid’s postulates: a set of irreducible rules, or axioms, that form the basis for complex and beautiful geometries. Thanks to Euclid, I understand that even the most complex systems must depend on foundational rules, and CSS is no different. Although modularization of a complex interface is a necessary step in its maturation, any interface that does not follow basic governing tenets is going to lack clarity.

The owl selector allows you to control flow content, but it is also a way of relinquishing control. By styling elements according to context and circumstance, we accept that the structure of content is—and should be—mutable. Instead of prescribing the appearance of individual items, we build systems to anticipate them. Instead of prescribing the appearance of the interface as a whole, we let the content determine it. We give control back to the people who would make it.

When turning off CSS for a webpage altogether, you should notice two things. First, the page is unfalteringly flexible: the content fits the viewport regardless of its dimensions. Second—provided you have written standard, accessible markup—you should see that the content is already styled in a way that is, if not highly attractive, then reasonably traversable. The browser’s user agent styles take care of that, too.

Our endeavors to reclaim and enhance the innate device independence offered by user agents are ongoing. It’s time we worked on reinstating content independence as well.

About the Author

Heydon Pickering

Heydon Pickering is a designer and interface developer from Norwich in the UK. He is lead designer at Neontribe and the accessibility editor for Smashing Magazine, where his book Apps For All is also available.

71 Reader Comments

  1. @Steve Hurst

    Sorry to hear that 😛

    It’s probably not something you should add late in a project’s maturity. That’ll mess things up.

    It’s something you might consider as a starting point.

  2. Wow. This is so simple and elegant. It’s 3 characters (not counting spaces, of course), but seems like the kind of thing that can subtly affect one’s entire approach to writing and architecting CSS.

    I can see it being very useful for a simple vertical rhythm system.

    Off to see where it leads me…thanks!

  3. I’ve written a long and rambly reply to this article on my blog (way too long for a comment): “On class names, semantics and accessibility”

    To summarize that post: I think the “lobotomized owl” technique is pretty cool, and I’m all for clever stuff we can do with selectors. However, when it goes into a critique of “OOCSS”-ish patterns, you bring up an example where broken markup (an unfocusable link, missing an href) somehow is associated with naming conventions and the use of presentational classes.

    Personally, I currently think that the benefits of these types of class names outweigh the cons – as do many other people. I try to argue some of your points in my post. Where ever one might land in that particular discussion, arguments against need to do better than to drag accessibility into it. Good HTML structure and choosing a particular naming convention are not mutually exclusive.

  4. It’s not just the owls that need lobotomies.

    The notion that HTML is an instrument to implement design is one of the key things that people need to unlearn. IMHO.
    We need more articles like this one to illuminate this. @ThatEmil also has some good points 😉

    As for the lobotomized owl – I think cases where I would be able to get away with using it would be few and far between. But at work we have been using its more sane cousins (p + p, etc) for the last 3 or so years 🙂

  5. @Emil Björklund

    > “you bring up an example where broken markup (an unfocusable link, missing an href) somehow is associated with naming conventions and the use of presentational classes. ”

    Yes. Yes it is ‘somehow associated’ with naming conventions. Here is the conventional (broadly accepted and ratified) convention for marking up buttons:

  6. This is damned elegant, and one of the freshest things I’ve seen in CSS for a while. I’m curious—what are some of your other favorite uses for the * + * beyond top-margins?

  7. @Jeremy Carlson To be honest, the `top-margin` property is the only one I use. It’s a normalization rule, used to make all objects adhere to a basic vertical rhythm. There are many more handy uses for the adjacent sibling combinator, though. I often use something like

    `section + section { border-top: 0.25em; padding-top: 3em; margin-top:
    3em; }’

    to divide up sections of content without leaving a pesky trailing border / padding / margin. You can see sort of thing on the geekmentalhelp.com website I’ve been working on with Andrew Clarke. The border is only applied to successive `.submission` blocks, so when I merge a pull request with a new submission, everything stays neat.

  8. @Heydon: You missed the part where I said the following:

    …we can either add the href-attribute (with a useful value), or change the element into a

    You and me both agree that using something like a span element with a truckload of JavaScript attached to create a button-like things is bad practice. To say that anything that is made to look like a button should be a button element is taking that too far.

    Links are interactive elements. You click on them and something happens. It’s not unreasonable that from a design standpoint, it may be desirable to have them look button-y. Using a class name to gather that styling information in one place makes a lot of sense, and doesn’t prevent you from also applying a sensible default styling to button elements.

    Consider the example of a page where we want to highlight the action of creating a new item. The form for the new item is on a separate page. Should we be forbidden to style that link as a button? I certainly don’t think so.

    I get what you’re saying regarding the affordances of tech: if we focus too much on style and ignore accessibility until the last minute, we’re screwed, and there’s definitely plenty of examples of frameworks and plugins out there that do that.

    But you said it yourself: classes are where we as authors are free to bring our own naming schemes. Elements are standardized (and should be used correctly), classes are not. I don’t understand why you point me towards the HTML5 spec for that.

  9. @Emil I like your example of the link that looks like a button but takes you to another form page. Indeed, that should probably look like a button but be announced as a link in AT. Good point.

    But my grievance with classes emerges where they are vaunted as a UI construction tool, when they are really a UI decoration tool. I used the a:not(href) example because it exemplifies the misapprehension that putting the class of `.button` on the link _makes_ it a button; that our name of `.button` is semantic in any real sense.

    The framework “Semantic UI”, for instance, defines buttons as

    s adorned with the classes “ui” and “button”. The term “semantic” is invoked while a purely decorational, non-functional (to many) object is defined.

    Making a link look like a button is fine in certain circumstances, like the one you suggest, but one does this with deliberation: “This should be a link, but the appearance should suggest the action is somewhat button-like”.

    That’s not what my example is about. It’s more like “I heard buttons are form elements, but I’m not in a form so I’ll use a link. I won’t be needing that href. Should I check what effect removing the href has? Nah, it’s probably fine. All my users will see it’s a button so I’ll call it good.”

    You start your article / reply by saying “naming things is hard”. It’s my opinion that most of the important naming (the names of elements like

  10. This is a pretty neat discovery. I would love to see this approach adopted into popular front end frameworks.

    Combining the owl selector with a build process like UnCSS would make for a pretty lean stylesheet.

  11. GREAT article. I’d find it a better read though if you avoided the thesaurus words and just used words that are in our every day vocabulary though. Like “unaxiomatically” or “interoperability”. I think it’s a much better read when you use the same words you’d use when speaking. I had a writing teacher who said something that I’ll never forget, “read above your level and write below it.” That’s my 2 cents anyway.

  12. a very thoughtful piece, thanks for this.
    as CSS developers & designers, we need to understand specificity and strive to wield it masterfully, and you have provided the community with a great example of doing so with your lobotomized owl selector.
    to paraphrase from above, we must keep the ‘C’ in CSS.

  13. So refreshing to see people point out that different things about CSS can actually be used. It’s very disappointing to see so many people parrot mantras like, “Don’t ever use the universal selector,” or, “Just put classes all over your HTML and then use those as your styling hooks.” I have used the universal selector before in cases like this where I wanted/needed everything within a certain element to adopt a particular style rule.

  14. @Devin McGregor

    > Is this equivalent to *:not(:first-child)?

    Almost, because that would style `root` too. To get the same selection without relying on the universal selector, I think we could simply use:

    :not(:first-child):not(:root)

    But in “real life”, I’d recommend sandboxing this *where needed* rather than blindly styling every_single_element on a page. May be doing something like this:

    .in-between-margin-trick :not(:first-child) {
    margin-top: 1.5em;
    }

    or (for IE8 support)

    .in-between-margin-trick * + * {
    margin-top: 1.5em;
    }

    In my opinion, we should strive to style things **as little as possible**… Because the less things you style, the less styles you have to style against.

  15. Great article, I totally agree with this way of writing CSS, avoiding presentation classes as much as possible.

    Don’t give in to the madness of OOCSS-ish patterns, it’s just bloat!

  16. @Thierry Hi! This wouldn’t be one of my CSS articles without us having a discussion. Welcome.

    Today, you’re not making much sense to me, Thierry.

    First, you construct an equivalent to * + * (:not(:first-child):not(:root) – which has less support and is harder to write) then seem to suggest using this with a * + * fallback for IE8, all in the context of suggesting we should be writing _less_ CSS!

    > “In my opinion we should be striving to style things as little as possible.”

    Unnecessary fallbacks aside, you are saying that * + * should be confined to specific contexts because “the less things you style, the less styles you have to style against”. You omit one important factor: If the * + * does not apply margin to objects outside of these contexts, something _else_ will have to. You seem to foresee a problem with overriding styles applied with * + *, but your solution is itself an override.

    The point is, * + * styles more things _with_ less. That is what smart CSS selectors do because they increase the brevity and maintainability of the stylesheet and keep the appearance of the document uniform. The radical thing about * + * that you may be missing is that it works best not as something you introduce, but as a foundation.

  17. @Pat Brady
    I’m glad you enjoyed the article and I’m sorry to hear you struggled with some of the language. Believe it or not, this is how I talk and write, without referring to a Thesaurus.

    I find your teacher’s mantra a little odd. If everyone is writing below their reading level, a scarcity is produced of writing that is above the level of the average reader (?)

  18. This article could have easily been from 2007. There is nothing new, and it has been known for a long time that the way you write selectors doesn’t really affect speed, browser vendors made sure of that, and it’s obvious that the more selectors you have the longer the browser needs to parse and apply them. So I don’t really understand why the author had spent hours of his time writing something that has been written already countless times…

  19. I enjoyed this article. You thoroughly explained your reasoning and justified why it can be useful, and provided work arounds. It’s not something you see a lot of anymore. I see a lot of articles that suggest something and barely explain why (A List Apart excluded).

    As for the technique, I will certainly see how it performs for me, and it is a shame this article did not come about a couple weeks ago, as I would have had the chance to play with it on a new project.

    I (as well as everyone I suppose) come across the whole ‘&:last-child { margin-bottom: 0; }’ fiasco regularly, and I have noticed recently that I am applying a lot more classes to my HTML to create more modularity, and ignoring the ‘C’ in CSS as you suggest. I think this is in part to the grid system way of thinking, that and I use them to describe an element.

    Sometimes I do wonder whether my CSS is better than it was just a few years ago…

  20. @Devin McGregor & Thierry:
    *+* and :not(:first-child) select the same, but there’s a big difference: specificity.
    The owl’s specificity is 000, whereas *:not(:first-child)’s specificity is 010. Because of this *:not(:first-child) cannot be overwritten by element type selectors.
    Rules like *+* {margin-top: 1.5em} set a default and should be easy to overwrite, i.e. must have low specificity. That’s why owl, not *:not(:first-child).

  21. This makes my life so much easier! Vertical rhythm is one of the most annoying parts of web design to consistently get right, and this solves the issue of compounding margins really elegantly. Love it!

  22. @Gunnar & Heydon:

    Heydon, you’re putting my “suggestion” out of context. I was answering Devin question, which was:

    > Is this equivalent to *:not(:first-child)?

    You also say:

    > Unnecessary fallbacks aside

    What fallback are you talking about? These are not 2 rules to use together. The “or” between the rules means one would pick the rule depending on the browsers she supports.

    Gunnar, I don’t think specificity plays much of a role here (unless you sandbox the rule as I suggested). If the styling needs to be overwritten, I’d expect people to use a class for that (0,0,1,0), and that would be enough to do the job. If overriding this style via a type selector is a possibility, then we may wonder why we are aiming at almost *all elements* on the page in the first place.

    Also, I won’t discuss performance because I know I cannot win that war here, but I’d like to mention that this is not just the universal selector. It is the universal selector, a combinator, and the universal selector again. Paul Irish said this:

    > [*] can be slow when you specifically use it like .foo > *, so don’t do that.

    Think about it…

    Now let’s try to remember the discussions we had when we were talking about resets, base style sheets, normalize, etc. We were trying to make sense of what to style and what not. The infamous * {margin:0;padding:0;} rule didn’t come back to life after people started saying there was no performance hit using such rule. And I think there is a reason for that.

    Heydon says:

    > The radical thing about * + * that you may be missing is that it works best not as something you introduce, but as a foundation.

    If we kept the reset I just suggested, that foundation would become:

    * {
    margin: 0;
    padding: 0;
    }

    * + * {
    margin-top: 1.5em;
    }

    And that’s called overwriting too. CSS is about overwriting stuff. You say applying a specific margin to almost all elements leads to less overwrites, I say it’ll lead to the opposite.

    Let’s give this some time. After all, we have seen people complaining that the “universal” reset was creating issues with some form controls, then we’ve seen people complaining about the too broad styling of box-sizing (Jonathan Neal then introduced “inherit”)…

  23. @Thierry

    Hello again.

    > “What fallback are you talking about? These are not 2 rules to use together. The “or” between the rules means one would pick the rule depending on the browsers she supports. ”

    There is no “or”. Why would you _ever_ choose a longer selector with demonstrably lower browser support when the two in contention do precisely the same thing? Madness.

    > “If the styling needs to be overwritten, I’d expect people to use a class for that (0,0,1,0), and that would be enough to do the job.”

    By people you mean developers. I’m talking about creating style schemae that accomodate content contributors. The low specificity _is_ important because it makes writing element-based (WYSIWYG / markdown produced) selectors as overrides easier.

    > “Paul Irish said this: > [*] can be slow when you specifically use it like .foo > *, so don’t do that.”

    Much as I respect his work, I don’t care what Paul Irish said. Show me bench tests. Show me evidence that the purported difference has any impact on users. I just siege tested a site which uses the lobotomized owl selector. Guess what? A big ASCII skull and crossbones did not appear in the command line with the rubric “selector performance death” 😛

  24. @Heydon,

    In this article, you use Steve Souders and Ben Frain names as a mean to brush away the performance issue but then you dismiss Paul Irish’s finding – even though what he reports is closer to the selector you’re using than what Steve and Ben discuss.

    And asking for *bench tests* confirms that you have no data to backup your claim. It’s unfortunate that the reviewer(s) of this article didn’t suggest you to provide some data. I think that would not be necessary if there was some sort of consensus but as I pointed out, this is not the case here.

    > I’m talking about creating style schemae that accomodate content contributors.

    Then you should be *clear* about that so devs don’t think this is some kind of magic rule they should plug in every project.

    Anyway, I won’t debate further here. I’d be better writing an article about this as at least I’d be able to **format** things the way I want 😉

  25. @Thierry

    It is not my or anyone else’s job to prove the nonexistance of something. That is a logical impossibility. I only point to Souders’ and Frain’s studies to underline the _lack_ of evidence for the stated issue – that the difference between selectors’ performance ACTUALLY MATTERS. It is one thing to say the difference can be measured and quite another to prove a detrimental effect caused by that difference.

    > “And asking for *bench tests* confirms that you have no data to backup your claim.”

    I am not making a claim, I am pointing to the lack of evidence for a claim. It is the job of the person that _claims_ something exists (in this case a significant performance issue with certain selector types) to prove it. That is how the “burden of proof” works: “the necessity of proof always lies with the person who lays charges.”

    It is your claim; prove it is worth considering.

    +1 on the formatting.

  26. I too think your language is to complicated. Considering the type of article, I believe that you should avoid using unnecessary words to not distract the readers and focus mostly on getting the message out.

  27. First: ‘I love the idea!’. But to place this in context, I never use margin-top. Simply because the whole idea is that an element is positioned in a flexible way on the page, in most cases by the elements above. The same idea goes for p-tags or header elements.

    So why not place margin-bottom on every * and reset the margin on last elements?
    * {
    margin-bottom: 10px;
    }

    *:last-child{
    margin-bottom: 0;
    }

    So this is not by a level of depth and it is more clear to understand, no illustrations needed?

    That being said, my use cases for the ‘+’ selector are very limited, and if you can prove me wrong, please do!

  28. @Spillebeen Mathieu

    > First: ‘I love the idea!’

    Who said that? Was it someone famous?

    > So why not place margin-bottom on every * and reset the margin on last elements

    Because then you’d be doing two things instead of just one.

    > That being said, my use cases for the ‘+’ selector are very limited, and if you can prove me wrong, please do!

    Please enumerate your use cases. Without this information it would be difficult to prove anything.

  29. For content-specific elements (such as p+p), ems would be preferable since you are dealing with font-size changes.

    For structure level elements however, I would suggest using either a rem unit or multiplier of that so that space between containers will be uniform.

    Therefore, it would be preferable to first define *+* in rems then cascading typographic content such as p+p as ems. This guarantees that spacing between elements will be uniform and that content will not appear crowded.

  30. @Thierry

    > If the styling needs to be overwritten, I’d expect people to use a class for that (0,0,1,0)

    Just no. I don’t. I concider styling solely on classes (propagated by approaches like OOCSS) as the most erroneous trend in frontend development in the last decade.

    Sticking to the marging-top example, one might reduce margin between adjacent headings:
    h1+h2, h2+h3, h3+h4, h4+h5, h5+h6 { margin-top: 0.5em }

    No need for polluting the markup with classes.

    Above rule would not overwrite :not(:first-child), but it overwrites *+*, as desired. Specificity is an issue here.

  31. been using the direct-neighbor selector for some case, but so far, i’ve been holding myself from using it as a global selector because:
    – form controls (label + input, label + label, button + button, …)
    – (inline)grids (.column + .column)
    – inline-block elements that happen to be neighbors in text (for example some “tags”)

    but as a general rule, i’m using
    li + li, p + p, .row + .row, … quite often

    PS

    nice article 🙂

  32. I recently ran a test using something like this `.parent > * + *` I thought that the performance seemed expensive compared to `.parent > .item` Since CSS selectors are evaluated from right to left using * + * at the end would require everything on the page to be considered twice?

    I would suggest measuring the performance of a selector like `* + *` to see if you are happy with the speed of the selector.

    So here is an example test Testing a CSS selector: lobotomized owl selector

    You can compare using this lobotomized owl selector (Universal adjacent sibling combinator selector) vs. a descendant class selector test-lobotomized-owl-selector-speed.html and test-descendant-class-selector.html

    There isn’t much if any of a performance difference. At least its in the tens of milliseconds range.

  33. Thoughtful article. A nitpick about the axiom definition. Wouldn’t it actually be defined as “All elements in the flow of the document that succeed other elements must receive a top margin of one line.” This might just be a disconnect in British and American English.

  34. This is awesome. With working to change my CSS style from form-centric to function-centric, this will be a great addition! Great article and some really good comments. Thanks for sharing this bold idea.

  35. Nice approach, I’ll try this on my next project, instead of the good ol’ :last-child technique.

    My main experience and concern about OOCSS practices is that it can be easily misused. If the CSS is not carefully planned and your team doesn’t follow specifications strictly, it can become a bad substitute for inline styles. And although we can give this practices sweet names like micro-styling, it could be called style-as-you-go.

    In one of my last projects I delivered a stylesheet with something like:

    .mb-xs { margin-bottom: 6px; }
    .mb-s { margin-bottom: 12px; }
    .mb-m { margin-bottom: 18px; }
    .mb-l { margin-bottom: 36px; }
    .mb-xl { margin-bottom: 48px; }
    

    One of the worst mistakes I’ve ever done in my life. It was immediately adapted as some kind of inline styling technique.

  36. This article was, as always, a wonderfully-refreshing journey and ‘eye-opener’ for me.
    I wonder about 1 thing though: What happens when we introduce HTML5’s document outlining algorithm using sections, such as:

    Flow content…

    Not the page title; just a ‘flow’ heading

    After trying it out with the lobotomised owl (poor thing) with margin-top as you’ve described, it seems that the h1 loses its needed larger spacing between it and the paragraph, and instead the second section now has a smaller margin-top of it’s own.
    I do wonder why I’d put the sectioning elements there in the first place if I’m not going to style them (and thus give them visible boundries), but that’s motivated for in the HTML5 Sectioning spec.

  37. Thank you for the article, It was a real eye opener as to the stupid simple things that you can do with css. I have actually implemented this on a site that I’m currently working on and for the most part it has worked out pretty well.

    I did run into a big issue with the * + * selector and all its glory. Some unwanted spacing happens when you use <style></code>, <link></code>, [removed], <meta></code>. These selectors are very common when working on a large site in a framework and when adding micro data to your code. To see the issue you can see them in this pen

    I have solved this unwanted issue by making an addendum to the * + * selector. The following works for every browser that supports the :not() selector, which is every browser except IE8 and below. Check out the updated lobotomized owl selector

    /* Updated version of the lobotomized owl selector */
    *:not(style):not(link):not(meta):not(script) ~ * {
      margin-top: 1em;
    }
    /* adds a larger gap between sections to create the correct break visual break */
    *:not(style):not(link):not(meta):not(script) ~ section {
      margin-top: 3em;
    }
    

    If you have to support IE8 and below, I feel really really sorry for you. Fortunatlly for you the code below will work correctly 95% of the time.

    style + *, link + *, meta + *, script + * {
      margin-top: 0;
    }
    * ~ style ~ *, * ~ link ~ *, * ~ meta ~ *, * ~ script ~ * {
      margin-top: 1em;
    }
    * ~ * {
      margin-top: 1em;
    }

    The only case where it adds unwanted space is when you have something like below.

    <div> <style></style> <meta> <div></div> </div>

    However this will work just fine.

    <div>
     <div></div>
     <style></style>
     <meta>
     <div></div>
    </div>
    
  38. Semantic UI is a library based around bringing useful linguistic concepts (plurality, different between modifiers and types, tense etc) to web development. Semantics does not refer to the misappropriation of the word to mean “Adherence to W3C web specification” but instead to its linguistic origins in creating systems of meaning, like Montague grammar. This argument about prescriptivist / descriptivist dilemma is well traveled territory in the field of linguistics, but still novel for the field of contrived languages, like programming languages. Generally anyone who create a formal system of language is bound to some level of prescription, but can avoid the overwhelming negative aspects of that ‘original sin’ by creating standards by consensus and convention. This is the same issue that Merriam Webster once struggled with or the Académie française.

    With regards to the owl selector, Semantic uses it adjacent sibling selectors (owl) quite frequently for spacing within components.

    They are generally very useful, but its worth a word of caution that they will not always apply correctly to arbitrary content. Any component that leads with an element that is not display: block or position: static will disrupt the vertical spacing of the component.

    With regards to CSS specificity: I don’t believe the idea of inheritance is broken, but the means of calculating specificity certainly is. Until there is a way to manually specify a ‘specificity index’ (like a z-index), we will be bound by the arbitrary tedium of automatic specificity calculations which don’t always do what we want (or expect) it to do.

  39. Love this technique.

    Be aware that there is a small issue in Firefox (35) with <br> elements. Even though they’re flow elements Firefox will put margin between them when repeated, ie. <br><br>. Easily fixed by adding br { margin-top: 0; }.

    Pretty sure this is a bug as I wouldn’t expect <br> elements to have margins, and other browsers do not have this behaviour.

  40. Other than the fact that anything laid out horizontally gets murdered by this technique, it’s pretty sweet. Seems to be a good foundation for anything that’ll go into an article body:

    article * + * { … }

  41. Hey,

    Interesting article. Just trying this out in a project which has Eric Meyer’s reset styles at the top. It seems, that due to the owls low selector specificity that the reset’s styles are being applied rather than the owl. Is there a way to keep using the reset and then the owl?

    Thanks.

  42. That’s so awesome! How is it possible that I didn’t come across this technique before!
    It’s a long time ago that I’ve been this excited about a piece of CSS.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA