Comments on Axiomatic CSS and Lobotomized Owls

71 Reader Comments

Back to the Article
  1. The lobotomized owl selector just completely blew up every style sheet I’m currently working on. Brilliant.

    Copy & paste the code below to embed this comment.
  2. This just changed my life. It’s THE solution I didn’t know I was looking for. You have permanently changed the way I approach CSS. Brilliant.

    Copy & paste the code below to embed this comment.
  3. 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!

    Copy & paste the code below to embed this comment.
  4. 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.

    Copy & paste the code below to embed this comment.
  5. Makes a lot of sense. Anything to keep CSS simple…

    Copy & paste the code below to embed this comment.
  6. 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 :)

    Copy & paste the code below to embed this comment.
  7. There is recursiveness in * + *.

    Copy & paste the code below to embed this comment.
  8. 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?

    Copy & paste the code below to embed this comment.
  9. @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 <button> element to fix the accessibility issue. (Depending on the rest of the page structure, either could be correct.)

    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.

    Copy & paste the code below to embed this comment.
  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.

    Copy & paste the code below to embed this comment.
  11. Great thread and comment dialog. Thanks for the post.

    Copy & paste the code below to embed this comment.
  12. Is this equivalent to *:not(:first-child)?

    Copy & paste the code below to embed this comment.
  13. nice!

    Copy & paste the code below to embed this comment.
  14. 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.

    Copy & paste the code below to embed this comment.
  15. 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.

    Copy & paste the code below to embed this comment.
  16. 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.

    Copy & paste the code below to embed this comment.
  17. @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.

    Copy & paste the code below to embed this comment.
  18. 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!

    Copy & paste the code below to embed this comment.
  19. Interesting article and interesting comments. I love the creativity of this CSS, something which is often missing when writing!

    Copy & paste the code below to embed this comment.
  20. 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…

    Copy & paste the code below to embed this comment.
  21. 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…

    Copy & paste the code below to embed this comment.
  22. @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).

    Copy & paste the code below to embed this comment.
  23. These types of techniques remind me of when I first read bullet proof web design back in 2005. Thanks for the article!

    Copy & paste the code below to embed this comment.
  24. 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!

    Copy & paste the code below to embed this comment.
  25. @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”)...

    Copy & paste the code below to embed this comment.
  26. @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 ;)

     

    Copy & paste the code below to embed this comment.
  27. Talk is cheap. Show me the code.

    Copy & paste the code below to embed this comment.
  28. You, sir, just blew my mind.

    * + * is indeed the ultimate selector for vertical rhythm – and, most importantly, it is beautiful to see on the screen.

    Copy & paste the code below to embed this comment.
  29. Ever since your talk at CSS Day, I read your posts in your accent…
    Nice work!

    Copy & paste the code below to embed this comment.
  30. 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.

    Copy & paste the code below to embed this comment.
  31. 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!

    Copy & paste the code below to embed this comment.
  32. @Spillebeen Mathieu

    Readability, maintainability: http://codepen.io/anon/pen/gboyJ

    Why reset if you do not need to?

    Copy & paste the code below to embed this comment.
  33. 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.

    Copy & paste the code below to embed this comment.
  34. @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.

    Copy & paste the code below to embed this comment.
  35. 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 :-)

    Copy & paste the code below to embed this comment.
  36. 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.

    Copy & paste the code below to embed this comment.
  37. Brilliant. Love the illustration, the wise words, and the wonderfully named lobotomized owl selector.

    Copy & paste the code below to embed this comment.
  38. Thoughtful article. A nitpick about the axiom definition. Wouldn’t it actually be defined as “All elements in the flow of the document that <em>succeed<em> other elements must receive a top margin of one line.” This might just be a disconnect in British and American English.

    Copy & paste the code below to embed this comment.
  39. 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.

    Copy & paste the code below to embed this comment.
  40. DONT. LOBOTOMIZE. OWLS.

    Copy & paste the code below to embed this comment.
  41. 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.

    Copy & paste the code below to embed this comment.
  42. I was there during CSS Day and it was because of: “the thinking behind the invention”.

    Just saying.

    Copy & paste the code below to embed this comment.
  43. hi

    Copy & paste the code below to embed this comment.
  44. This blew my mind! Goes to show that less is always more.

    Copy & paste the code below to embed this comment.
  45. found myself writing this today (in SCSS, obviously):
    > * + * {
    voilà - the Niki Lauda owl, with two different ears

    Copy & paste the code below to embed this comment.
  46. What the heck am I misunderstanding? I tried a fiddle (http://jsfiddle.net/skube/ddzsp9ax/) and expected the `two` block to have the top margin, but it doesn’t.

    Edit: n/m I think it’s a specificity issue but then I would argue your figure (http://alistapart.com/article/axiomatic-css-and-lobotomized-owls#figure5 ) is slightly inaccurate and should show `.row * + *` instead of simply `* + *`

    Copy & paste the code below to embed this comment.
  47. nice post on Axiomatic CSS. thanks

    Copy & paste the code below to embed this comment.
  48. 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:

    <section>
    Flow content…
    </section>
    <section>
    <h1>Not the page title; just a ‘flow’ heading</h1>
    </section>

    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.

    Copy & paste the code below to embed this comment.
  49. 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>, <code><link></code>, <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 <code>* + * 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>
    <div>
     <style></style>
     <meta>
     <div></div>
    </div>
    </div>

    However this will work just fine.

    <div>
     <div></div>
     <style></style>
     <meta>
     <div></div>
    </div>
    
    Copy & paste the code below to embed this comment.
  50. After using this, it seems a few “reset” selectors are necessary.

    * + br,
    option + option,
    th + th,
    th + td,
    td + th,
    td + td {
      margin-top: 0;
    }
    Copy & paste the code below to embed this comment.
  51. CSS is things which offer world class web page designing according to your choice. if you use CSS is prefer Div base design. Thank you, great information.

    Copy & paste the code below to embed this comment.
  52. 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.

    Copy & paste the code below to embed this comment.
  53. @Semantic UI: Yeah, I think you failed basic semantics by doing this:

    <div class="ui button">
      Follow
    </div>
    Copy & paste the code below to embed this comment.
  54. 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.

    Copy & paste the code below to embed this comment.
  55. Do we clear out other margins before the lobotomized owl?

    * { margin: 0; }

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

    Copy & paste the code below to embed this comment.
  56. 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 * + * { ... }

    Copy & paste the code below to embed this comment.
  57. Wow man. Wow.

    Copy & paste the code below to embed this comment.
  58. 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.

    Copy & paste the code below to embed this comment.
  59. good article for learning web design , by chance I was looking for knowledge on this , so this really helped me ,, thank you. Harga Sepeda Pacifik

    Copy & paste the code below to embed this comment.
  60. 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.

    Copy & paste the code below to embed this comment.