Menu Search
Jump to the content X X
Smashing Conf San Francisco

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf San Francisco, dedicated to smart front-end techniques and design patterns.

CSS Inheritance, The Cascade And Global Scope: Your New Old Worst Best Friends

I’m big on modular design1. I’ve long been sold on dividing websites into components, not pages, and amalgamating those components dynamically into interfaces. Flexibility, efficiency and maintainability abound.

But I don’t want my design to look like it’s made out of unrelated things. I’m making an interface, not a surrealist photomontage.

Further Reading on SmashingMag: Link

As luck would have it, there is already a technology, called CSS, which is designed specifically to solve this problem. Using CSS, I can propagate styles that cross the borders of my HTML components, ensuring a consistent design with minimal effort. This is largely thanks to two key CSS features:

  • inheritance,
  • the cascade (the “C” in CSS).

Despite these features enabling a DRY5, efficient way to style web documents and despite them being the very reason CSS exists, they have fallen remarkably out of favor. From CSS methodologies such as BEM and Atomic CSS through to programmatically encapsulated CSS modules, many are doing their best to sidestep or otherwise suppress these features. This gives developers more control over their CSS, but only an autocratic sort of control based on frequent intervention.

I’m going to revisit inheritance, the cascade and scope here with respect to modular interface design. I aim to show you how to leverage these features so that your CSS code becomes more concise and self-regulating, and your interface more easily extensible.

Inheritance And font-family Link

Despite protestations by many, CSS does not only provide a global scope. If it did, everything would look exactly the same. Instead, CSS has a global scope and a local scope. Just as in JavaScript, the local scope has access to the parent and global scope. In CSS, this facilitates inheritance.

For instance, if I apply a font-family declaration to the root (read: global) html element, I can ensure that this rule applies to all ancestor elements within the document (with a few exceptions, to be addressed in the next section).

html { 
  font-family: sans-serif;
}

/* 
This rule is not needed ↷
p { 
  font-family: sans-serif;
}
*/

Just like in JavaScript, if I declare something within the local scope, it is not available to the global — or, indeed, any ancestral — scope, but it is available to the child scope (elements within p). In the next example, the line-height of 1.5 is not adopted by the html element. However, the a element inside the p does respect the line-height value.

html {
  font-family: sans-serif;
}

p {
  line-height: 1.5;
}

/* 
This rule is not needed ↷
p a {
  line-height: 1.5;
}
*/

The great thing about inheritance is that you can establish the basis for a consistent visual design with very little code. And these styles will even apply to HTML you have yet to write. Talk about future-proof!

The Alternative Link

There are other ways to apply common styles, of course. For example, I could create a .sans-serif class…

.sans-serif {
  font-family: sans-serif;
}

… and apply it to any element that I feel should have that style:

<p class="sans-serif">Lorem ipsum.</p>

This affords me some control: I can pick and choose exactly which elements take this style and which don’t.

Any opportunity for control is seductive, but there are clear issues. Not only do I have to manually apply the class to any element that should take it (which means knowing what the class is to begin with), but in this case I’ve effectively forgone the possibility of supporting dynamic content: Neither WYSIWYG editors nor Markdown parsers provide sans-serif classes to arbitrary p elements by default.

That class="sans-serif" is not such a distant relative of style="font-family: sans-serif" — except that the former means adding code to both the style sheet and the HTML. Using inheritance, we can do less of one and none of the other. Instead of writing out classes for each font style, we can just apply any we want to the html element in one declaration:

html {
  font-size: 125%;
  font-family: sans-serif;
  line-height: 1.5;
  color: #222;
}

The inherit Keyword Link

Some types of properties are not inherited by default, and some elements do not inherit some properties. But you can use [property name]: inherit to force inheritance in some cases.

For example, the input element doesn’t inherit any of the font properties in the previous example. Nor does textarea. In order to make sure all elements inherit these properties from the global scope, I can use the universal selector and the inherit keyword. This way, I get the most mileage from inheritance.

* {
  font-family: inherit;
  line-height: inherit;
  color: inherit;
}

html {
  font-size: 125%;
  font-family: sans-serif;
  line-height: 1.5;
  color: #222;
}

Note that I’ve omitted font-size. I don’t want font-size to be inherited directly because it would override user-agent styles for heading elements, the small element and others. This way, I save a line of code and can defer to user-agent styles if I should want.

Another property I would not want to inherit is font-style: I don’t want to unset the italicization of ems just to code it back in again. That would be wasted work and result in more code than I need.

Now, everything either inherits or is forced to inherit the font styles I want them to. We’ve gone a long way to propagating a consistent brand, project-wide, with just two declaration blocks. From this point onwards, no developer has to even think about font-family, line-height or color while constructing components, unless they are making exceptions. This is where the cascade comes in.

Exceptions-Based Styling Link

I’ll probably want my main heading to adopt the same font-family, color and possibly line-height. That’s taken care of using inheritance. But I’ll want its font-size to differ. Because the user agent already provides an enlarged font-size for h1 elements (and it will be relative to the 125% base font size I’ve set), it’s possible I don’t need to do anything here.

However, should I want to tweak the font size of any element, I can. I take advantage of the global scope and only tweak what I need to in the local scope.

* {
  font-family: inherit;
  line-height: inherit;
  color: inherit;
}

html {
  font-size: 125%;
  font-family: sans-serif;
  line-height: 1.5;
  color: #222;
}

h1 { 
  font-size: 3rem; 
}

If the styles of CSS elements were encapsulated by default, this would not be possible: I’d have to add all of the font styles to h1 explicitly. Alternatively, I could divide my styles up into separate classes and apply each to the h1 as a space-separated value:

<h1 class="Ff(sans) Fs(3) Lh(1point5) C(darkGrey)">Hello World</h1>

Either way, it’s more work and a styled h1 would be the only outcome. Using the cascade, I’ve styled most elements the way I want them, with h1 just as a special case, just in one regard. The cascade works as a filter, meaning styles are only ever stated where they add something new.

Element Styles Link

We’ve made a good start, but to really leverage the cascade, we should be styling as many common elements as possible. Why? Because our compound components will be made of individual HTML elements, and a screen-reader-accessible interface makes the most of semantic markup.

To put it another way, the style of “atoms” that make up your interface “molecules” (to use atomic design terminology6) should be largely addressable using element selectors. Element selectors are low in specificity7, so they won’t override any class-based styles you might incorporate later.

The first thing you should do is style all of the elements that you know you’re going to need:

a { … }
p { … }
h1, h2, h3 { … }
input, textarea { … }
/* etc */

The next part is crucial if you want a consistent interface without redundancy: Each time you come to creating a new component, if it introduces new elements, style those new elements with element selectors. Now is not the time to introduce restrictive, high-specificity selectors. Nor is there any need to compose a class. Semantic elements are what they are.

For example, if I’ve yet to style button elements (as in the previous example) and my new component incorporates a button element, this is my opportunity to style button elements for the entire interface.

button {
  padding: 0.75em;
  background: #008;
  color: #fff;
}

button:focus {
  outline: 0.25em solid #dd0;
}

Now, when you come to write a new component that also happens to incorporate buttons, that’s one less thing to worry about. You’re not rewriting the same CSS under a different namespace, and there’s no class name to remember or write either. CSS should always aim to be this effortless and efficient — it’s designed for it.

Using element selectors has three main advantages:

  • The resulting HTML is less verbose (no redundant classes).
  • The resulting style sheet is less verbose (styles are shared between components, not rewritten per component).
  • The resulting styled interface is based on semantic HTML.

The use of classes to exclusively provide styles is often defended as a “separation of concerns.” This is to misunderstand the W3C’s separation of concerns8 principle. The objective is to describe structure with HTML and style with CSS. Because classes are designated exclusively for styling purposes and they appear within the markup, you are technically breaking with separation wherever they’re used. You have to change the nature of the structure to elicit the style.

Wherever you don’t rely on presentational markup (classes, inline styles), your CSS is compatible with generic structural and semantic conventions. This makes it trivial to extend content and functionality without it also becoming a styling task. It also makes your CSS more reusable across different projects where conventional semantic structures are employed (but where CSS ‘methodologies’ may differ).

Special Cases Link

Before anyone accuses me of being simplistic, I’m aware that not all buttons in your interface are going to do the same thing. I’m also aware that buttons that do different things should probably look different in some way.

But that’s not to say we need to defer to classes, inheritance or the cascade. To make buttons found in one interface look fundamentally dissimilar is to confound your users. For the sake of accessibility and consistency, most buttons only need to differ in appearance by label.

<button>create</button>

<button>edit</button>

<button>delete</button>

Remember that style is not the only visual differentiator. Content also differentiates visually — and in a way that is much less ambiguous. You’re literally spelling out what different things are for.

There are fewer instances than you might imagine where using style alone to differentiate content is necessary or appropriate. Usually, style differences should be supplemental, such as a red background or a pictographic icon accompanying a textual label. The presence of textual labels are of particular utility to those using voice-activation software: Saying “red button” or “button with cross icon” is not likely to elicit recognition by the software.

I’ll cover the topic of adding nuances to otherwise similar looking elements in the “Utility Classes” section to follow.

Attributes Link

Semantic HTML isn’t just about elements. Attributes define types, properties and states. These too are important for accessibility, so they need to be in the HTML where applicable. And because they’re in the HTML, they provide additional opportunities for styling hooks.

For example, the input element takes a type attribute, should you want to take advantage of it, and also attributes such as aria-invalid9 to describe state.

input, textarea {
  border: 2px solid;
  padding: 0.5rem;
}

[aria-invalid] {
  border-color: #c00;
  padding-right: 1.5rem;
  background: url(images/cross.svg) no-repeat center 0.5em;
}

A few things to note here:

  • I don’t need to set color, font-family or line-height here because these are inherited from html, thanks to my use of the inherit keyword. If I want to change the main font-family used application-wide, I only need to edit the one declaration in the html block.
  • The border color is linked to color, so it too inherits the global color. All I need to declare is the border’s width and style.
  • The [aria-invalid] attribute selector is unqualified. This means it has better reach (it can be used with both my input and textarea selectors) and it has minimal specificity. Simple attribute selectors have the same specificity as classes. Using them unqualified means that any classes written further down the cascade will override them as intended.

The BEM methodology would solve this by applying a modifier class, such as input--invalid. But considering that the invalid state should only apply where it is communicated accessibly, input--invalid is necessarily redundant. In other words, the aria-invalid attribute has to be there, so what’s the point of the class?

Just Write HTML Link

My absolute favorite thing about making the most of element and attribute selectors high up in the cascade is this: The composition of new components becomes less a matter of knowing the company or organization’s naming conventions and more a matter of knowing HTML. Any developer versed in writing decent HTML who is assigned to the project will benefit from inheriting styling that’s already been put in place. This dramatically reduces the need to refer to documentation or write new CSS. For the most part, they can just write the (meta) language that they should know by rote. Tim Baxter also makes a case for this in Meaningful CSS: Style It Like You Mean It10.

Layout Link

So far, we’ve not written any component-specific CSS, but that’s not to say we haven’t styled anything. All components are compositions of HTML elements. It’s largely in the order and arrangement of these elements that more complex components form their identity.

Which brings us to layout.

Principally, we need to deal with flow layout — the spacing of successive block elements. You may have noticed that I haven’t set any margins on any of my elements so far. That’s because margin should not be considered a property of elements but a property of the context of elements. That is, they should only come into play where elements meet.

Fortunately, the adjacent sibling combinator11 can describe exactly this relationship. Harnessing the cascade, we can instate a uniform default across all block-level elements that appear in succession, with just a few exceptions.

* {
  margin: 0;
}

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

body, br, li, dt, dd, th, td, option {
  margin-top: 0;
}

The use of the extremely low-specificity lobotomized owl selector12 ensures that any elements (except the common exceptions) are spaced by one line. This means that there is default white space in all cases, and developers writing component flow content will have a reasonable starting point.

In most cases, margins now take care of themselves. But because of the low specificity, it’s easy to override this basic one-line spacing where needed. For example, I might want to close the gap between labels and their respective fields, to show they are paired. In the following example, any element that follows a label (input, textarea, select, etc.) closes the gap.

label { 
  display: block 
}

label + * {
  margin-top: 0.5rem;
}

Once again, using the cascade means only having to write specific styles where necessary. Everything else conforms to a sensible baseline.

Note that, because margins only appear between elements, they don’t double up with any padding that may have been included for the container. That’s one more thing not to have to worry about or code defensively against.

Also, note that you get the same spacing whether or not you decide to include wrapper elements. That is, you can do the following and achieve the same layout — it’s just that the margins emerge between the divs rather than between labels following inputs.

<form>
  <div>
    <label for="one">Label one</label>
    <input id="one" name="one" type="text">
  </div>
  <div>
    <label for="two">Label two</label>
    <input id="two" name="two" type="text">
  </div>
  <button type="submit">Submit</button>
</form>

Achieving the same result with a methodology such as atomic CSS13 would mean composing specific margin-related classes and applying them manually in each case, including for first-child exceptions handled implicitly by * + *:

<form class="Mtop(1point5)">
  <div class="Mtop(0)">
    <label for="one" class="Mtop(0)">Label one</label>
    <input id="one" name="one" type="text" class="Mtop(0point75)">
  </div>
  <div class="Mtop(1point5)">
    <label for="two" class="Mtop(0)">Label two</label>
    <input id="two" name="two" type="text" class="Mtop(0point75)">
  </div>
  <button type="submit" class="Mtop(1point5)">Submit</button>
</form>

Bear in mind that this would only cover top margins if one is adhering to atomic CSS. You’d have to prescribe individual classes for color, background-color and a host of other properties, because atomic CSS does not leverage inheritance or element selectors.

<form class="Mtop(1point5) Bdc(#ccc) P(1point5)">
  <div class="Mtop(0)">
    <label for="one" class="Mtop(0) C(brandColor) Fs(bold)">Label one</label>
    <input id="one" name="one" type="text" class="Mtop(0point75) C(brandColor) Bdc(#fff) B(2) P(1)">
  </div>
  <div class="Mtop(1point5)">
    <label for="two" class="Mtop(0) C(brandColor) Fs(bold)">Label two</label>
    <input id="two" name="two" type="text" class="Mtop(0point75) C(brandColor) Bdc(#fff) B(2) P(1)">
  </div>
  <button type="submit" class="Mtop(1point5) C(#fff) Bdc(blue) P(1)">Submit</button>
</form>

Atomic CSS gives developers direct control over style without deferring completely to inline styles, which are not reusable like classes. By providing classes for individual properties, it reduces the duplication of declarations in the stylesheet.

However, it necessitates direct intervention in the markup to achieve these ends. This requires learning and being commiting to its verbose API, as well as having to write a lot of additional HTML code.

Instead, by styling arbitrary HTML elements and their spacial relationships, CSS ‘methodology’ becomes largely obsolete. You have the advantage of working with a unified design system, rather than an HTML system with a superimposed styling system to consider and maintain separately.

Anyway, here’s how the structure of our CSS should look with our flow content solution in place:

  1. global (html) styles and enforced inheritance,
  2. flow algorithm and exceptions (using the lobotomized owl selector),
  3. element and attribute styles.

We’ve yet to write a specific component or conceive a CSS class, but a large proportion of our styling is done — that is, if we write our classes in a sensible, reusable fashion.

Utility Classes Link

The thing about classes is that they have a global scope: Anywhere they are applied in the HTML, they are affected by the associated CSS. For many, this is seen as a drawback, because two developers working independently could write a class with the same name and negatively affect each other’s work.

CSS modules14 were recently conceived to remedy this scenario by programmatically generating unique class names tied to their local or component scope.

<!-- my module's button -->
<button class="button_dysuhe027653">Press me</button>

<!-- their module's button -->
<button class="button_hydsth971283">Hit me</button>

Ignoring the superficial ugliness of the generated code, you should be able to see where disparity between independently authored components can easily creep in: Unique identifiers are used to style similar things. The resulting interface will either be inconsistent or be consistent with much greater effort and redundancy.

There’s no reason to treat common elements as unique. You should be styling the type of element, not the instance of the element. Always remember that the term “class” means “type of thing, of which there may be many.” In other words, all classes should be utility classes: reusable globally.

Of course, in this example, a .button class is redundant anyway: we have the button element selector to use instead. But what if it was a special type of button? For instance, we might write a .danger class to indicate that buttons do destructive actions, like deleting data:

.danger {
  background: #c00;
  color: #fff;
}

Because class selectors are higher in specificity than element selectors and of the same specificity as attribute selectors, any rules applied in this way will override the element and attribute rules further up in the style sheet. So, my danger button will appear red with white text, but its other properties — like padding, the focus outline, and the margin applied via the flow algorithm — will remain intact.

<button class="danger">delete</button>

Name clashes may happen, occasionally, if several people are working on the same code base for a long time. But there are ways of avoiding this, like, oh, I don’t know, first doing a text search to check for the existence of the name you are about to take. You never know, someone may have solved the problem you’re addressing already.

Local Scope Utilities Link

My favorite thing to do with utility classes is to set them on containers, then use this hook to affect the layout of child elements within. For example, I can quickly code up an evenly spaced, responsive, center-aligned layout for any elements:

.centered {
  text-align: center;
  margin-bottom: -1rem; /* adjusts for leftover bottom margin of children */
}

.centered > * {
  display: inline-block;
  margin: 0 0.5rem 1rem;
}

With this, I can center group list items, buttons, a combination of buttons and links, whatever. That’s thanks to the use of the > * part, which means that any immediate children of .centered will adopt these styles, in this scope, but inherit global and element styles, too.

And I’ve adjusted the margins so that the elements can wrap freely without breaking the vertical rhythm set using the * + * selector above it. It’s a small amount of code that provides a generic, responsive layout solution by setting a local scope for arbitrary elements.

My tiny (93B minified) flexbox-based grid system15 is essentially just a utility class like this one. It’s highly reusable, and because it employs flex-basis, no breakpoint intervention is needed. I just defer to flexbox’s wrapping algorithm.

.fukol-grid {
  display: flex;
  flex-wrap: wrap;
  margin: -0.5em; /* adjusting for gutters */
}

.fukol-grid > * {
  flex: 1 0 5em; /* The 5em part is the basis (ideal width) */
  margin: 0.5em; /* Half the gutter value */
}
logo with sea anemone (penis) motif

Fukol’s distinctive logotype

Using BEM, you’d be encouraged to place an explicit “element” class on each grid item:

<div class="fukol"> <!-- the outer container, needed for vertical rhythm -->
  <ul class="fukol-grid">
    <li class="fukol-grid__item"></li>
    <li class="fukol-grid__item"></li>
    <li class="fukol-grid__item"></li>
    <li class="fukol-grid__item"></li>
  </ul>
</div>

But there’s no need. Only one identifier is required to instantiate the local scope. The items here are no more protected from outside influence than the ones in my version, targeted with > *nor should they be. The only difference is the inflated markup.

So, now we’ve started incorporating classes, but only generically, as they were intended. We’re still not styling complex components independently. Instead, we’re solving system-wide problems in a reusable fashion. Naturally, you will need to document how these classes are used in your comments.

Utility classes like these take advantage of CSS’ global scope, the local scope, inheritance and the cascade simultaneously. The classes can be applied universally; they instantiate the local scope to affect just their child elements; they inherit styles not set here from the parent or global scope; and we’ve not overqualified using element or class selectors.

Here’s how our cascade looks now:

  1. global (html) styles and enforced inheritance,
  2. flow algorithm and exceptions (using the lobotomized owl selector),
  3. element and attribute styles,
  4. generic utility classes.

Of course, there may never be the need to write either of these example utilities. The point is that, if the need does emerge while working on one component, the solution should be made available to all components. Always be thinking in terms of the system.

Component-Specific Styles Link

We’ve been styling components, and ways to combine components, from the beginning, so it’s tempting to leave this section blank. But it’s worth stating that any components not created from other components (right down to individual HTML elements) are necessarily over-prescribed. They are to components what IDs are to selectors and risk becoming anachronistic to the system.

In fact, a good exercise is to identify complex components (“molecules,” “organisms”) by ID only and try not to use those IDs in your CSS. For example, you could place #login on your log-in form component. You shouldn’t have to use #login in your CSS with the element, attribute and flow algorithm styles in place, although you might find yourself making one or two generic utility classes that can be used in other form components.

If you do use #login, it can only affect that component. It’s a reminder that you’ve moved away from developing a design system and towards the interminable occupation of merely pushing pixels.

Conclusion Link

When I tell folks that I don’t use methodologies such as BEM or tools such as CSS modules, many assume I’m writing CSS like this:

header nav ul li {
  display: inline-block;
}

header nav ul li a {
  background: #008;
}

I don’t. A clear over-specification is present here, and one we should all be careful to avoid. It’s just that BEM (plus OOCSS, SMACSS, atomic CSS, etc.) are not the only ways to avoid convoluted, unmanageable CSS.

In an effort to defeat specificity woes, many methodologies defer almost exclusively to the class selector. The trouble is that this leads to a proliferation of classes: cryptic ciphers that bloat the markup and that — without careful attention to documentation — can confound developers new to the in-house naming system they constitute.

By using classes prolifically, you also maintain a styling system that is largely separate from your HTML system. This misappropriation of ‘separate concerns’ can lead to redundancy or, worse, can encourage inaccessibility: it’s possible to affect a visual style without affecting the accessible state along with it:

<input id="my-text" aria-invalid="false" class="text-input--invalid" />

In place of the extensive writing and prescription of classes, I looked at some other methods:

  • leveraging inheritance to set a precedent for consistency;
  • making the most of element and attribute selectors to support transparent, standards-based composition;
  • applying a code- and labor-saving flow layout system;
  • incorporating a modest set of highly generic utility classes to solve common layout problems affecting multiple elements.

All of these were put in service of creating a design system that should make writing new interface components easier and less reliant on adding new CSS code as a project matures. And this is possible not thanks to strict naming and encapsulation, but thanks to a distinct lack of it.

Even if you’re not comfortable using the specific techniques I’ve recommended here, I hope this article has at least gotten you to rethink what components are. They’re not things you create in isolation. Sometimes, in the case of standard HTML elements, they’re not things you create at all. The more you compose components from components, the more accessible and visually consistent your interface will be, and with less CSS to achieve that end.

There’s not much wrong with CSS. In fact, it’s remarkably good at letting you do a lot with a little. We’re just not taking advantage of that.

(vf, al, il)

Footnotes Link

  1. 1 https://www.smashingmagazine.com/2016/06/designing-modular-ui-systems-via-style-guide-driven-development/
  2. 2 https://www.smashingmagazine.com/2010/04/css-specificity-and-inheritance/
  3. 3 https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/
  4. 4 https://www.smashingmagazine.com/2010/11/the-important-css-declaration-how-and-when-to-use-it/
  5. 5 https://en.wikipedia.org/wiki/Don't_repeat_yourself
  6. 6 http://bradfrost.com/blog/post/atomic-web-design/#molecules
  7. 7 https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/
  8. 8 https://www.w3.org/TR/html-design-principles/#separation-of-concerns
  9. 9 https://www.w3.org/TR/wai-aria/states_and_properties#aria-invalid
  10. 10 http://alistapart.com/article/meaningful-css-style-like-you-mean-it
  11. 11 https://developer.mozilla.org/en/docs/Web/CSS/Adjacent_sibling_selectors
  12. 12 http://alistapart.com/article/axiomatic-css-and-lobotomized-owls
  13. 13 http://acss.io/
  14. 14 https://css-tricks.com/css-modules-part-1-need/
  15. 15 https://github.com/Heydon/fukol-grids

↑ Back to top Tweet itShare on Facebook

Heydon is a designer, writer and public speaker. He works with The Paciello Group as a UX and accessibility consultant. His book, Inclusive Design Patterns, is available in hardcover and as an ebook from Smashing Magazine.

  1. 1

    I think I’m in love with Heydon, now (if I wasn’t already). 😍

    Wonderful article, which expresses exactly why I’m writing “old-fashioned” CSS without any methodologies in mind, using the Cascade and inheritance as good as I can.

    33
    • 2

      Agree totally — well, maybe not so much the love part. :)

      Seriously, though, it’s refreshing to see Heydon address CSS being used in the way it was intended. I, too, write “old-fashioned” CSS and sometimes feel defensive when others insist I use the latest methodology that is suddenly in vogue. Next time, I’ll simply point them to this article.

      12
  2. 3

    Heydon, you are the Hemingway of CSS. What a refreshing article.

    The sceptic in me wonders whether this will break down in The Real World (which always seems to be the world that people who disagree with your opinion inhabit), once you get beyond very simple/small sites. But it sounds oh-so-plausible and desirable.

    If nothing else, I think everyone should give it a try before dismissing it.

    4
    • 4

      Anselm Hannemann

      November 21, 2016 5:52 pm

      Hey Mike, I’ve been building a couple of projects now with and without techniques like ITCSS, BEM, etc, and in variable team sizes between 1 and 20 developers.

      What I can conclude from this is that it’s definitely easier to let all developers stick to BEM. On the other hand, all the time I saw people using such naming strategy some people in the team failed to use this, apply it properly or wrote so much duplicated code because of this as they created a new module for everything. So while theoretically conventions like BEM make it easier for developers to apply CSS to markup and make it more maintainable, this has never been the case in the projects I saw over the last years.
      It is harder to understand the Cascade, so yes you need to spend more time working on CSS if you’re going to use Heydon’s proposed methods instead of blindly applying some convention. This said, you get the clear benefits of avoiding unnecessary classes, saving code (therefore improving performance) and even less work (inheritance can improve maintainability).

      I don’t think the decision relies on the size of a project but certainly it’s harder to have a team of twenty developers working on the CSS to understand the cascade than just yourself. But to achieve a good, maintainable codebase that has a small impact on data transmission, you anyway need to ensure quality which means it requires discipline for either something like BEM or using the cascade. At least I then conclude that BEM and similar approaches don’t matter much here—it’s teaching developers about the cascade, re-using modules and write lean code that counts.

      18
      • 5

        That sounds highly sensible, Anselm. Thanks.

        I think often people get very invested in a tool or methodology that has been useful to them. That’s fine, but when it becomes the One True Way, it’s moved into the realm of dogma.

        It doesn’t seem that long ago that approaches like BEM, OOCSS, and SMACSS were being shouted down as “wrong” by semantic purists. Now they are mainstream, and — in some circles at least — it’s the contrary approaches that get slammed.

        2
  3. 6

    I definitely think this is a great article that reminds us of the pros of CSS native features, but I do have to say a lot of this is assuming that the layout from design itself is straight-forward and modular. Working with a range of designers from small companies to large, sometimes it’s not as easy to implement a design using these properties because the design changes so much from component to component and base/layout styles aren’t as helpful. Still, a great article though!

    6
    • 7

      As I stated at the beginning of the article, I’m writing advice in the context of modular design. It’s not an assumption but an assertion.

      sometimes it’s not as easy to implement a design using these properties because the design changes so much from component to component and base/layout styles aren’t as helpful.

      The design should not be inconsistent. That is your problem here.

      Thank you for reading!

      8
      • 8

        The design should not be inconsistent. That is your problem here.

        Maybe in magical fantasy land where the fairies and elves do web design. But in the real world, designers and especially clients, have very different ideas.

        Because the surroundings of each component are different, designers like to ‘tweak’ the components to make them visually consistent, even though the real values are not the same.

        The differences start out small, but after a few weeks, months or even years of adding new pages, features and interfaces to major international websites, components start to get quite different in their implementation.

        Clients like to tweak things, because, well, they think they know everything and like to destroy consistent designs just for fun :P Good luck getting a high profile client, such as an international airline or credit card company to agree to your perfect design. It just won’t happen, they will always want changes that will mess up the code-consistency.

        I don’t have a problem with the information presented in your article (except the stupid atomic css crap, which is the worst idea ever created in the history of css), but the criticism offered by Amber is indeed valid for a lot of projects. Dismissing it because of a somewhat unrealistic design ideal is not fair. If your methodologies require strict conditions to work, then it’s not necessarily going to be practical for every project. This is why there is no one perfect tool / approach for every project.

        Regarding to your original article, you state that CSS is quite DRY. Maybe in the way you define it, it is.

        To achieve DRYness, you extensively use the cascade, which can introduce other ‘issues’. The issue of overriding previously set values. Just as repeating your own code adds maintainability issues, overriding your own code does the same thing, just in a different form.

        Over time, without proper refactoring, it becomes hard to tell how small changes in the code will affect all of your components, without studying the entire style sheet.

        This is because the appearance of a component relies not just on it’s local CSS code block, but on other bits and pieces that are scattered elsewhere throughout the code. You can’t see the whole picture of a component just by looking at the local code block.

        In a nutshell, the more you use the cascade, the more you introduce the possibility that changing something will have an unintended effect on another element.

        I think that this is why things like BEM were introduced – Because the cascade can cause maintainability issues in large, constantly changing projects.

        This isn’t to say that you can’t use the cascade if you maintain the code properly, and of course other methodologies can introduce other issues as well. I think my point is that each methodology has it’s own set of strengths and weaknesses. You can eliminate repetition in one area, but usually it will introduce a different form of repetition in another area. So it’s personal preference as to which repetition and maintainability issues you want to address throughout the project lifecycle.

        I think that most approaches will work for most projects if time is invested into refactoring instead of taking the quick approach. But realistically this doesn’t happen as much as it should, as projects have limited budgets and time frames. Plus developers get lazy, or they don’t know the project well enough to do the correct thing.

        But I still maintain that the key to maintainable and easy to work with CSS is refactoring.

        26
        • 9

          I said:

          The design should not be inconsistent.

          You said:

          Maybe in magical fantasy land where the fairies and elves do web design. But in the real world, designers and especially clients, have very different ideas.

          Do the designers and clients want the design to be inconsistent? If so, not using any kind of methodology or sensible use of the cascade (as described in the article) is probably your best bet.

          3
          • 10

            No, designers or project owners don’t want inconsistency. They want small changes in various places that add up to consistency over time.
            Btw: Please also consider the rest of Karl’s post. Not just the first paragraph.

            2
          • 11

            Thank you for reading,

            Please note that I don’t think that there’s anything wrong with the classical cascading approach that you write about in the original article. Most older developers grew up with it and it’s important to have a refresher for the younger developers who may have grown up to only use frameworks and ‘anti-cascading’ methodologies. The only thing I wanted to add was that there are disadvantages to that approach too, which is why alternative methodologies were created in the first place.

            Using some kind of defined standard or methodology is always good, even with inconsistent designs, but the type that you use is largely project-dependent and somewhat of a personal preference.

            I know it’s disheartening to think of inconsistency in a design – I hate it just as much as you. I’m always having friendly arguments with designers and trying to convince clients not to do the things that cause inconsistency. Sometimes I’m successful and sometimes I’m not.

            I find that Smashing Magazine targets freelancers and agencies that retain more control over the online strategy. Fair enough. However, there is a difference between being a freelancer, working for a digital agency and working for an agency that handles entire online strategies for their clients. They have different levels of control and responsibility.

            The more control you or your company has, the easier it is to use your own preferred coding style and the easier it is to code your websites. You can maintain perfect consistency.

            With less control, you need to prepare for the unknown. Your code needs to be more future-proof, easily changeable with minimum (or easy) refactoring. You may not be able to use your preferred coding style if it doesn’t suit the project. Readers need to be aware of this and how the technical implementation of a website can make life easier or harder for them in the long run. Which is why I wrote the articles I linked to in the first comment and why I’m posting comments here in this article.

            16
        • 12

          Pankaj Parashar

          November 26, 2016 7:21 am

          I’m curious what led you to believe that Atomic CSS is crap? Any pointers would be more helpful than lamenting a framework by making plain assertions.

          2
  4. 13

    Benjamin Solum

    November 21, 2016 5:41 pm

    Despite protestations by many, CSS does not only provide a global scope. If it did, everything would look exactly the same. Instead, CSS has a global scope and a local scope. Just as in JavaScript, the local scope has access to the parent and global scope. In CSS, this facilitates inheritance.

    You can really only say CSS has local and global scope after you’ve redefined how these idioms apply to CSS. When I define a <button>, that definition carries across modules and pages; anywhere I’ve included that CSS. It’s very much like declaring variables on the window object (or globally) in JavaScript and is just as privy to collisions. However, unlike in JavaScript with functional scope (or block scope with ES6 additions), there’s no way for me to prevent my button styles from leaking into other buttons.

    This is exactly what most CSS conventions and methodologies seek to avoid.

    Now, I think this is a really interesting article. Competing ideas for how CSS should be authored will only serve to improve our industry’s workflows and I think deep down we all want to author CSS this way (or in a similar manner). In fact, once we have strong `:scope`, Shadow DOM, or even nested selector support in CSS, I think we’ll start to see an exodus from conventions like BEM because we’ll have much better ways of to scope our CSS.

    However, as it stands today, I think you really have to call into question the scalability and maintainability of this practice. I would love to see this live on a large project somewhere where the team outlined how they got there and how they keep things maintainable as the product lives on. Thanks for the write up Heydon!

    5
    • 14

      Anselm Hannemann

      November 21, 2016 6:05 pm

      When I define a , that definition carries across modules and pages; anywhere I’ve included that CSS. It’s very much like declaring variables on the window object (or globally) in JavaScript and is just as privy to collisions. However, unlike in JavaScript with functional scope (or block scope with ES6 additions), there’s no way for me to prevent my button styles from leaking into other buttons.

      Yes, true. But using BEM or similar conventions is using the same technique. A primary button should be defined as `.button–primary` and should be used for every primary button on the project. Now in practice (while in theory there is a difference) there’s no difference between using the native element or BEM as CSS selector here. You can add modifiers to your button on either, see Heydon’s example in the article.
      If you want to have two entirely different button styles on one page, I doubt it’s a good idea to style anything specific on `button`. But all the shared styles (I guess `:focus` would still apply to both types of buttons) would still be best styled on `button {}`. The rest of the styles, the individual designs, goes to whatever class-name you prefer then.

      > In fact, once we have strong `:scope`, Shadow DOM, or even nested selector support in CSS, I think we’ll start to see an exodus from conventions like BEM because we’ll have much better ways of to scope our CSS.

      I’ve read dozens of articles on scoping CSS, isolating CSS, etc; I’ve tried out a lot of inline-style generator tools, CSS Modules, styled-components, etc. and yet (despite a very very very few edge cases) I fail to see why we’d need scoped CSS for the masses, especially as you now name Shadow DOM with it here. Generally, if you don’t inject your markup as a third-party to a foreign site I don’t see why you should isolate a module’s scope from the global scope defined for the whole site. By isolating the scope, we also neglect the global scope and I think Heydon has made clear at the beginning of the article why this has disadvantages and causes unnecessary, repeating code…?

      Maybe I just didn’t understand your intention here though. For the “bigger project write up and real life scenario” I hope my example in a previous comment can help here? I acknowledge this is not a proper write-up but it’s sharing a bit of an insight on some bigger projects.

      5
      • 15

        Benjamin Solum

        November 21, 2016 6:25 pm

        Yes, true. But using BEM or similar conventions is using the same technique. A primary button should be defined as `.button–primary` and should be used for every primary button on the project. Now in practice (while in theory there is a difference) there’s no difference between using the native element or BEM as CSS selector here. You can add modifiers to your button on either, see Heydon’s example in the article.

        My comment you’re replying to here was more on the redefinition of “global/local scope” in the article. If we’re all honest with each other, I think we can all admit that CSS is really just globally scoped… which is largely why BEM/Atomic/<insert convention here> exist.

        I fail to see why we’d need scoped CSS for the masses, especially as you now name Shadow DOM with it here.

        I guess I fail to see why giving developers more options is a bad thing? That’s great that you haven’t run across a need for scoping. But there are large teams/projects that have and continue to. Global scope means maintainability nightmares. We need to have certainty that when I change a button’s appearance that it only impacts the button(s) I intended to change.

        By isolating the scope, we also neglect the global scope and I think Heydon has made clear at the beginning of the article why this has disadvantages and causes unnecessary, repeating code…?

        They don’t have to be mutually exclusive and true scoping in CSS would make it a lot easier for large teams to get the best of both worlds.

        6
    • 16

      You can really only say CSS has local and global scope after you’ve redefined how these idioms apply to CSS. When I define a <button>, that definition carries across modules and pages; anywhere I’ve included that CSS. It’s very much like declaring variables on the window object (or globally) in JavaScript and is just as privy to collisions.

      You’re telling me exactly what the article would have told you had you read it.

      However, unlike in JavaScript with functional scope (or block scope with ES6 additions), there’s no way for me to prevent my button styles from leaking into other buttons.

      Yes there is:


      /* restricted to forms */
      form button {
      font-size: 1.25em;
      }

      /* restricted to toolbars */
      [role="toolbar"] button {
      font-size: 1.5em;
      }

      -10
      • 17

        Benjamin Solum

        November 22, 2016 5:01 pm

        You’re telling me exactly what the article would have told you had you read it.

        No, re-read what I said. I’m telling you that you redefined common idioms to fit your posts narrative. You can pretend that adding more and more selectors make things “locally scoped”, but what you’re really doing is changing specificity.

        It may sound pedantic, but this is what conventions like BEM solve for developers. They’re not so much “suppressing features” as they are trying to deal with the scoping problems that have plagued web applications.

        There’s absolutely a tradeoff when adopting a convention like BEM which your article highlights well, but that doesn’t change the fact that the protestations are right.

        9
        • 18

          I’m telling you that you redefined common idioms to fit your posts narrative.

          You mean I offered a different perspective?

          You can pretend that adding more and more selectors make things “locally scoped”, but what you’re really doing is changing specificity.

          Why not both? A more complex selector is more specific and has a more limited scope. E.g. .card a { ... } is more specific than a { ... } and is scoped to containers with the .card class.

          -12
          • 19

            Benjamin Solum

            November 23, 2016 5:54 pm

            You mean I offered a different perspective?

            Yes, you did, but that’s not what I took issue with.

            Why not both? A more complex selector is more specific and has a more limited scope.

            Because they’re not synonyms. Overly Specificic Selectors != Local Scope and it’s the lack of local scoping that highlights the Catch-22 for CSS authors:

            The more specific my selectors, the more more bloated my stylesheets and less reusable (or DRY) my styles become.

            The less specific my selectors, the more reusable but leaky my styles become.

            Thus CSS conventions were born.

            Your .card class offers no built-in guarantees that there isn’t a .card class being used elsewhere (or won’t be used in the future) on a large web app by another developer. That is, unless your team strictly adheres to some naming convention or is using Web Components/Shadow DOM to actually keep your .card class scoped.

            9
  5. 20

    Leonardo Rothe Tagliafico

    November 21, 2016 5:54 pm

    It baffles me that someone had to make an article in 2016 about how cascading and inheritance, two powerful concepts, have to be justified in this new era of anal-retentive class-name-only “methodologies”, that are now considered best-practice.

    Which is non-sense, because one of the things that front-end developers of the past decade were yearning the most for was more powerful selectors, which allowed not only for styling consistenly, but also for easier exceptions cases and even easier transition to whole new redesigns without touching the underlying HTML (which I personally got a couple of opportunities to execute, and that’s when the lessons of the CSS Zen Garden -anyone?- stopped being about novelty and more about practicality).

    I guess this is a generational breach problem, because last time I checked, this heavy class name usage was primarily used to accommodate for IE6 limitations on parsing of “too specific” selectors or poor/nonexistent CSS2/CSS3 selector support, when class names had to be appended via JS or even from server-side templating just to make components look right.

    10
    • 21

      No, multiple classes methodologies are used to keep your sanity in larger projects with multiple developers of different technical backgrounds.

      11
    • 22

      Your .card class offers no built-in guarantees that there isn’t a .card class being used elsewhere (or won’t be used in the future) on a large web app by another developer. That is, unless your team strictly adheres to some naming convention or is using Web Components/Shadow DOM to actually keep your .card class scoped.

      Like I said in the article, you can just CMD + F to look for the “.card” class before you take it.

      0
      • 23

        Thierry Koblentz

        December 9, 2016 2:33 am

        you can just CMD + F to look for the “.card” before you take it.

        I think this explains pretty well everything.
        In my opinion, anybody who’s dealing with a large code base or working in a multi-team environment would never ever think of looking for the existence of a class by doing a “CMD + F”. Without mentioning the fact that different people could do such search at the same time—which would lead to a name collision.

        To me, this shows that there are many engineering challenges you do not seem to be aware of/take into consideration…

        2
  6. 24

    Vitaly Friedman

    November 21, 2016 6:24 pm

    Dear Thierry, please use <code>…code snippet…</code> to add code snippets!

    -3
    • 25

      Thierry Koblentz

      November 21, 2016 6:59 pm

      Dear Vitaly,

      I tried everything but nothing seems to work on my end.
      Here is what I tried (using < and > here now):

      <pre><code class=”language-html”> …my snippet… </code></pre>

      <pre><code class=”language-markup”> …my snippet… </code></pre>

      <code> …my snippet… </code>

      Could you please clean up my comments?
      Thanks!

      0
  7. 26

    Thierry Koblentz

    November 21, 2016 6:53 pm

    This:


    does not make much sense.

    Thanks for the link and mention!!

    0
    • 27

      Markus Seyfferth

      November 22, 2016 2:42 pm

      Maybe using < (& l t ;) for CSS and scripts does the trick? Sorry for the hassle, dear Thierry! Alternatively, just email me the code to markus at smashingmagazine.com and I’ll update your comment! Thanks!

      0
      • 28

        Thierry Koblentz

        November 23, 2016 4:57 am

        Hi Markus,

        Yes, as you can see in my previous posts, I did wrap my snippets inside <pre><code>…</code></pre> or <code>…</code>; I’d say this is the reason why we see a background color for **empty** <code> in my replies. For some reasons, my snippets have been stripped no matter what I tried…

        Anyways, the code snippet I was referring to is this: <div class=”Mtop(0)”> as there should be no reason really to set a margin of 0 on a <div>

        As a side note, I find very little value in comparing different methods without making a distinction between the problems those methods are supposed to solve. There is no “one-size-fit-all” solution out there, no holly grail. In my opinion, the key is to understand the pros and cons of the many various methods we have to style documents and understand which one should be used for any given job.

        Like others have mentioned in this thread, the author is “redefining common idioms to fit [his] posts narrative” or ignoring the reality of environments that are not his own.

        Please don’t get me wrong, this approach has merits but for a specific audience. For many authors it makes very little sense because it creates more problems than it solves; and that’s the bottom line…

        6
        • 29

          Anyways, the code snippet I was referring to is this: & l t; div class=”Mtop(0)”& lgt;  as there should be no reason really to set a margin of 0 on a & l t; div& lgt; 

          True, it is redundant in this case, though I believe the countless other classes are what I would be coding if I adopted Atomic CSS. But the point is I can do better and add margins to <div>s where contextually appropriate. Using the lobotomized owl selector, I normalize margins automatically and don’t have to remember where and where not to apply classes.

          For many authors it makes very little sense because it creates more problems than it solves; and that’s the bottom line…

          By inference, I assume you mean my technique creates problems for those maintaining “inconsistent” / overly complex interfaces. The point is, they shouldn’t be doing that. The interface should be consistent and uniform. Interface design is bigger than what’s convenient for devs to code and maintain. Interfaces should be good — there should be planning and thought in how they are made, not just methodologies that help them become more and more disparate as they mature.

          -3
          • 30

            Thierry Koblentz

            November 23, 2016 7:31 pm

            With all dure respect, I think you live in your own world. You seem oblivious to the many challenges authors need to deal with when working on (very) large projects in big companies. You do not seem to take into consideration any of the problems many of us have to deal with: different tech stacks, heterogeneous teams (in term of skills), poor communication channels between teams, environments with various styles guides, release cycles, cost of on-boarding new hires, performance (CSS bloat), maintenance, refactoring, etc.

            This article and your talk (which we discussed somewhere else) are about to solve a specific set of problems. As I said before, your approach has value, but it relates to a specific context that unfortunately you avoid discussing, allowing your audience to believe that your way to write CSS is _the best way_.

            For what it is worth, I think it is better to tell people what a solution does best instead of trying to sell them one as the only solution they’ll ever need…

            7
          • 31

            With all due respect, I think you live in your own world.

            You raise an interesting point here, Thierry. Since I can offer nothing more than my own perspective, my assertions are necessarily egocentric. In fact, I would take it further and concede that I am skeptical of the authenticity of anything that exists outside my own mind. In my soliptical prison, your perspective on CSS methodology appears to me as a protagonist in a ghoulish, ephemeral theatre which is apparently my own invention. However, since the term ‘solipsism’ precedes my own existence, I can make the intellectual vault that other people have felt the same way and their own perspectives are, by extension, manifest and autonomous.

            -9
          • 32

            I upvoted every comment in this thread because you guys are both right for your own contexts. I’ve never worked in the sort of context Thierry is describing. Nor do I want to; I like small teams who communicate well. My gut instinct is that, if ‘old-fashioned’ CSS doesn’t fit into an organisation, it’s a hint that the organisation is broken, and/or some of the developers need training. But I realise that organisational change is sometimes less feasible than methodological constraints.

            That’s why I feel passionate about what Heydon is advocating, but I also feel like Thierry has some good points about making practical choices when faced with a sub-optimal reality.

            11
          • 33

            Pankaj Parashar

            November 26, 2016 7:50 am

            Hi Heydon,

            Being skeptic about a framework is fine. Questioning the decisions and the approach of a framework is totally fine too. But lamenting a framework that you’ve never tried on real production sites; never attempted to understand the kind of problem it solves is completely unreasonable.

            I’m sure your approach towards writing CSS works perfectly fine for a defined set of use cases and you should continue to write CSS the way it works for you.

            But while writing on a public site, it is imperative that you make your readers aware of the kind of problems this approach solves and the kind of problems it creates when used for a different use-case.

            6
  8. 34

    Oliver Williams

    November 21, 2016 8:01 pm

    Is there any practical difference between

    html {
    font-family: sans-serif;
    }

    * {
    font-family: inherit;
    }

    and (slightly less code):

    * {
    font-family: sans-serif;
    }

    1
    • 35

      For “font-family” I don’t believe so because it is natively inherited already.

      However it is useful in non-inherited properties that you need to change back in and element *and* its children. It is often used to globally set "box-sizing: border-box".

      Here’s an example of changing a global property back using the 2 different ways:
      https://jsfiddle.net/bpsp0hLw/
      https://jsfiddle.net/f86akste/

      Does that make sense?

      1
    • 36

      Yes. With the former, if you want to override the font-family for an element and its children, all you need to do is target that element. With the latter, you have to target the element and all its children.

      And, as Heydon said in the article:

      For example, the input element doesn’t inherit any of the font properties in the previous example.

      So, if you don’t tell them to inherit with * { font-family: inherit } they will keep whatever the browser/OS’s default font is.

      3
  9. 37

    Hi Heydon, thank you for the writeup! I appreciate the elegance of your approach and I was nodding along a few times, but I have to admit, I was shaking my head as well. If I try to match your well thought-out button example to my reality, it doesn’t quite fit. In my project, I have “visual buttons” (elements that are designed to look like a button) that might be implemented as elements, but they could just as well be anchor tags, because the print “button” links to a dedicated print version. I also have button elements that are comprised of a visual icon only (and accessibly hidden text, of course) – a “share by mail” button, for example. The smallest common denominator for just these three variations is really small, especially if I don’t want to pollute the cascade for all elements with button styles.

    Would you agree that this is a real world challenge? Or would you rather say it’s my job to question the design/ux when it requires me to mix “button” and “link” concepts? I’m a bit at a loss here whether your example appears simplified to me because it is, or because you didn’t mention the hard work you put in to push back on inelegant requirements.

    4
    • 38

      In general, buttons should look like buttons. Even ones with icons. So, border and background styles should probably be similar. You could create generic utility classes for special cases, though.

      I appreciate that sometimes links may be button shaped, but I don’t style them like the <button> elements in the same interface because they have different behaviors, so should be visually differentiated. I tend to use a .call-to-action class or similar to use on links that are emphasized and may (or may not) appear in a box-like shape, similar to buttons.

      1
      • 39

        Could you help me with this part?

        > sometimes links may be button shaped, but I don’t style them like the elements in the same interface because they have different behavior

        From my perspective as backend developer, it just depends on if it’s a form or not (and some other non-functional requiements). With my limited frontend knowledge one is a call-to-action with parameters and the other without, but otherwise they have the same behaviour of starting an action (in comparsion to normal links which just refer to other content). What am I missing?

        0
        • 40

          If the action is not to “refer to other content” then you should not use a link to do it. For accessibility’s sake (and to invoke the expected browser behaviors) you should use a <button> control. The button element can and should be used outside of forms for non-linking functionality.

          2
          • 41

            I think I understand what Chris is saying. As a backend developer, he recognises that, in each case, it’s just a GET request. Whether it’s an <a> whose URL has query string parameters, an <a> without query string parameters, or a <button> that submits a form via GET, the server sees them all as just another action to grab a resource. In this sense the semantics of all three are identical from the server’s perspective, and I can even see how they’re similar from a user’s perspective too: they all trigger an action that results in you seeing a new page.

            There are other considerations too: button-shaped links ‘look’ more clickable, and as designers we’re ultimately serving business needs, so more clicks might mean more business. There’s value in styling them slightly differently though; Heydon, what sort of things do you do to differentiate buttony links from real buttons?

            3
  10. 42

    I think your article will help beginners learn about css and its fine for small peojects but i disagree with the following:
    1) styling common elements directly slows browser rendering time because it reads from right to left. See css performance.
    Example:
    .componentx p
    .componenty p
    .componentz p
    The browser will look for all p tags before filtering it down to the inheritance wrapper.
    Where as .myp, the browser only looks for that class.

    2) using * + * to set margin, while very lightweight is clever, the amount of overrides you would end up doing in many different component layouts to meet a design brief would make it redundant and just exacerbate the browser performance.
    3) generally inheritance is poweful but dangerous. The more inheritance you have the more complicated your architecture. Using it carefully is fine but most large scale applications end up with several developers with different styles gradually destroying any semblance of consistency. The reason classes are popular is to isolate clashing and reducing inheritance.

    1
    • 43

      1) styling common elements directly slows browser rendering time because it reads from right to left. See css performance.

      CSS selector performance not a real problem. It will never noticeably affect the rendering time of you page unless you use countless thousands of DOM nodes. Even then it’s bearly measurable. Don’t worry about it.

      2) using * + * to set margin, while very lightweight is clever, the amount of overrides you would end up doing in many different component layouts to meet a design brief would make it redundant and just exacerbate the browser performance.

      If you have to make exceptions in almost all cases, your interface is not uniform and consistent. That is the problem you need to address.

      generally inheritance is poweful but dangerous. The more inheritance you have the more complicated your architecture. Using it carefully is fine but most large scale applications end up with several developers with different styles gradually destroying any semblance of consistency. The reason classes are popular is to isolate clashing and reducing inheritance.

      Nothing in this paragraph explains why inheritance is a problem. “Several developers with different styles”? Why are developers working on the same project diverging in their use of style? It sounds like a mess. Components should be constructed following brand rules / common styles for consistency.

      7
      • 44

        I have been building pixel perfect designs for 16 years, from tables to css to responsive in large and small companies. Over that time i have customized my approach and utilized some build tools and preprocessors in the process. I wont claim to be the best fe developer but experience has taught me irrespective of coding standards or linting, due to varying pressure deadlines and uncaring devs all code gets hacked at some point and a company doesnt have the privaledge of strong fe devs to own and keep the code clean all the time. Classes are safer for isolating codebase. I have alway applied at the start of a project basic styles on common elements but the only ones ever really kept is probably the p tag and the a tag. All the others have been overridden by classes.

        5
  11. 45

    Great article, but how do you style custom components (such as cards) using your approach?

    2
    • 46

      Good question, and one I nearly covered in the article.

      A generic .card utility class to define the basic card appearance should do it. If you want to make the card contents smaller and you’re taking advantage of relative units, you can scale everything inside the card proportionately using an em-based declaration on the card container.

      .card {
      font-size: 0.85em; /* makes all contents proportionatelty smaller */
      padding: 1em;
      border-radius: 0.25em;
      box-shadow: 0 0 0.5em #ddd;
      }

      It’s not really something I covered in the article, but you shouldn’t be afraid of using descendent selectors with utility classes. Just don’t make them more complex than [utility class] [element] {}.

      .card h3 {
      font-weight: 500;
      }

      2
      • 47

        thanks for your answer!
        do you think it’s possible to style the entire components using only descendent selectors ?

        For example card title can be an h3 but sounds a bit weird since we don’t want to give semantic meaning to the child elements, so i usually end up using something like this

        and here of course something like BEM is required.

        1
        • 48

          Ops, the previous example was

          div.card > div.card-tile

          0
          • 49

            For example card title can be an h3 but sounds a bit weird since we don’t want to give semantic meaning to the child elements

            I’m not sure I follow. Why would you not want to use semantic elements where applicable? For accessibility, an <h3> should be an <h3>.

            0
          • 50

            Do you mean that sometimes a card should semantically have a h2 but you need it to appear styled as though it is a h3?

            Bearded had a wonderful approach to this with heading mixins used in a preprocessor.

            First you set all your heading sizes (assuming they differ from inheritence as Heydon suggested in the article)

            @mixin heading-1 {
            font-size: 3rem;
            }
            @mixin heading-2 {
            font-size: 2.4rem
            }
            @mixin heading-3 {
            font-size: 2rem
            }

            Then declare you headings as

            h1 {@include heading-1}
            h2 {@include heading-2}
            h3{@include heading-3}

            Then when it comes to your card you would use the mixin for the heading-3 as the style for your heading 2.
            .card {
            h2 { @include heading-3}
            }

            Is it the right way to do things? Probably not, but I find it a very handy solution.

            0
  12. 51

    Great article and one which I fully agree with. However, the unfortunate truth is that this type of approach will only work when FED and design are done side-by-side, or FED has a very strong say in how things are build/designed.

    It’s a shame that a lot of us probably still have to deal with “marketing agencies”, “UX designers” or “interface designers” who just throw some crap at the wall in Sketch/Photoshop and see what sticks. No thoughts about differences between buttons and anchors, they don’t see the problem with styling an H3 to look like an H1, just use some magic numbers for paddings/margins/etc., create custom styling for input controls etc. etc.

    I can hear people say it already “But you should discuss it with the designers!”. Believe me, I’ve wasted countless hours on discussing topics like these. When dealing with people who are not working with the web in mind, just creating (sometimes pretty) pictures, it’s useless.

    30
    • 52

      +10 to this comment

      1
    • 53

      Totally agree. Communication beats any methodology.

      (And yes, we really do need to move on from Sketch/Photoshop files dictating visual design.)

      4
    • 54

      Emanuel Saramago

      November 25, 2016 4:09 pm

      More important than working with the web in mind, is working with the user (who uses the web) in mind.
      The way SEO, a blind person or another person “sees” a website are totally different. So, visual architecture doesn’t always have to follow html architecture strictly.
      Different styles (with a reason, not just because), can help a visual user understands the interface easier.
      P.s. I’m a front end developer and a web designer, so I understand both sides.

      0
  13. 55

    Bård Nyheim Hovde

    November 22, 2016 9:57 am

    No doubt does this post point contain some good advice and point out some pain points of BEM. I still feel like the author has an overly optimistic idea about maintaining long-lived sites and applications involving more than a couple of developers.

    The approach suggested also re-introduces some of the below pain points that BEM and others were created to solve. I can’t help but feel like we’ve been here before and that we’ve moved on for a reason.

    1: Base selectors and global styles
    Setting things like font family and base font sizes globally are a great idea and seems like a no-brainer whether using a CSS system or not. I’ve never seen anyone use font-family classes. If your project relies on more than a couple of fonts that can be applied globally to body copy and headers, surely this is the problem?

    2: Self-documenting markup
    With BEM, any developer can jump into a project, read the markup and immediately see where components start/end, what elements they contain and understand how to modify them without site effects. This is incredible valuable and ties directly into my next point..

    3: Side effects
    The project has gone live and a new feature is required. You didn’t build the application, but you’re the only developer with free time and so you’re tasked with changing module G on page X. I’ve been that person. It’s terrifying making changes not being confident where else the CSS you’re modifying is used. You can say that this should be documented or otherwise made clear, but again I think without something like BEM this is incredibly hard unless everyone is constantly keeping everyone else up to date on what’s gone into the project.

    4: Developers
    In an ideal world, all maintainers of the project’s CSS would be experts and know all the ins and outs of a project. In reality, developers come and go, and I can’t see the cognitive load of a system of global selectors and cross-module bindings end up in anything but a mess a year down the line. Perhaps it’s possible, but I’ve yet to see it.

    5: Performance
    Like you pointed out in the comments, CSS selector performance not a real problem. Neither is code repetition as this will be gzipped into oblivion. The only cost is more source code to maintain, but his is a trade-off I’d happily take for the reasons stated above.

    As always, Philip Walton puts it better than me. This should be required reading for anyone writing CSS: https://philipwalton.com/articles/side-effects-in-css/

    17
    • 56

      No doubt does this post point contain some good advice and point out some pain points of BEM. I still feel like the author has an overly optimistic idea about maintaining long-lived sites and applications involving more than a couple of developers.

      For other BEM ‘pain points’ (design flaws) see Battling BEM (extended edition). Nobody seems to agree on how to write BEM, which is a bit of an issue.

      Setting things like font family and base font sizes globally are a great idea and seems like a no-brainer whether using a CSS system or not.

      I agree. That’s why I wrote about it, but also to explain how inheritance and the cascade differ and work together.

      With BEM, any developer can jump into a project, read the markup and immediately see where components start/end, what elements they contain and understand how to modify them without site [sic] effects.

      I appreciate that being able to identify component boundaries is useful, but you don’t need to write several classes on every element within the component to achieve this end. You could, as I suggest, use an ID on the wrapper element or (if the components are to be used more than once a page) you could namespace a single class like .compont-[name]. HTML is self documenting, and there’s the spec to refer to if you get stuck.

      It’s terrifying making changes not being confident where else the CSS you’re modifying is used. You can say that this should be documented or otherwise made clear, but again I think without something like BEM this is incredibly hard unless everyone is constantly keeping everyone else up to date on what’s gone into the project.

      Like I said, layout should not be applied to individual elements. If you edited margin on button, it’s likely to break the layout elsewhere.

      In an ideal world, all maintainers of the project’s CSS would be experts and know all the ins and outs of a project. In reality, developers come and go, and I can’t see the cognitive load of a system of global selectors and cross-module bindings end up in anything but a mess a year down the line. Perhaps it’s possible, but I’ve yet to see it.

      In an ideal world developers talk and collaborate, yes. However maintaining a component library is a must, in my opinion. Part of the point of my approach is that you don’t have to be an expert in an in-house system. The foundational CSS outlined should mean you can add HTML arbitrarily, as explained. It’s more important that developers understand HTML than they understand some CSS methodology or other.

      As always, Philip Walton puts it better than me. This should be required reading for anyone writing CSS: https://philipwalton.com/articles/side-effects-in-css/

      Thanks for the link. Interesting. As you may have gathered, I try to write CSS so that the side effects are just effects: when you change something in one place it affects other places desirably. It’s quite a different philosophy, I guess.

      Thanks for reading and covering the BEM related stuff.

      7
      • 57

        I think Heydon hits the nail on the head here: “maintaining a component library is a must.

        Projects really should get used to starting the design with the help of modern pattern / component libraries and methodologies so that consistent design can always be maintained by whoever happens to be updating the design at a later stage. That’s why approaches such as
        Fractal,Astrum and Pattern Lab have recently been adopted by thought leaders.

        0
    • 58

      Thank you for this comment. Having been doing this sort of thing for big, faceless organisations for longer than I wish to remember (and starting this journey almost 20 years ago teaching table based layouts…) you have hit the nail on the head.

      I have sat poking legacy CSS trying to figure out why the f**k changing a margin on one element breaks half the site while the CTO stands behind me on the phone to a client. BEM isn’t perfect but it is a hell of a lot easier to work with than the alternative soup.

      This line from the article you linked to sums it up perfectly.
      “I should also point out that using scoped type selectors makes this problem much worse. Writing rules like .article h3 is just asking for trouble.”

      5
  14. 59

    Very interesting article *and* comments.

    A few take homes for me:

    Heydons article is pretty much spot on – lets not throw the cascade out the window over an obsession with component based architecture. Consider global scope and less specific scope as a starting point of any project. Much of what has been written here has precedence in css ‘reset’ frameworks/methodologies. Can this be taken too far? Yes, it already did and the popular ‘reset’ frameworks changed to suit. To be fair, they also matured as browsers and standards approached some kind of sanity.

    The idea that design should be consistent vs. client demands. This is a battle that can never be won, but compromises can be made – it all depends on the balance of effort! (pick your battles). The battle can be made easier when developers, designers & clients work closely together. Silos are our worst enemy.

    The maintainability of a codebase that becomes ‘legacy’ with multiple developers working on that code over time. “You didn’t look at the README or my comments? Arrghghgh!”. There’s not much that can be done about this, aside from trying to hire the right people.

    8
  15. 61

    On general I agree with Heydon. In defense of methodologies like BEM, they cater not only to the way CSS styles are written but in how the HTML/CSS/JS are connected together as one component. When we get to larger scale application we get to a situation where we have design built 10 years ago, 5 years ago and brand new stuff as well.

    The basic styles inheritance expect people to know bigger portion of the code-base so they will not damage the rest of the components accidentally. In that regard I like to interpret BEM, OOCSS and etc. as a contract between the developers on how to implement their code in non destructive way.

    It’s true that it adds bloat though.

    1
  16. 62

    Mr Pickering, it’s always a pleasure to read your articles. You bring a heaping of contrariness to the CSS world, which is wonderful not just because I happen to agree with the simplicity of your ethic, but also because we need to challenge our belief systems on a regular basis if we want to grow.

    One advantage of this style is that it forces you to be simple. It actually requires more work to make things look broken, so it’s easier to just go with the ‘flow’ (pun intended). It also forces you to understand how inheritance and the cascade work, which is an overall advantage, but could be a disadvantage because (as Anselm says above) there are some people who just simply won’t learn what they need to learn.

    3
  17. 63

    A really interesting article Heydon. I thought I’d play with a few ideas from here and I have encountered an issue that I’m sure someone can help me understand!

    To give a simple example:

    .page > * { color: red; }
    main { color: blue; }

    The main text remains red. But if I add a class to ‘main’..

    .page > * { color: red; }
    .main { color: blue; }

    The main text is blue. It also works if I write:

    .page > * { color: red; }
    .page main { color: blue; }

    or

    .page > * { color: red; }
    main { color: blue!important; }

    Why does the universal selector override ‘main’ without a class but not with one?

    0
    • 64

      hehrehgztjtjwrewrew

      November 25, 2016 1:34 am

      Class selectors have a higher specify than element selectors.
      Your example all highlight the issue most people have with cascading and specificity. If you add in an id and some attribute selectors you will basically have the full range of specificity issues.

      1
    • 65

      Hi Isloss,
      That’s because the universal selector has no specificity and .main has a higher specificity than main (element selector).

      The advantage of this is that you can use simple classes further down in the cascade to override the > * styling (as you discovered).

      I hope that helps.

      1
  18. 67

    I liked this article as it has definitely made me think more about my use of CSS architectures such as OOCSS and BEM. *However*, I think its message is over-simplistic. It positions a solution like this as an ‘either-or’ alternative to CSS architectures like OOCSS and BEM. That is not the case. There are some projects a system like this will work for, but for many enterprise-level projects in the real world it would be highly unlikely to suffice. You say it yourself: “Always be thinking in terms of the system.” The fact is, when a project scales either across codebase size/complexity or team size any one developer cannot be expected to have a high level view of the whole system in their head at any one time, and nor should they. Just like when we build javascript applications we build them from decoupled independent modules or units precisely so the developer does not need to have a whole working module of the entire application in their head in order to know how to change one part of the system. So it is with large CSS codebases. Architectures like BEM and OOCSS were not invented just for the sake of it but to solve a problem, and its that I have just described. Whilst those architectures are far from perfect I don’t agree that describing them as redundant is correct.

    1
    • 68

      I agree. This article does a great job of explaining the benefits of well structured “vanilla” CSS without addressing any of the problems OOCSS solves.

      0
  19. 69

    This article does a great job of explaining how “vanilla” CSS should be approached and structured. Every front end developer should know all of this without thinking. It’s important and often overlooked. It also does a great job of explaining the shortcomings of OOCSS, making you aware of how vanilla CSS might be a better choice at times.

    The thing is, OOCSS should only ever be embraced when its benefits outweigh its shortcomings.

    A good developer should know how to straddle both these worlds, and even intermingle them as necessary, depending on the project, because the benefits of encapsulation can be huge, especially in team environments, or in projects where regular change is expected.

    -1
    • 70

      Additionally, some of the points raised by this article point to the fact that OOCSS is better suited to Reset.css than Normalize.css, as there’s a much bigger change that you’ll want ‘0px’ than any other number.

      0
  20. 71

    Adrian Roselli

    November 25, 2016 7:05 pm

    Here is the key takeaway from this article: if you feel you cannot implement this in your work, you do not have a technology problem, you have a process problem.

    Saying this will not work in your case is just raising objections. Instead, consider *how* you can make this work for your project(s). Maybe that means pushing for more time with the designers, maybe it means holding vendors accountable, maybe it means better communication within the team. All the reasons I see others cite boil down to process.

    If instead you think this approach is technically inferior to BEM, Atomic, or whatever “novel” naming conventions you use, then you still have a process problem but just are not seeing it. One which you are continuing to encode as a form of technical debt.

    Of course there will be exceptions to the approach Heydon outlines. That is normal. A talented developer will find ways to minimize both the number and scale of those exceptions. Frankly, that is the kind of developer I enjoy trying to be, even though I fail regularly.

    11
    • 72

      Johnny Walker

      December 6, 2016 6:36 pm

      I used CSS’s intended process, and was a big proponent of it for many, many years. I still know how to code CSS correctly (and shudder when I see the messes I’m sometimes handed). My brain still thinks in efficient cascading ways, and I’m super fast at working in that way because of it. CSS can be great as it was designed to be used, but it can also be a pain.

      The article overlooks the benefits of the naming conventions you slyly dismiss as “novel”. For me, it wasn’t until I freelanced with an extremely talented developer that I learned those benefits and had to force myself to change my thinking.

      There are pros and cons to both approaches, and you need to know both intricately to understand when to use them. Insisting CSS is perfect as design or dismissing the benefits of BEM sounds like nothing more than a reluctance to learn new things and an avoidance of the pain of changing the way you think.

      CSS is not perfect as design, no matter how well you understand it.

      0
  21. 73

    Eduardo Weidman Barijan

    November 25, 2016 11:00 pm

    Nice article. I do prefer to write plain and “old” HTML and CSS and I appreciate when others like to do it as well. Thanks for sharing those techniques.

    1
  22. 74

    is there any difference between defining global properties on html vs body selector?

    0
  23. 75

    Interesting and thought provoking article.

    Have you ever tried running the style sheet through an online word count utility? Hopefully the results will count duplicates such as background-color:#fff; which can be replaced with a .bgs class. Three letter acronym classes can drastically shrink the style sheet file size and introduce consistency in the web-pages.

    Beware using the CSS global * because it invalidates AmpHtml pages.

    0
  24. 76

    Brilliant article, Heydon. I’m with you – I’ve never been convinced by class naming methodologies when old-school CSS works so well out of the box.

    Admittedly, code can spiral out of control on large projects with a mix of developers with differing levels of CSS experience. Naming methodologies then help but only because you’re avoiding selector cascade and introducing bulky, less-readable HTML.

    Perhaps it’s best to teach developers the basics of CSS before adopting a framework or naming processes?

    1
  25. 77

    TonyTomTomBobBob

    November 29, 2016 6:24 pm

    The problem is not cascading.

    The problem is lazy uncommunicative devs. The problem is amateurs masquerading as professionals.

    I’ve never been screwed by a cascade, until some idiot threw in an “!important” because they had no idea how to do it the right way.

    It’s weird to me that devs would rather learn a new CSS framework, than learn to use CSS–like the professional they purport to be.

    4
  26. 78

    You state you don’t write CSS like this:

    
    header nav ul li {
      display: inline-block;
    }
    header nav ul li a {
      background: #008;
    }
    

    What do you do instead?

    0
    • 79

      Hi Robert,

      I‘m not Heydon, but based on this article I would do something like this:


      [role="navigation"] li {
      display: inline-block;
      }

      [role="navigation"] a {
      background-color: #008;
      }

      Cheers

      1
      • 80

        Yep, that works, Jan.

        Basically, try never to use more than 2 components per selector (one space).

        1
        • 81

          I really like the concept.

          An example I’m struggling with: [role=”navigation”] in a header is typically distinguished from [role=”navigation”] in an aside. Without attributes, you might write that:

          header li {
          display: inline-block;
          }
          aside li {
          display: block;
          }

          But an article can also have a header with list items in it. You likely want those list items to look like list items, not navigation. Which is why the [role=”navigation”] selector is important.

          I would’ve done something like:

          header [role="navigation"] li {
          display: inline-block;
          }
          aside [role="navigation"] li {
          display: block;
          }

          But, that is more than 2 components per selector. Is that just an instance when the specificity is needed… Or can we do that better?

          Thanks a lot!

          0
          • 82

            Good question!

            I would style generic [role=”navigation”] li, then get more specific for exceptions, if necessary. In general, I think navigation li elements should look similar across the interface, with only minor changes per context. For example, I might want the li elements to be block, not inline-block, in a narrower context like a sidebar. Other properties should be shared.

            Come to think of it, with container queries this could be automated and [role=”navigation”] li would just need a container query for width. No header / footer differentiation needed.

            I sometimes use aria-labels to differentiate navigation regions, like

            [aria-label=”site”] li (for main site navigation)

            [aria-label=”pages”] li (for pagination)

            0
    • 83

      Johnny Walker

      December 6, 2016 6:39 pm

      This is impossible to answer without seeing the rest of the project, but you should never have so many components to your selectors. It’s unnecessary, slow, and can come back to bite you.

      The following may work:

      header li {
        display: inline-block;
      }
      header li a {
        background: #008;
      }

      Or the follow may also work:

      li {
        display: inline-block;
      }
       li a {
        background: #008;
      }

      You need to think efficiently about your CSS and make sure you're not overdoing your specificity.

      0
  27. 84

    Thank you so much for writing this article. Ever since CSS preprocessors came into the picture, inheritance and the cascade have become very useful to write clean CSS code.

    0
  28. 85

    Juan Maldonado

    December 6, 2016 7:49 pm

    Outstanding article. There’s truly nothing wrong with only making things as complicated as they have to be in CSS or any coding language, really. I’m an educator and this is the approach I take with students with regards to leveraging the cascade and inheritance because it reinforces both concepts.

    I figure that students will learn stuff like BEM and OOCSS after they graduate and are working in teams, but at least they’ll go into both those workflows understanding how the cascade works.

    0
  29. 86

    suuperb

    0
  30. 87

    Volodymyr Hrebnov

    January 12, 2017 3:31 pm

    Has the author ever worked with a large projects (e.g. big ERP applications)?

    0
  31. 88

    Poor form Web Layouts.

    Using the power of the Smashing Magazine comments section to up your SEO inbound link profile is shameless. You could have at least pointed to a related blog article or something useful.

    0
  32. 89

    Really minor nitpick, but I suspect by “ancestor” and “ancestral” elements (“Inheritance and font-family” section) you really mean “descendant” – the html tag has no ancestors.

    Descendents inherit, ancestors provide that which is inherited.

    0

↑ Back to top