Semantic CSS With Intelligent Selectors

Advertisement

“Form ever follows function. This is the law.” So said the architect and “father of skyscrapers” Louis Sullivan1. For architects not wishing to crush hundreds of innocent people under the weight of a colossal building, this rule of thumb is pretty good. In design, you should always lead with function, and allow form to emerge as a result. If you were to lead with form, making your skyscraper look pretty would be easier, but at the cost of producing something pretty dangerous.

So much for architects. What about front-end architects — or “not real architects,” as we are sometimes known? Do we abide by this law or do we flout it?

With the advent of object-oriented CSS2 (OOCSS), it has become increasingly fashionable to “decouple presentation semantics from document semantics3.” By leveraging the undesignated meanings of classes4, it is possible to manage one’s document and the appearance of one’s document as curiously separate concerns.

Overthinking how a functional thing should look.

In this article, we will explore an alternative approach to styling Web documents, one that marries document semantics to visual design wherever possible. With the use of “intelligent” selectors, we’ll cover how to query the extant, functional nature of semantic HTML in such a way as to reward well-formed markup. If you code it right, you’ll get the design you were hoping for.

If you are like me and have trouble doing or thinking about more than one thing at a time, I hope that employing some of these ideas will make your workflow simpler and more transferable between projects. In addition, the final section will cover a more reactive strategy: We’ll make a CSS bookmarklet that contains intelligent attribute selectors to test for bad HTML and report errors using pseudo-content.

Intelligent Selectors

With the invention of style sheets came the possibility of physically separating document code from the code used to make the document presentable. This didn’t help us to write better, more standards-aware HTML any more than the advent of the remote control resulted in better television programming. It just made things more convenient. By being able to style multiple elements with a single selector (p for paragraphs, for instance), consistency and maintenance became significantly less daunting prospects.

television remote reading DRIVEL

The p selector is an example of an intelligent selector in its simplest form. The p selector is intelligent because it has innate knowledge of semantic classification. Without intervention by the author, it already knows how to identify paragraphs and when to style them as such — simple yet effective, especially when you think of all of the automatically generated paragraphs produced by WYSIWYG editors.

So, if that’s an intelligent selector, what’s an unintelligent one? Any selector that requires the author to intervene and alter the document simply to elicit a stylistic nuance is an unintelligent selector. The class is a classic unintelligent selector because it is not naturally occurring as part of semantic convention. You can name and organize classes sensibly, but only with deliberation; they aren’t smart enough to take care of themselves, and browsers aren’t smart enough to take care of them for you.

Unintelligent selectors are time-intensive because they require styling hooks to be duplicated case by case. If we didn’t have p tags, we’d have to use unintelligent selectors to manufacture paragraphs, perhaps using .paragraph in each case. One of the downsides of this is that the CSS isn’t portable — that is, you can’t apply it to an HTML document without first going through the document and adding the classes everywhere they are required.

class selector called paragraph

Unintelligent selectors at times seem necessary, or at least easier, and few of us are willing to rely entirely on intelligent selectors. However, some unintelligent selectors can become “plain stupid” selectors by creating a mismatch between document structure and presentation. I’ll be talking about the alarming frequency with which the unintelligent .button selector quickly becomes plain stupid.

Vive la Différence

Intelligent selectors are not confined just to the basic elements offered to us in HTML’s specification. To build complex intelligent selectors, you can defer to combinations of context and functional attribution to differentiate basic elements. Some elements, such as <a>, have a multitude of functional differences to consider and exploit. Other elements, such as <p>, rarely differ in explicit function but assume slightly different roles according to context.

header p {
   /* styles for prologic paragraphs */
}

footer p {
   /* styles for epilogic paragraphs */
}

Simple descendent selectors like these are extremely powerful because they enable us to visually disclose different types of the same element without having to physically alter the underlying document. This is the whole reason why style sheets were invented: to facilitate physical separation without breaking the conceptual reciprocity that should exist between document and design.

a semantic heirarchy of needs: what it is, how it functions, where it is5

Inevitably, some adherents of OOCSS treat the descendent selector with some suspicion6, with the more zealous insisting on markup such as the example below, found in BEM’s “Definitions7” documentation.

<ul class="menu">
  <li class="menu__item">…</li>
  <li class="menu__item">…</li>
</ul>

I won’t cover contextual selectors any further because, unless you have a predilection for the kind of overprescription outlined above, I’m sure you already use them every day. Instead, we’ll concentrate on differentiation by function, as described in attributes and by attribute selectors.

Hyperlink Attributes

Even those who advocate for conceptual separation between CSS and HTML are happy to concede that some attributes — most attributes besides classes and custom data attributes, in fact — have an important bearing on the internal functioning of the document. Without href, your link won’t link to anything. Without type, the browser won’t know what sort of input to render. Without title, your abbr could be referring to either the British National Party or Banco Nacional de Panama.

Some of these attributes may improve the semantic detail of your document, while others are needed to ensure the correct rendering and functioning of their subject elements. If they’re not there, they should be, and if they are there, why not make use of them? You can’t write CSS without writing HTML.

The rel Attribute

The rel attribute emerged as a standard for link relations8, a method of describing some specific purpose of a link. Not all links, you see, are functionally alike. Thanks to WordPress’ championing, rel="prev" and rel="next" are two of the most widely adopted values, helping to describe the relationship between individual pages of paginated blog content. Semantically, an a tag with a rel attribute is still an a tag, but we are able to be more specific. Unlike with classes, this specificity is semantically consequential.

The rel attribute should be used where appropriate because it is vindicated by HTML’s functional specification9 and can therefore be adopted by various user agents to enhance the experience of users and the accuracy of search engines. How, then, do you go about styling such links? With simple attribute selectors, of course:

[rel="prev"] {
  /* styling for "previous links" */
}

[rel="next"] {
  /* styling for "next" links */
}

Attribute selectors like these are supported by all but the most archaic, clockwork browsers, so that’s no reason not to use them anywhere the attributes exist. In terms of specificity, they have the same weight as classes. No woe there either, then. However, I recall it being suggested that we should decouple document and presentation semantics. I don’t want to lose the rel attributes (Google has implemented them10, for one thing), so I’d better put an attribute that means nothing on there as well and style the element via that.

  <a href="/previous-article-snippet/" rel="prev" class="prev">previous page</a>

The first thing to note here is that the only part of the element above that does not contribute to the document’s semantics is the class. The class, in other words, is the only thing in the document that has nothing functionally to do with it. In practice, this means that the class is the only thing that breaks with the very law of separation that it was employed to honor: It has a physical presence in the document without contributing to the document’s structure.

OK, so much for abstraction, but what about maintenance? Accepting that we’ve used the class as our styling hook, let’s now examine what happens when some editing or refactoring has led us to remove some attributes. Suppose we’ve used some pseudo-content to place a left-pointing arrow before the [rel="prev"] link’s text:

.prev:before {
  content: '2190'; /* encoding for a left-pointing arrow ("←") */
}

previous link with arrow

Removing the class will remove the pseudo-content, which in turn will remove the arrow (obviously). But without the arrow, nothing remains to elucidate the link’s extant prev relationship. By the same token, removing the rel attribute will leave the arrow intact: The class will continue to manage presentation, all the time disguising the nonexistence of a stated relationship in the document. Only by applying the style directly, via the semantic attribute that elicits it, can you keep your code and yourself honest and accurate. Only if it’s really there, as a function of the document, should you see it.

Attribute Substrings

I can imagine what you’re thinking: “That’s cute, but how many instances are there really for semantic styling hooks like these on hyperlinks? I’m going to have to rely on classes at some point.” I dispute that. Consider this incomplete list of functionally disimilar hyperlinks, all using the a element as their base:

  • links to external resources,
  • links to secure pages,
  • links to author pages,
  • links to help pages,
  • links to previous pages (see example above),
  • links to next pages (see example above again),
  • links to PDF resources,
  • links to documents,
  • links to ZIP folders,
  • links to executables,
  • links to internal page fragments,
  • links that are really buttons (more on these later),
  • links that are really buttons and are toggle-able,
  • links that open mail clients,
  • links that cue up telephone numbers on smartphones,
  • links to the source view of pages,
  • links that open new tabs and windows,
  • links to JavaScript and JSON files,
  • links to RSS feeds and XML files.

That’s a lot of functional diversity, all of which is understood by user agents of all sorts. Now consider that in order for all of these specific link types to function differently, they must have mutually differential attribution. That is, in order to function differently, they must be written differently; and if they’re written differently, they can be styled differently.

In preparing this article, I created a proof of concept, named Auticons11. Auticons is an icon font12 and CSS set that styles links automatically. All of the selectors in the CSS file are attribute selectors that invoke styles on well-formed hyperlinks, without the intervention of classes.

art_auticons13

In many cases, Auticons queries a subset of the href value in order to determine the function of the hyperlink. Styling elements according to the way their attribute values begin or end or according to what substring they contain throughout the value is possible. Below are some common examples.

The Secure Protocol

Every well-formed (i.e. absolute) URL begins with a URI scheme14 followed by a colon. The most common on the Web is http:, but mailto: (for SMTP) and tel: (which refers to telephone numbers) are also prevalent. If we know how the href value of the hyperlink is expected to begin, we can exploit this semantic convention as a styling hook. In the following example for secure pages, we use the ^= comparator, which means “begins with.”

a[href^="https:"] {
   /* style properties exclusive to secure pages */
}

a link to a secure page with a lock icon

In Auticons, links to secure pages become adorned with a padlock icon according to a specific semantic pattern, identifiable within the href attribute. The advantages of this are as follows:

  • Links to secure pages — and only secure pages — are able to resemble links to secure pages by way of the padlock icon.
  • Links to secure pages that cease to be true links to secure pages will lose the https protocol and, with it, the resemblance.
  • New secure pages will adopt the padlock icon and resemble links to secure pages automatically.

This selector becomes truly intelligent when applied to dynamic content. Because secure links exist as secure links even in the abstract, the attribute selector can anticipate their invocation: As soon as an editor publishes some content that contains a secure link, the link resembles a secure one to the user. No knowledge of class names or complex HTML editing is required, so even simple Markdown15 will create the style:

[Link to secure page](https://payment.example.com/)

Note that using the [href^="https:"] prefix is not infallible because not all HTTPS pages are truly secure. Nonetheless, it is only as fallible as the browser itself. Major browsers all render a padlock icon natively in the address bar when displaying HTTPS pages.

PayPal secure page

File Types

As promised, you can also style hyperlinks according to how their href value ends. In practice, this means you can use CSS to indicate what type of file the link refers to. Auticons supports .txt, .pdf, .doc, .exe and many others. Here is the .zip example, which determines what the href ends with, using $=:

[href$=".zip"]:before,
[href$=".gz"]:before {
   content: 'E004'; /* unicode for the zip folder icon */
}

Combinations

You know how you can get all object-oriented and use a selection of multiple classes on elements to build up styles? Well, you can do that automatically with attribute selectors, too. Let’s compare:

/* The CSS for the class approach */

.new-window-icon:after {
   content: '[new window icon]';
}

.twitter-icon:before {
  content: '[twitter icon]';
}

/* The CSS for the attribute selector approach */

[target="_blank"]:after {
   content: '[new window icon]';
}

[href*="twitter.com/"]:before {
  content: '[twitter icon]';
}

(Note the *= comparator, which means “contains.” If the value string contains the substring twitter.com/, then the style will be honored.)

<!-- The HTML for the class approach -->

<a href="http://twitter.com/heydonworks" target="_blank" class="new-window-icon twitter-icon">@heydonworks</a>

<!-- The HTML for the attribute selector approach -->

<a href="http://twitter.com/heydonworks" target="_blank">@heydonworks</a>

A twitter link with icons to show that it goes to twitter and is external

Any content editor charged with adding a link to a Twitter page now needs to know only two things: the URL (they probably know the Twitter account already) and how to open links in new tabs (obtainable from a quick Google search).

Inheritance

Some unfinished business: What if we have a link that does not match any of our special attribute selectors? What if a hyperlink is just a plain old hyperlink? The selector is an easy one to remember, and performance fanatics will be pleased to hear that it couldn’t be any terser without existing at all.

A basic anchor selector (a)

Flippancy aside, let me assure you that inheritance within the cascade works with attribute selectors just as it does with classes. First, style your basic a — perhaps with a text-decoration: underline rule to keep things accessible; then, progressively enhance further down the style sheet, using the attribute selectors at your disposal. Browsers such as Internet Explorer (IE) 7 do not support pseudo-content at all. Thanks to inheritance, at least the links will still look like links.

a {
  color: blue;
  text-decoration: underline;
}

a[rel="external"]:after {
   content: '[icon for external links]';
}

Actual Buttons Are Actual

In the following section, we’ll detail the construction of our CSS bookmarklet for reporting code errors. Before doing this, let’s look at how plain stupid selectors can creep into our workflow in the first place.

Adherents of OOCSS are keen on classes because they can be reused, as components. Hence, .button is preferable to #button. I can think of one better component selector for button styles, though. Its name is easy to remember, too.

button element selector

The <button> element represents a button.

W3C Wiki16

Topcoat17 is an OOCSS BEM-based UI framework from Adobe. The CSS for Topcoat’s various button styles is more than 450 lines if you include the comment blocks. Each of these comment blocks suggests applying your button style in a manner similar to this introductory example:

   <a class="topcoat-button">Button</a>

This example is not a button. No, sir. If it were a button, it would be marked up using <button>. In fact, in every single browser known to man, if it were marked up as a button and no author CSS was supplied, you could count on it looking like a button by default. It’s not, though; it’s marked up using <a>, which makes it a hyperlink — a hyperlink, in fact, that lacks an href, meaning it isn’t even a hyperlink18. Technically, it’s just a placeholder19 for a hyperlink that you haven’t finished writing yet.

Dog in a shark costume
A dog in a shark costume does not a shark make. (Image: reader of the pack20)

The examples in Topcoat’s CSS are only examples, but the premise that the class defines the element and not the HTML is deceptive. No amount of class name modification via “meaningful hyphenation” can make up for this invitation to turn your unintelligent selector into a plain stupid one and to just code stuff wrong.

Update: Since writing this article, Topcoat.io has replaced these examples with <button> examples. This is great! However, I still have my reservations about the way the examples expound the use of the .is-disabled class while omitting the proper disabled attribute. To hear both sides, find my conversation with the Topcoat representative in the comments. For further examples of OOCSS-facilitated web standards mishaps, look no further than semantic-ui.com21. The “standard button” in their examples is a <div> containing an empty <i>.

See No Evil, Hear No Evil

“If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.”

A link that resembles a button and triggers button-like JavaScript events is, to many, a button. However, this only means that it has passed the first two stages of the “duck test.” For all users to be able to apply inductive reasoning and discern the button as such, it must also quack like one. Because it remains a link, it will be announced by screen readers as “link,” meaning that your allegorical skyscraper is not wheelchair-accessible. Avoiding this kind of unnecessary confusion for assistive technology users is not a pursuit of semantic perfection but a responsibility we should undertake for real benefit.

Nonetheless, some will insist on using a as the basis of their buttons. Hyperlinks are (slightly) easier to restyle consistently, after all. If a is the element of choice, then there is only one way to make it a close-to-true button in the accessibility layer. You guessed it: You must apply another meaningful attribute in the form of a WAI ARIA22 role. To ensure that a hyperlink element looks like a button for good reason, apply only the following attribute selector.

[role="button"] {
   /* semantic CSS for modified elements that are announced as “button” in assistive technologies */
}

Quality Assurance With Attribute Selectors

“CSS gives so much power to the class attribute, that authors could conceivably design their own “document language” based on elements with almost no associated presentation (such as DIV and SPAN in HTML) and assigning style information through the “class” attribute. Authors should avoid this practice since the structural elements of a document language often have recognized and accepted meanings.”

– “Selectors23,” CSS Level 2, W3C

The reason we have two elements — a and button — is to semantically demarcate two entirely different types of functional interaction. While the hyperlink denotes a means to go somewhere, the button is intended as the instigator of an event or action. One is about traversal, the other about transformation. One facilitates disengagement, the other engagement.

To make sure we don’t do anything too daft and get our links and buttons muddled up, we will now build a CSS bookmarklet that uses intelligent attribute selectors to test the validity and quality of the two respective elements.

Inspired partly by Eric Meyer’s post24 and taking a few cues from DiagnostiCSS25, this style sheet will combine attribute selectors and the :not selector (or negation pseudo-class26) to highlight problems in the HTML. Unlike these other two implementations, it will write an error to the screen using pseudo-content. Each error will be written in Comic Sans against a pink background.

By connecting function directly to form, we see that ugly markup results in ugly CSS. Consider this the revenge of an abused document, exacted on its designer. To try it out, drag revenge.css to your bookmarks, and click the bookmark to trigger it on any page that you fancy. Note: It won’t currently work for pages that are served over https.

REVENGE.CSS27
Drag to your bookmarks bar.

Rule 1

“If it’s a hyperlink, it should have an href attribute.”

a:not([href]):after {
   content: 'Do you mean for this to be a link or a button, because it does not link to anything!';
   display: block !important;
   background: pink !important;
   padding: 0.5em !important;
   font-family: 'comic sans ms', cursive !important;
   color: #000 !important;
   font-size: 16px !important;
}

Notes: In this example, we are testing not the attribute’s value, but whether the attribute exists in the first place — that is, whether [href] matches any element with an href attribute. This test is only appropriate on hyperlinks, hence the a prefix. The rule reads like, “For every a element that is not also an [href] element, append some pseudo-content with an error notice.”

Rule 2

“If it’s a hyperlink and has an href attribute, it should have a valid value.”

a[href=""]:after, a[href$="#"]:after, a[href^="javascript"]:after {
   content: 'Do you mean for this link to be a button, because it does not go anywhere!';
   /*... ugly styles ...*/
}

Notes: If the href is empty, ends in a # or is using JavaScript, it’s probably being used as a button without the correct button element. Note that I am using “starts with javascript.” Standard practice for voiding hrefs is to use javascript:void(0), but we can’t depend on that always being written in the same way (with or without a space after the colon, for example).

Rule 3

“If it uses a button class, it should be a button — at least in the accessibility layer.”

.button:not(button):not([role="button"]):not([type="button"]):not([type="submit"]):not([type="reset"]):after,
.btn:not(button):not([role="button"]):not([type="button"]):not([type="submit"]):not([type="reset"]):after,
a[class*="button"]:not([role="button"]):after {
   content: 'If you are going to make it look like a button, make it a button, damn it!';
   /*... ugly styles ...*/
}

Notes: In this example, we’re demonstrating how you can chain negation when testing for attributes. Each selector reads like this: “If the element has a class that says it’s a button but it’s not a button element and it doesn’t have the correct role to make it a button in the accessibility layer and it’s not an input being used as a button, then… well, you’re lying.” I’ve had to use [class*="button"] to catch the many Topcoat class variations (62 in total!) that fail to enforce actual buttons on hyperlinks. I’ve noticed that some authors use button-container and the like on parent elements, which is why the a qualifier is included to avoid false positives. You may recognize the .btn class from Twitter Bootstrap, which (if you’ve read the component’s documentation28 carefully) you’ll know is also unsure about whether links or buttons are buttons.

Rule 4

“If it is an a element with role="button", then it should link to somewhere when JavaScript is off.”

a[role="button"]:not([href*="/"]):not([href*="."]):not([href*="?"]):after {
   content: 'Either use a link fallback, or just use a button element.';
   /*... ugly styles ...*/
}

Notes: We can be fairly sure that hrefs that do not include one of /, . (usually to precede a file extension) or ? (to start a query string) are probably bogus. Getting links to act as buttons and return: false when JavaScript is on is fine — fine, that is, if they have a page to go to when JavaScript is off. In fact, it’s the only legitimate reason I can think of not to use <button> instead.

Rule 5

“You can’t disable a hyperlink.”

a.button[class*="disabled"]:after,
a.btn.disabled:after,
a[class*="button"][class*="disabled"]:after {
   content: 'You cannot disable a hyperlink. Use a button element with disabled="disabled".';
   /*... ugly styles ...*/
}

Notes: Even ancient user agents understand the disabled attribute, so use it with an appropriate element in a compliant way. You can concatenate attribute selectors just as you can concatenate classes: In the last of the three selectors, we’re saying, “If it’s a link that contains the substring button and the substring disabled, then print an error message.” Twitter Bootstrap uses the second form, .btn.disabled, in its style sheet, but not with the a prefix. We’ll only consider it an error if used on hyperlinks.

Rule 6

“Buttons in forms should have explicit types.”

form button:not([type]):after {
    content: 'Is this a submit button, a reset button or what? Use type="submit", type="reset" or type="button"';
}

Notes: We need to determine whether buttons within forms have explicit types, because some browsers29 will treat any button in this context without a specified type as type="submit". We want to be absolutely sure that the form won’t submit if our button has a different purpose.

Rule 7

“Both hyperlinks and buttons should have some sort of content or an ARIA label.”

a:empty:not([aria-label]):not([aria-labelledby]):after,
button:empty:not([aria-label]):not([aria-labelledby]):after,
button:not([aria-label]):not([aria-labelledby]) img:only-child:not([alt]):after,
a:not([aria-label]):not([aria-labelledby]) img:only-child:not([alt]):after {
   content: 'All buttons and links should have text content, an image with alt text or an ARIA label';
   /*... ugly styles ...*/
}

Notes: Buttons and links that don’t include any kind of direction for their usage — in either textual or graphical form — are pretty bogus. These final two selectors are perhaps the most complex I’ve ever written. For the hyperlink version, the selector reads something like this: “If it is a hyperlink that does not have either an aria-label attribute or an aria-labelledby attribute and it contains only an image as content but this image does not have an alt attribute, then write the ugly error message.” Also, note the use of the :empty selector30. Arguably, no element that is not self-closing should ever be left empty.

Ten points to the first person using revenge.css who can tell me where I’ve broken my own rule in this very article. Trust me, the error is definitely there.

Conclusion

The reason I use the kinds of selectors and patterns described above is not to try something different or to have something new to write about. Attribute selectors aren’t, by themselves, anything new anyway. IE 6 is the only browser31 that doesn’t support them. The reason I use them is because I simply do not have the time or mental capacity to “do” HTML and CSS in parallel. My brain just isn’t good enough for that. The reason I style my page headers with [role="banner"] and not .page-header is because that’s the only way I’ll know — upon seeing the intended visual effect — that I’ve put the navigable landmark32 in place. How else does one keep track? You can’t just leave it to testing, because then it’s usually too late.

There’s no such thing as semantic CSS. There’s only semantic HTML and its visible form. In this article I have tried to demonstrate that, by coupling the function and form of Web pages directly, you can create mechanisms for reward and punishment. On the one hand, you can set up selectors that invoke visual motifs only when the suitable markup is used. On the other hand, you can query the markup for bad patterns and erode the visual design as a commitment to the underlying ugly truth.

It’s true that not all the styling hooks in your arsenal will likely ever be uniformly semantic or intelligent. Classes are often desirable as polyfills for much needed elements or attributes that have yet to be standardized. That’s how .footer became <footer> and type="text" (with a bunch of JavaScript) became type="url". Other times, they are helpful for doing non-semantic layout scaffolding with grid frameworks33 and the like.

However, if you are committed to giving CSS its own completely separate logic, then you are bound to create unnecessary arguments between form and function. In this eventuality, only constant vigilance can protect against inaccessibility and invalidity. To make matters worse, trying to manufacture pseudo-semantics purely with classes makes it easy to fall into one of those interminable discussions over what makes a semantic class name34. You’ll start spending less time using the remote to control the TV and more time just sitting there, contemplating the remote control held in your hand.

Life is too short.

(al)

Footnotes

  1. 1 http://en.wikipedia.org/wiki/Louis_Sullivan
  2. 2 http://www.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss/
  3. 3 http://nicolasgallagher.com/about-html-semantics-front-end-architecture/
  4. 4 http://www.w3.org/TR/CSS2/selector.html#class-html
  5. 5 http://www.smashingmagazine.com/wp-content/uploads/2013/08/art_heirarchy_mini.png
  6. 6 http://www.impressivewebs.com/when-to-avoid-descendant-selector/
  7. 7 http://bem.info/method/definitions/
  8. 8 http://blog.whatwg.org/the-road-to-html-5-link-relations#what
  9. 9 http://en.wikipedia.org/wiki/Functional_specification
  10. 10 http://googlewebmastercentral.blogspot.co.uk/2011/09/pagination-with-relnext-and-relprev.html
  11. 11 http://heydonworks.com/auticons-icon-font/
  12. 12 http://sixrevisions.com/resources/free-icon-fonts/
  13. 13 http://www.heydonworks.com/auticons-icon-font
  14. 14 http://en.wikipedia.org/wiki/URI_scheme
  15. 15 http://daringfireball.net/projects/markdown/syntax#link
  16. 16 http://www.w3.org/wiki/HTML/Elements/button
  17. 17 http://topcoat.io/
  18. 18 http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-href
  19. 19 http://www.w3.org/wiki/HTML/Elements/a
  20. 20 http://www.flickr.com/photos/youngandwithit/
  21. 21 http://semantic-ui.com/elements/button.html
  22. 22 http://www.w3.org/WAI/intro/aria
  23. 23 http://www.w3.org/TR/CSS2/selector.html#class-html
  24. 24 http://meyerweb.com/eric/tools/css/diagnostics/
  25. 25 https://github.com/diagnosticss/diagnosticss
  26. 26 http://dev.w3.org/csswg/selectors3/#negation
  27. 27 (function(){revenge=document.createElement('LINK');revenge.href='//www.heydonworks.com/css/revenge_buttons.css';revenge.rel='stylesheet';revenge.media='all';document.body.appendChild(revenge);})();
  28. 28 http://twitter.github.io/bootstrap/components.html#buttonDropdowns
  29. 29 http://stackoverflow.com/questions/932653/how-to-prevent-buttons-from-submitting-forms
  30. 30 https://developer.mozilla.org/en-US/docs/Web/CSS/:empty
  31. 31 http://www.quirksmode.org/css/selectors/
  32. 32 http://blog.paciellogroup.com/2013/07/enabling-landmark-based-keyboard-navigation-in-firefox/
  33. 33 http://unsemantic.com/
  34. 34 http://css-tricks.com/semantic-class-names/

↑ Back to topShare on Twitter

Heydon has a love/hate relationship with CSS and a lust/indifference relationship with javascript. He writes a lot and makes fonts.

Advertising

Note: Our rating-system has caused errors, so it's disabled at the moment. It will be back the moment the problem has been resolved. We're very sorry. Happy Holidays!

  1. 1

    In theory I appreciate what Heydon is saying and there are many useful takeaways in here. OOCSS shouldn’t be an excuse to disregard good semantics in your html.

    HOWEVER, in practice… this is exactly how I used to code CSS and it led to all of the problems BEM and OOCSS have identified and tried to solve, i.e. the often counterproductive design of the CSS specificity model, massive (slow) selectors, arbitrary class names, granularity issues, and lack of code reusability. I would have to see how you apply your method to a large project to be convinced of its efficacy.

    Your BEM example is also not quite fair (and while you could do BEM that way, it is not usually necessary to add classes to every element unless you have a very complex block you’re working with). The premise behind BEM is thinking about your design in terms of groups of elements (blocks) that are always found together and ONLY using descendent selectors within these elements so as to avoid selector conflicts and specificity issues. In practice, this actually frees you up from using loads of classes where they’re not necessary.

    What I did take away from this article is how many attributes I was unaware or only vaguely aware of, and how (like Jens Grochtdreis pointed out above) these can be used to enhance my BEM selectors and simplify html markup. In a complex visual design, classes are still absolutely necessary, but may only need to be applied in many cases on the block parent element.

    • 2

      Heydon Pickering

      August 20, 2013 8:05 am

      Sure, that sounds good.

      Just wondering, though…

      If I’m permitted to use descendant selectors within individual modules, I’m wondering why BEM’s example has the classes on each <li> within the <ul>?

      • 3

        The reasons for having a class on each li element:

        1. You are going to have child li elements within those li elements that you don’t want to inherit the parent li’s styles. Using “menu > li” instead of “menu li” will usually take care of this without having to use the extra classes, however.

        2. You are very concerned about selector performance. Using a class directly means that the browser doesn’t have to search all li elements and then narrow down to those with a parent .menu class. Or at least that’s what I’ve been told.

        If I need to use a class within a block, I will prefix it with the block name (i.e. .menu-first) and select it with just the class (no decendant), since this gives me a new namespace to work with and makes it easy to keep all my block definitions together, but if a class isn’t necessary within a block and isn’t going to cause a lot of issues down the road, I won’t use it. “.menu > li” is perfectly acceptable and usually preferable. Once your selectors start getting too deep you’re going to start fighting with specificity, though.

        I really wish specificity had been handled some other way in CSS. Things could have been much different.

  2. 4

    Yes, I did appreciate the irony of the bookmarklet triggering the pink warning.

    I am also trying to decide if I’m happy or sad that Comic Sans does not actually appear on Ubuntu!

    That aside, very enjoyable article, and I think I like the idea of seeing if I can’t do _something_ to add that kind of test into the build process, to remind myself of what Not To Do.

    • 5

      Heydon Pickering

      August 20, 2013 3:50 am

      Winner! 10 points to you :-)

      Perhaps I should have abstracted the “add to bookmarks” function and used a button / .AddFavourite() function combination or similar (http://snipplr.com/view/70220/)

      You know, if I was going to do it properly…

      • 6

        The one thing I am curious about is how this affects performance? Have you done any tests on it? (I know that the CSS linter frowns on ‘selectors that look like regex': https://github.com/stubbornella/csslint/wiki/Disallow-selectors-that-look-like-regular-expressions )

        • 7

          Regarding performance of CSS for complex selectors: my approach is to adapt my CSS performance to the dynamic design of the page; the browser can do pretty well with very complex CSS if your page is rendered once. However, if you have animations that reflow the DOM elements, the browser will recalculate some or all CSS. Even so, the most problematic is not the regex search of the DOM (unless you have tens of thousands of tags), but the transparencies, transitions, etc. Not all browsers use the GPU effectively for CSS rendering.

          One other situation you have to test is browser window resize. I’ve seen some pretty heavy CSSed pages (regex and all) that cause no problems at all when resizing my window, and I’ve seen some simpler CSS but with lots of transparency, animations, reflowing rules etc, which made the resizing feel like extreme stuttering.

          • 8

            A good point. The complexity of rendering via whatever selector is a much bigger performance question than the selector used to invoke that rendering.

  3. 9

    Jens Grochtdreis

    August 20, 2013 3:21 am

    Thanks a lot for this massive and really good article. I published myself an article today in my German blog about this topic, although not that detailed.

    Your examples are really good and point to the shortcomings of all the object-oriented concepts. The BEM example always makes me shiver. Not long ago I marked navigations with list-items that hold the same class as a bad example in my lectures. Nowadays it is recommended as best practice? Not in my book!

    But I wouldn’t go so far as to ban all classes from my document. Classes have their use in identifying the constructing modules of my page. If necessary even he elements of those modules can have classes. But mostly they can be targeted with selectors.

    And hopefully many people will read this article to identify over-classification of HTML as a way of doing it wrong.

    • 10

      Heydon Pickering

      August 20, 2013 3:57 am

      Sounds good, Jens.

      Regrettably, my German is very poor.

      Can we have a link for our Freiburg friends, though?

      :-)

    • 11

      I believe one of the reasons for using name-spaced classes for elements within modules is to avoid styles from other libraries/devs leaking into your module. How would you propose to avoid this situation? Would you just avoid 3rd-party libraries and enforce rigorous standards within your development team?

      • 12

        Heydon Pickering

        August 21, 2013 1:15 am

        Yes.

        I’m often asked what styling hook I’ve designated for buttons, for instance. The conversation goes a bit like this:

        DEV: “What are we using for button styles again? Is it just ‘button’?”
        ME: “Well, you know me…”
        DEV: “Okay… I’ll just use ‘button'”
        DEV: “There – class=’button’. Simple.”
        ME: “What??”
        DEV: “Ha ha. Only joking. I put a button element in.”

        Recently, when I’ve been writing the CSS and someone else is writing the HTML, they know to use the correct elements and roles because they know that’s all I’ve catered for in my normalization file. Classes don’t do a lot in my CSS :-)

  4. 15

    Henrik Kjelsberg

    August 20, 2013 3:38 am

    You’ve pointed out some obvious issues with OOCSS. OOCSS will also become less important as web-components emerge; but what you’ve detailed here, I believe is future-proof. Well done!

  5. 16

    Heydon, do I understand this correctly, you’re saying…

    Do not use additional selectors if styling can be done by:

    – using the correct tag
    with/or
    – the correct attributes/values

    So (for example) instead of using div.address you’d always go for the address-tag?

    • 17

      Heydon Pickering

      August 20, 2013 4:52 am

      Certainly. By using a class as the styling hook you are not addressing the true nature of the element. Instead you are just addressing what the author (perhaps oneself) has decided that element is.

      This can lead to drifting away from proper standards.

      • 18
        • 19

          I second this… How?

          • 20

            I’m tempted to say “just read the article again”. Alas, I don’t think you’ll be satisfied with that.

            Instead, lets break it down:

            1. The .button class selector can be used to style anything as a “button”
            2. The button element selector can only be used to style a true, accessible, interoperable, standardised <button> element as a “button”

            Do you see the advantages of (2) over (1)?

      • 21

        This is nothing to do with standards. There’s nothing in standards about how you choose to target an element for styling.

      • 22

        So it’s an advantage that you can only style a button to look like a button. What do you do when you need to style a link like a button?

  6. 23

    Excellent article. I appreciate the mention of Topcoat as well. Unfortunately your info is out of date. We use a button tag because well, it’s a button. This was not included previously since we were iterating on getting the markup right ( portable, accessible, minimal ) and were lazer focused on CSS performance, which is something you don’t mention in this article. Most of the selectors you outline suffer from the lack of direct specificity which is the largest contributing factor to CSS selector speed. CSS selector speed is a very minor part of page performance, but if you are making an application where feel matters you most likely will need to consider how these factors are compounded at some point. With every decision you make there will always be trade-offs. The example of using an anchor tag as a button is a great example. This tag has a special ability in that it can trigger navigation. Using a button tag as a button sounds almost humorously straight forward, but if all that button does is trigger navigation then you are replicating built in functionalty with your own script. This starts to uncover what Topcoat is trying to address; The web is a platform that is expressing far more than just documents. Applications built on this platform need to take special considerations since the web has evolved to support a use that was not even imagined at it’s inception. To me it seems that every mention of semantics on the web eventually devolves into a pedantic debate fueled by zealots who believe that there can only be one right answer. I feel that we should instead consider our users and make our decisions based off of what fulfills their needs best.

    • 24

      Heydon Pickering

      August 20, 2013 5:28 am

      Hey, thanks for the detailed comment. Sorry to demonize Topcoat; it’s certainly no worse than other frameworks in this respect.

      I’ve just downloaded version 0.6.0 and am pleased to share that the link examples have been replaced with buttons. Thanks!

      I am still, however, concerned with the below

      <button class="topcoat-button is-disabled">Button</button>
      

      since it implies that using the “is-disabled” class suffices. No disabled="disabled" (or readonly attribute) is included. Some developers might not be aware that these are required to make the button a proper disabled button and “is disabled” a true statement. One could test for this with something like:

      button[class*="disabled"]:not([disabled]):after {
         content: 'Use disabled="disabled" to disable this button';
      }
      

      “The example of using an anchor tag as a button is a great example. This tag has a special ability in that it can trigger navigation. Using a button tag as a button sounds almost humorously straight forward, but if all that button does is trigger navigation then you are replicating built in functionalty with your own script.”

      Yeah, then I’d use a link :-)

      “Most of the selectors you outline suffer from the lack of direct specificity which is the largest contributing factor to CSS selector speed. CSS selector speed is a very minor part of page performance, but if you are making an application where feel matters you most likely will need to consider how these factors are compounded at some point.”

      Agreed, CSS selector performance is a very minor part of page performance. In most cases, just compressing or removing a couple of images would have a much greater impact. However, I do appreciate that a lot of dynamic CSS – especially using animations – might require a selector audit.

      “The web is a platform that is expressing far more than just documents. Applications built on this platform need to take special considerations”

      Again, I agree, which is partly why I wrote this. By its very nature, a “one page app” is not (for the most part) a linked document. I wanted to create awareness around the button as a more appropriate “clickable” in such a context.

  7. 25

    The author has written a couple of thousand words on using attribute selectors instead of classes.

    I’m not saying he’s wrong, but the article could have been more concise and (a lot) less condescending.

  8. 26

    This is a ridiculous example:

    <button class="button">This is a button</button>

    Classes are meant to separated into theme and layout styles.

    If you were using OCSS properly it would look something more like this:

    <button class="theme-name w1of3">This is a button</button>

    Secondly, the css you’re writing goes against best practices from Mozilla and Google:
    1) Attribute selectors are less efficient
    2) Universal rules are less efficient
    3) Chained selectors are less efficient

    and you’re using all three of them!

    https://developers.google.com/speed/docs/best-practices/rendering
    https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Writing_efficient_CSS

    • 27

      Heydon Pickering

      August 20, 2013 5:54 am

      CSS selctor performance hardly matters in most cases; not compared to image weight or javascript performance by a long shot. In addition, it is actually improving for the complex selectors you have listed. The following post addresses these improvements and was written by the inventor of OOCSS, Nicole Sullivan: http://calendar.perfplanet.com/2011/css-selector-performance-has-changed-for-the-better/

      If you were using OCSS properly it would look something more like this:
      <button class=”theme-name w1of3″>This is a button</button>

      You can do that if you like, but it scares the heck out of me :-O

      • 28

        I agree with Heydon. OOCSS becomes far too weighty, far too verbose, and far too difficult to code (you have to remember all the classes, sub-classes, sub-sub-classes, etc. that you invented). If you aim to instead use more element/attribute combinators, you can still use themes with ease by merely relying upon the cascade to *add* theme styles to the existing semantic rules, as it were. If that makes sense.

        However, I do wonder about grids, at least until we actually get an official CSS spec for how to do them without classes. Thoughts?

        • 29

          Heydon Pickering

          August 22, 2013 7:30 am

          you have to remember all the classes, sub-classes, sub-sub-classes, etc. that you invented

          Absolutely. And the key word here is “invented”.

          Thanks for reading, Chris!

        • 30

          As for grids, you have many ways to not have to use classes (or very sparingly) via using a preprocessor such as Sass, Grid systems powered by Sass such as singularitygs, Suzy, and Foundation; and semantic grid systems.

          • 31

            You raise a good point and I’m not strongly opposed to grids being powered by classes, but I’m not sure what you mean by “semantic grid system”, Kevin? Do you have an example?

            Surely grids should be powered using <div>s, because they’re just unsemantic scaffolding.

          • 32

            I believe that when Kevin means when he says ‘semantic’ is ‘semantic-to-the-developer’, not ‘semantic-to-the-document-parser’. A few people have written on different levels of semantics: the difference between semantic markup and classnames that mean something to someone who’s reading the source code (e.g., a class like ‘call-to-action’ is better than something like ‘big-and-red’). Think of it as ‘semantic lite’.

            (Unfortunately I can’t reference any of the articles I’ve read recently, because I don’t know where I found them.)

            Semantic grids pretty much require a CSS preprocessor. What you do is give your gridded element a meaningful name: let’s say ‘.categories’ rather than ‘.grid-1-span-3′. Then you use your CSS preprocessor to give .categories the grid styling.

            .categories {
            @media (min-width: 48em) {
            @include grid($start: 1, $span: 3);
            }
            }

            Something like that. The nice thing about this is, because the classnames are decoupled from presentation entirely (all the HTML knows is that it has a class of ‘categories’) you can make it behave differently at different breakpoints (you can see above that my .categories element will only be part of a grid when the viewport is 48em or larger). Try to do that with a plain-CSS grid framework!

            Anyhow, I think this fits in nicely with Heydon’s recommendations; you’d use these classes for when styling based on document semantics just doesn’t cut it.

  9. 33

    The danger you run into with this is assuming that every button, or link, or address should be styled the same way. On some sites, with a lot of forward planning and thinking this may be possible, but at least in my experience the vast majority vary the look depending on context. Now you can argue about the benefits of rules that look like

    footer nav ul button and footer nav button versus .footer_sub_button and .footer_main_button. But I think they both have their place.

    Especially because inevitably it seems like someone will want to put their specially designed button here at the end of the list of all the other buttons, or something like that where you do need to target very specifically, and then inheritance can start to screw you over when you need to override a bunch of styles for that one exception instead of just targeting two (or more) different specific classes.

    Still, I like the article and it has a lot of great suggestions.

  10. 38

    Thank you! Great article. I’ve been able to use class-less CSS with at most two-level selectors (e.g., “footer p”) in all my websites. Jeff Starr’s H5 template for WordPress provides an inspiring example, too. It’s actually not that hard, and has surely made for a lot less work. As you say, “Life is too short,” and I’m a lazy cuss.

  11. 39

    Thank you for the post here, Heydon. I thought the overall message was quite helpful to both those who are learning CSS and have used it on an Intermediate, and possibly even expert, level.

    One of my concerns with this method is scalability. I think a lot can be said about performance here – though from my experience, browsers have less and less trouble with style hooks with practically each update.

    Another angle which should be considered is readability. One of the benefits with SMACCS, BEM, or OOCSS in general, is that developer(s) can quickly read and understand the codebase architecture, which is incredibly valuable– especially when it’s a large scale project.

    All of this to say, it depends on the project. This is certainly a great solution, but not an absolute one. I think a more well-rounded approach would be to use a variety of CSS selectors, they are all there for a reason, and serve a useful purpose(s). As with anything, we as developers must focus on using them wisely.

    Thanks for sharing, man! Really appreciate you sharing your perspective here.

  12. 40

    First, a minor correction for what I hope was a typo:

    Use a button element with type=”disabled”.

    I assume you meant to write:

    use a button element with disabled=”disabled”

    So with that out of the way, I would remind you that anchors are perfectly valid without [href] attributes. Particularly because they were designed to not only be links to other pages, but anchors to content within the page. Be sure to verify that an anchor that does not have an [href] attribute at least has an [id] or [name] attribute because then it would be a named anchor used for navigation within the page. Additionally, it could simply be a placeholder for where a link could be.

    Additionally, the link role is an extension of the button role. All links are buttons, not all buttons are links.

    • 41

      Heydon Pickering

      August 20, 2013 7:55 am

      Actually, the name attribute is obsolete (http://dev.w3.org/html5/markup/a.html) and any hyperlink that does not include an href is now considered a placeholder link, not an anchor. Any ID can be used for in-page navigation so there’s no need to produce spurious (placeholder) hyperlinks for the task.

      RE “type=disbaled”: Not so much a typo as me getting in a muddle :-) I saw the error and corrected straight away.

  13. 42

    I really love this article. OOCSS has never felt quite right to me. It’s always seemed overbearing and too difficult to properly implement in the majority of my projects, but I’ve never been presented with an alternative that seemed any better.

    That said, I’m not sure how this method would function in a large project. How do you style modules and wrappers and elements like divs, sections, and asides? Do you continue to rely on various role types?

    • 43

      One option is to use RDFa. You can use linked data attributes to semantically define and therefore style all sorts of things; articles, products, people, recipes etc etc. Could each one of these items be considered a “module”, I wonder?

      http://schema.org/docs/full.html

  14. 44

    Thank you for bringing attribute selectors back to the conversation. OOCSS has its benefits, but we’ve got to remember the foundation of semantic markup. I also appreciate your attention to accessibility. My testing shows mixed support for the generated content. Static strings tend to be announced by screen readers, but auto-generating content, such as counts, may not be annnounced.

    I wrote a similar article in 2006 to address the lang and hreflang attributes. http://www.last-child.com/attribute-selectors-to-provide-language-information/ I still use the CSS whenever building an international web site.

  15. 45

    Mustafa Kurtuldu

    August 20, 2013 8:30 am

    In using these type of selectors, do they cause any slow down with CSS rendering? Was looking for bench marks online but there doesnt seem to be an official “use x and everything will grind down”. The reason i ask is that i remember a dev telling me a while back that targeting tags slowed web pages down alot.

    Great post by the way.

  16. 48

    I love the entire concept of this article – it really goes with the way I’ve been trying to work for years now.

    Having said that, it entirely depends exactly how complex the design is!

    Lets take the buttons as an example.
    In a design, I have a red button, a green button and a blue button. Without classes, how could I add these different button colors?
    I’m guessing by using role?
    roll=”cancel” or roll=”submit” ?

    Great, but hold on, the ‘submit’ button in the design is larger than the ‘cancel’ button for some layouts, but not for others. So, do we use role on the parent container?

    Ok, that’s do-able, but what about grids?

    • 49

      If you’re putting something in a strict grid, the semantic solution is really to use a table, though they went through a pretty dark period.

  17. 50

    Great article! I’m working on a framework which allows users to write 99% classless, 100% semantic HTML. Seeing the sea of frameworks which use things like , makes me cringe, so it’s good to see others are working towards a web that organizes “thingnesses” better. I trust you don’t mind me using your Auticon idea on a larger scale!

  18. 52

    you should really make the font size in the comments !important so people can’t do this

  19. 53

    You’ve hit on something interesting, but missed a powerful extension of this: Using ARIA states such as aria-invalid to style feedback or output elements. This is something my team is currently working on integrating, and it’s made both our HTML and our CSS much clearer to new readers.

    • 54

      Spot on, Ted! I couldn’t agree more!

      Actually, I wanted to do a section dedicated to using ARIA state-related attributes as styling hooks but, alas, I got carried away with the other stuff.

      A basic example would be

      [aria-invalid="true"] {
         border: 2px solid red;
      }

      Another “state” example that springs to mind:

      [aria-expanded="false"] {
         height: 0;
      }
      
      [aria-expanded="true"] {
         height: auto;
      }

      Sounds like what you and the team are doing is pretty great!

      • 55

        Frederik Krautwald

        September 9, 2013 6:01 pm

        I would have loved if attribute key-values were reversed. E.g., instead of aria-invalid=”true”, we could have aria-state=”invalid”; and instead of aria-expanded=”true”, we could have aria-state=”expanded”. These could even be combined, like, aria-state=”invalid expanded”.

        This approach makes more sense from a development point-of-view. At least this approach was taken with the type attribute for input elements.

  20. 57

    I think it’s great that you’re reminding us that markup is the foundation; there is a useful vocabulary there and we must not forget it. A link without an href is dubious. The rel attribute is a useful enhancement.

    But just because we *can* use these attributes as styling hooks doesn’t mean we should. Your strongest argument is that when an element has certain properties, we can ensure that visual affordances are tied to those properties. That does make some sense. However, its usefulness is limited (your examples are almost all focused on micro-sematics, like `rel`) and in my experience, the general approach doesn’t scale to the variety of styling tasks we regularly have.

    The reason for the rise of OOCSS and kin is pragmatism: to make authoring complex sites and apps sane again. For a very simple example, the `header` and `footer` elements you cite are not global – they can be used in any sectioning element. I can have an article header, a section header, etc. Assuming they should look different (likely), how do I achieve that? If I isolate them by scoping (`article header p`), it’s harder to reuse this style elsewhere. I’m also likely to run into specificity problems the more I work this way.

    The notion that OOCSS precludes good semantic HTML simply doesn’t follow. It’s like saying paying attention to my wardrobe will make me forget to eat properly. I also don’t buy the idea that it’s too much work to maintain a more loosely coupled front-end architecture. In fact, it’s far *less* work to build a UI with an approach like SMACSS and some BEM-like naming conventions, than it is to hang all my selectors on just the document semantics.

    For example, if my design calls for more than one size or style of button (common), that’s easy:
    .Button { /* base styles */ }
    .Button--large { /* just the modifications */ }
    .Button--primary {}

    <button class="Button Button--primary" type="submit" value="foo">Submit</button>

    If I need a big call-to-action that looks like a button but is a proper link, no worries:

    <a class="Button Button--large" href="/foo">Buy now!</a>

    If I need a button that toggles my responsive nav and has minimal chrome (a <button> is appropriate since this is not a hyperlink) then I apply a different class designed for this appearance.

    <button class="BasicButton" type="button" data-action="toggle" data-target="#main-nav"><span class="Icon Icon--menu" aria-hidden="true"></span><span class="visually-hidden">Main Menu</span></button>

    The CSS (and HTML) for a project built this way is readable, almost self-documenting. Each selector has low specificity (unless you want otherwise). The styles are modular and extensible. All of this means less frustration during build and easier maintenance.

    “the premise that the class defines the element and not the HTML is deceptive.”

    The class doesn’t define the element, it defines _how it looks_. That’s it. That’s the idea. The reality is that these two things – though obviously related – aren’t *rigidly* bound. There is wiggle room, and often the needs of a particular design require more nuance than what document semantics provide.

    It’s true that appearance and content semantics shouldn’t radically diverge, but they should be loosely rather than tightly coupled. Which is exactly what where the class attribute comes in, and where OOCSS and friends provide a better way forward.

    • 58

      great comment

    • 59

      Heydon Pickering

      August 21, 2013 2:39 am

      I appreciate what you’re saying, Ryan, and your comment is perhaps the clearest explanation of the “modification” pattern I’ve read.

      I just don’t think individual apps need to be “self documenting” in quite this way. Toggle buttons, submit buttons, disabled buttons, readonly buttons, buttons that trigger popups, externally labelled buttons, buttons that contain images, pressed buttons, unpressed buttons etc are defined and documented by the W3C as interoperable, accessible standards. That’s a lot of buttons.

      a <button> is appropriate since this is not a hyperlink

      Yet it includes a curious attribute; data-target="#main-nav". Assuming #main-nav is a page fragment identifier, this attribute is essentially a reinvention of href="#main-nav".

      If you used <a href=”#main-nav”> then clicking the element would still “go” to the navigation when javascript is off. This would, arguably, be better progressive enhancement. It also speaks to the convention of having skip-to-nav links for use with screenreaders.

      If the <button> really isn’t for “going to the navigation” (just showing and hiding it instead) then a better hook would be aria-controls="main-nav". You have the same effect (and available name, minus the “#”), but aria-controls is exposed for use by assistive technology: It would be known in the accessibility layer that the button controls the navigation.

      • 60

        The “data-target” is most likely from Bootstrap. It isn’t for navigation, it is indicating where to find the relevant content for a component.

        I think this is where purely semantic HTML (and CSS) falls down. It is fine when you are creating just basic documents. Who wouldn’t want all article links styled the same way. But the most important reason for OOCSS and BEM is to style complex reusable components. So, what is semantically a button in one component can be an entirely different beast than a button in another component.

        Maybe the emerging web component standards will one day improve this, but until then we are stuck with creating complex user interfaces out of a few standard HTML tags and CSS.

  21. 61

    No all adherents of OOCSS are evil and go about using classes in detrement of semantic HTML elements:). Some of us actually do combine them.

    Nice examples of link styling based on attrute matching.

    Unfair assumption that OOCSS-er won’t guess to use his classes on element, poor thing. Still. What if you need to write CSS for an app that, according to specs., has say 20 button styles? Wouldn’t it be nice to write a .button class, apply it to element, or any element if needed, and then to write another 19 small classes, that will extend the .button class? Following your logic I can only do this 20 variants by assigning aria roles or preg matching some other button attributes. Which ties my CSS to my HTML so tight, that it defies the reason for having CSS at all.
    But may be I am missing something.

    • 62

      ups, comment field ate my buttons:) Replay:

      “Unfair assumption that OOCSS-er won’t guess to use his classes on BUTTON element, poor thing”
      and
      “Wouldn’t it be nice to write a .button class, apply it to BUTTON element, … “

    • 63

      I don’t mean to characterize OOCSSers as evil; just that there are shortcomings, limitations and contradictions inherent in the approach they choose to adopt.

      Who’s written a spec’ for an app that requires a total of 20 different button styles? What would each of them do?

      • 64

        ” just that there are shortcomings, limitations and contradictions inherent in the approach they choose to adopt”

        True. Also true for the approach you choose to adopt. That’s what I wanted to point out.
        Perfection is still out there:))).

        I don’t disagree with preaching what you practice, but I disagree with illustrating your way with essentially bad examples of what your “opponent” would do.
        Bad code choices are bad code choices – be they semantic or OO.

  22. 66

    Obviously a “button” must have hurt you in the past and I hope you find some comfort in the positive responses your article has had.

    Lots to think about and will help keep the importance of semantic markup at the forefront.

  23. 68

    It’s important to recognise that there is more than one valid approach to writing CSS, and there may be other considerations in a project that impact on the approach you choose. For example, are you working with back-end devs with limited CSS skills who will benefit from a CSS system that allows them to create new layouts with existing components?

    Yandex developed the strict BEM approach to cope with a massive codebase with many separate and interchangeable components, and they had the resources to develop tools to enable them to author that kind of code efficiently. From the point of view of maintaining clean OOCSS with a flat level of specificity this approach is the ideal, but isn’t very practical for most projects.

    The use of roles as style hooks is interesting and isn’t something I’d considered before. However there will always be a component that is semantically one thing but looks like something else. There are many valid cases for styling a regular link as a button, for example; or there might be one paragraph in the footer that needs to look like the paragraphs do in the header. Separation of concerns is a valid goal, ask any experienced programmer.

  24. 69

    Your examples of OOCSS are actually BEM / SMACSS style CSS organization. BEM and SMACSS use classes that describe elements’ relationships to each other, while OOCSS uses classes that describe the element’s visual attributes.

    The link/button and attribute selector recommendations are great stuff. I can’t say I agree with your preference for descendant selectors, but thanks for sharing your arguments for them.

  25. 70

    One of the major advantages of OOCSS in a large, team-built site is precisely that you can change the document semantics without rewriting your CSS. So you’re working on an h4 in some nested template, and when the parent template gets changed around and you discover it should be an h3, it doesn’t cost you twice as long to change it.

    Also, designs frequently call for hyperlinks, buttons, and even labels for radios or checkboxes, to look the same, and applying a class is a sane way to make that happen.

    Maintainability is important. I think this article overlooks that.

    • 71

      Heydon Pickering

      August 22, 2013 5:03 am

      Maintainability is important, but not as important as quality.

      The very nature of class-based frameworks is that they supplant quality with maintainability.

  26. 72

    I like that you’ve fronted more semantic coding of HTML documents and usage of attribute selectors in CSS, but I have a few concerns with the degree of your argumentation.

    1. “If it uses a button class, it should be a button — at least in the accessibility layer.”

    This is your opinion, yet most web designers will disagree with you. On most web sites, there are “buttons” that are links. Such as the famed Call to Action Button. A link doesn’t provide the same gravitas as a “button”. Users are quite used to this paradigm, although you’re right in pointing out that buttons should be buttons, so as not to confuse when it comes to forms and Javascript-activated buttons.

    My advice: use the button element if it’s not a link, and of course, use proper HTML when it comes to forms, using one of the different input types. If you’re using an empty href or an href with only # in it that fires off a Javascript event, you should probably be using the button element.

    2. Attribute selectors are something I started out using a lot, but then I scaled back and instead use them sparingly. The reason for this is two-fold; performance and maintainability.

    Every performance test I’ve seen shows that class selectors perform many degrees better than attribute selectors. If you’re concerned with performance down to the nitty gritty level, then this matters – and you should be. Remember, not everyone is running the fastest device with the most modern browser. If you can cut down the rendering time by using CSS selectors that perform better, why not do it?

    Also, as others have pointed out, when working with a larger team, or in a context where the code may suddenly change, relying on fragile things such as attributes is a no-go. It’s a clash of the theoretical and practical realms. A class name is more resilient, it can be applied to any element type, and it’s much more likely to survive the turbulent world of web development.

    Same goes for OOCSS, when it comes to relying solely on element names as selectors vs. giving them class names. In a lot of instances, you have no guarantee that the element selector will stand the test of time – that element can be suddenly changed to something else. The class name, however, will easily survive this because it’s only related to presentation, not function.

    Let’s say you have a document marked up with some headings, maybe inside some components that, for the time being, it makes sense to mark up with h2 headings. Now, at some point forward, the structure of the document may change, and now it might make more semantic sense for them to be h3 headings instead.

    You still want them to look the same, but you simply want to change from an h2 to an h3. Now what? Your element-based selector is broken – it will no longer apply. Yet if you used a class name, that will still be on the element, even if you changed from h2 to h3, and the style is maintained. And, shock and horror, you can name this class in a semantically meaningful way so that it’s easy to discern from the style sheet what you’re styling!

    However, in other cases, when the element is atomic in its presence in the context, then it’s safe to use an element selector rather than giving it a class name. An img element within a given context, for example, is the only way to mark up an image, so you are guaranteed that it will always be an img and can safely use that as your CSS selector. Same with elements such as time, etc.

    In summary, your article is well-intentioned, but it goes a bit too far in being polarizing against the use of the object-oriented CSS methodology. The better recipe is not going overboard with the OOCSS approach, and making sure to not add a bunch of class names when they aren’t really necessary. Advocating the almost complete disuse of class names is not only foolish and impractical, it negates the very theoretical foundation for their creation and existence.

    • 73

      I was just discussing the very h2/h3 problem you describe here with a work colleague.

      I think you’re being idealistic in the extreme to think that just changing an h2 to an h3 and letting the class take care of the styling would suffice. Unless of course you have a reset CSS that makes h2 and h3 have identical styles? Or you make sure you implement every style in your .some-heading (or whatever) selector such that it overrides the default styles for that element.

      Whichever way you do it, there will likely be more work to do than you want; and this suggestion I hear over and over that styling against classes necessarily makes something portable is just not true.

    • 74

      Heydon Pickering

      August 21, 2013 1:42 am

      On most web sites, there are “buttons” that are links. Such as the famed Call to Action Button.

      No, those are links that look like <button>s, but I take your point ;-)

      My advice: use the button element if it’s not a link, and of course, use proper HTML when it comes to forms, using one of the different input types. If you’re using an empty href or an href with only # in it that fires off a Javascript event, you should probably be using the button element.

      That’s what one of the revenge.css tests deals with (agreed).

      You still want them to look the same, but you simply want to change from an h2 to an h3.

      If they are different, why should they look the same? If it becomes an h3, it should look like an h3.

      And, shock and horror, you can name this class in a semantically meaningful way so that it’s easy to discern from the style sheet what you’re styling!

      And the most semantically “meaningful” (broadly understood) name for an h2 is “h2″, right? So I’d have to write <h2 class=”h2″>. I think you’re overthinking this.

      In a lot of instances, you have no guarantee that the element selector will stand the test of time – that element can be suddenly changed to something else.

      Or its class can be changed to something else. What’s your point?

      Advocating the almost complete disuse of class names is not only foolish and impractical, it negates the very theoretical foundation for their creation and existence.

      Sort of, but the other way round. First you investigate their theoretical foundation, then — if you see fit — you propose conditions for their disuse.

      My website doesn’t use any classes. Oh, except the dynamic disqus stuff I added the other day, but that’s all them.

      • 75

        My website doesn’t use any classes. Oh, except the dynamic disqus stuff I added the other day, but that’s all them.

        No offense meant, but your site is *super* simple. After reading numerous comments on this article and initially deciding your approach is fantastic, I’d have to now say it’s idealistic. George hits on this pretty well and I’m not sure you fully understood where he was coming from.

        If you saw some of the incredible designs I’m having to code up, it’s very likely trying to code them without using classes would be an exercise in frustration.
        I’m talking about layouts as complex as Google Mail here – effectively, online applications, rather than a simple blog.

        And these designs are *not* flawed, but rather, crafted with UX very much the key focus – there’s different buttons for *good* reason, not just on a design whim.

        By all means *limit* the amount of classes required to the bare minimum – absolutely.
        But also work in a modular fashion. An entire section with one semantically named class, that can be lifted out and dropped *anywhere* else on the website and *still* render as required.

        That is first prize.

        • 76

          Heydon Pickering

          August 21, 2013 5:02 am

          No offense meant, but your site is *super* simple.

          I take that as a compliment.

          There are few extremely complex UIs that need to be extremely complex. However, in the exceptionally rare case that 20 (as one commenter suggested) different button styles are required, classes are going to have to take some of the weight, I expect.

          This does not mean that the application should start out on OOCSS principles. The trick is in comprehensively normalizing your styles based on standard and/or functional semantics then extending the vocabulary of the design with classes only where you have no other choice. I think we agree on this?

          Starting out with OOCSS means you are starting out on a path where document semantics are not in focus. I believe this is not conducive to good practise.

          • 77

            I would actually argue the opposite — I think that the approach described in this article has a much greater tendency to cause designers to abuse document semantics.

            The reason we should care about writing clean, semantic HTML is to 1) deliver a good experience to our users, 2) to provide contextual information about the content to machines and screen readers, and 3) to make our source code easier to maintain.

            These three contexts — users looking at rendered HTML in a browser, machines interpreting the markup, and developers maintaining the source code — are different. They serve different purposes and have different needs. Information that is useful in one of these contexts is not necessarily useful in all contexts.

            For example, error messages are typically styled with red text. This provides immediate information about the nature of the message to an ordinary user who is looking at the rendered HTML in their browser. As their eyes move over the page, the red text gets their attention and lets them know that they might want to take a closer look because something bad just happened.

            In the context of a person skimming your website, this is helpful information. But what about the context of a person with a screen reader? If your error message is marked up with role=”alert”, JAWS is going to automatically read your message text when it’s generated — would they really benefit from (hypothetical) markup that caused JAWS to announce (eg.) “error” first? What about a machine that’s parsing your page — is there an actual use case for letting arbitrary bots know that they’re looking at an error message as opposed to a generic alert? Would you even want search engine bots to know that if they could?

            My point with this example is that the information we provide in a visual context does not always need to map one-to-one to the information we provide in others.

            When you add in things like element attributes, aria roles, and microdata, your focus shouldn’t be on what that information could mean to users who experience your page visually, which I think your approach encourages. Instead, you should be primarily thinking about what that will mean to the humans and machines who will actually be reading and interpreting that information as it is. In my view, CSS styles encourage better document semantics specifically *because* they keep the visual experience separate from the markup as understood by machines.

            Just adding in a bunch of microdata, attributes, etc. because you can and they make for convenient styling hooks isn’t “semantic”. Semantics are about meaning.

          • 78

            Just adding in a bunch of microdata, attributes, etc. because you can and they make for convenient styling hooks isn’t “semantic”. Semantics are about meaning.

            Absolutely. I’m not saying you should throw in inappropriate semantics to differentiate elements. That’d be worse than using classes to differentiate them. I’m saying “style it unusually if it is semantically unusual. If it isn’t semantically unusual it should look generic because it is generic”.

            This was the point of the hyperlink example: If it isn’t one of the many semantically (functionally) complex hyperlinks – if it doesn’t have special attributes or use specific URL patterns etc – then it should and can only inherit the basic styles. It just defers to “a”, defined somewhere way up in the cascade.

  27. 79
  28. 80

    As anyone that designs or codes webpages for a living as I do will know: You can’t create a webpage using just the ‘intelligent selector’ methods in this article. This would be a much better article if that were stated in the first paragraph. Instead, what’s stated is a quote from Louis Sullivan “Form follows function”. That may be true, but it’s an arbitrary position to state that the coded form is more important than, and takes precedence over the visual form.
    Webpages are made for humans to interact a computer using visual cues. If a button looks like a button, clicks like a button, and does what the user thinks it should, based on the overall appearance, cues and design of the page, then it is a button.
    Quack Quack

    • 81

      Heydon Pickering

      August 21, 2013 3:33 am

      Webpages are made for humans to interact a computer using visual cues. If a button looks like a button, clicks like a button, and does what the user thinks it should, based on the overall appearance, cues and design of the page, then it is a button.

      What if you’re blind? Or you’re a piece of software, like a browser, and you have to identify buttons?

      Moo! Moo!

      • 82

        I did not say that webpages should exclude blind, or otherwise less-enabled people, and my approach to building them is always accessible.
        I am saying that your approach will only be able to make a small percentage of the websites in existence.
        The web a visual medium (for most people), and while what you’re saying is compelling, well thought out, and very well written, it is not a solution. OOCS or other approaches are not ‘polyfills’, they’re useful tools in an imperfect medium.

  29. 83

    This is very useful information for some one who is really beginer in design modification and CSS. Thankd Nice share now I can modify things more easily…keep it up

  30. 84

    I think it’s obvious that the author doesn’t fully understand OOCSS and the implications of building and maintaining large scale web applications. I suggest you to try out http://inuitcss.com/

    • 85

      Abstractions abstractions abstractions… that is the way to write good, maintainable css.

      I’ve taken a lot from inuit over the past few months. It’s really improved my workflow. With a base set of classes I can build a prototype really quickly.

      With this approach of using ‘intelligent’ selectors, well.. good luck with that!

      • 86

        Heydon Pickering

        August 22, 2013 4:36 am

        With a base set of classes I can build a prototype really quickly.

        Or with a base set of element styles. The difference is that starting out by styling elements means that you cover (anticipate) dynamic CMS produced content as well. The conventions you create are also much more transferable between projects and teams because you are using standardized, recognised conventions as described in the W3C’s HTML specification.

        Too many developers think that being “semantic” is about how they organise and name their classes. Just because it can (often it doesn’t, in my experience) speed up development time, its not conducive to quality.

  31. 87

    As a relatively new web designer/developer this gave me a lot to think about. As I’m trying to use “best practices” and learning more as I go, I appreciate anything that will streamline my workflow while being consistent and hopefully more future-proof in the long run. This makes more sense to me than most other recommendations I have explored. Thanks for a thought-provoking, very useful article! Even the arguments against your methodology have made me reexamine my current practice. I will look forward to future articles.

  32. 88

    Hi,

    I understand the kind of beauty in this approach.
    What about “the grid”? What about images? Although I really love the idea that every button on a page looks the same, I have to design my page and format my images.
    Is there a new frontier? Where we seperate site layout/grid from site design/typography/…?

    • 89

      Heydon Pickering

      August 21, 2013 6:25 am

      RE “the grid”, I must say there’s not much harm in using classes on elements that have no semantic purpose – like <div>s working together in a grid layout.

      The real danger is in using classes on unsemantic elements (like div or span) instead of using the correct, browser and parser supported elements and attributes.

      For instance, you wouldn’t want to do <span class=”button”> because

      1. span is not read as “button” by the browser / screenreader
      2. span can’t be focused
      3. None of the functional attributes reserved for <button>s will work with span

      The various button examples in semantic-ui.com, for instance, are each based on <div>. Just for starters, thats not even the right “level” (inline/block).

      Thanks for reading.

      • 90

        What about “article class=’6_columns'”, where a non-semantic class is applied to a semantic element? There has to be a better way use a grid framework than embedding classes directly into the HTML. I haven’t tested this, but I think it could be done with SASS to inherit the properties of another class like so:

        article {
        @extend .6_columns;
        }

        • 91

          Heydon Pickering

          August 22, 2013 4:28 am

          Sure, that makes sense if you have enough elements likely to use 6 columns to justify abstracting the 6 column code into a component.

          The thing is, I don’t think I’ve ever coded anything to be divided into as many as 6 columns…

          • 92

            With foundation’s 12-column layout, it’s less about using all 12 columns, but rather about making columns out of the possible ratios. There have been times where I’ve used the 1/12th column style. Basically, deal with proportions instead of percents.

        • 93

          Better yet, use a SASS mixin library like Neat ( neat.bourbon.io ) to create your grid.

  33. 94

    What is the problem with classes? Seems to me like you are working really hard to avoid using them.

    You should really take a look at Harry Roberts talk – Breaking good habits.

    link: http://vimeo.com/44773888

    I would certainly be interested in seeming some proof of concept on a large website. Do you have any examples of large websites you’ve built using this approach.

    I write clean semantic markup, packed full of classes. I just don’t see what the worry about classes is.

    • 95

      Many thanks for the link to Harry’s talk. Especially as I start to work on larger and larger sites and more diverse teams, I appreciate his approach and find it to be very sound.

  34. 96

    A worthwhile exploration of an ideal worth striving for — Thanks for this thought-provoking article! Even as I find the coinage and application of “class” attributes useful where appropriate (I’ve spent going on 2 years developing a Mac OS X HTML editor, “TypeMetal”, whose key goals have included making that easier), I think we’re not terribly far from agreement that one should leverage HTML’s existing semantics wherever possible, augmenting (but not supplanting) them via class attributes only as a relative last resort. There are indeed many cases where existing element semantics and styling provisions are adequate, and it’s well to continually remind ourselves of them — the under-leveraged power of advanced CSS selectors included. Thank you for the worthwhile food for thought.

  35. 97

    Gabriele Romanato

    August 21, 2013 11:03 am

    There’s only a little problem with your article, perhaps insignificant to most of the new developers who started using CSS only after IE8. You mention the OOCSS approach. If you read carefully the CSS specifications and the Hakon Wium Lie’s thesis on CSS, you’ll notice that the very basic foundation of CSS is simplicity. Also, the aforementioned separation between structure, semantic and presentation is also implicit in the CSS design. There’s no OOCSS as many developers intend it, as well as there is no responsive design as many people today intend it. These features were already present in CSS, but only few developers used it (the hasLayout crew – John Gallant, Holly Bergevin, Ingo Chao, Bruno Fassino, Georg Sortun, Philippe Wittemberg – for example). These people created stunning demos and examples back in 2004/2005 when there were browsers like IE5 on the web. Also, Gianluca Troiani wrote one of the first guides for creating mobile layouts back in 2004 and the principles used were exactly the same as today – but in 2004 mobile browsers had almost no support to CSS. The point is that many best practices of today were first discovered and used several years ago but only today we use them because of the improved browser support. For the rest, your article is excellent.

  36. 99

    These selectors aren’t intelligent at all, they’re the ugliest I’ve ever seen.
    General idea of the article is unreasonably redundant, you’re speaking about the things you’ve no idea about.

  37. 101

    It’s always refreshing when someone avoids the hype-train and delivers some well-formulated sanity.

    Thanks!

  38. 102

    tl;dr – The author of this article would be a nightmare to work for :)

    Separating content from style is important, but this seems a little bit obsessive.

  39. 104

    I don’t know if you are aware, but your revenge.css rules are causing the comments section buttons to go all crazy-time in IE9.

  40. 105

    I really like the ideas you’ve presented. To me this goes back to some topics presented by others in the design community; ideas like progressive enhancement & mobile first. It seems simple to me that you start with your bare bones content, avoiding any unnecessary markup, attributes and fluff and you build up layer upon layer from that. If you can use elements, element hierarchy, and attribute selectors for the majority of your design AWESOME.

    To me the concepts expressed above work hand in hand with Atomic Design, which ultimately is a basis for platforms like BEM. You break your design elements down into irreducible complexity and then look at how those elements fit together in greater and greater complexity and how each level of complexity is styled and impacts the overall design.

    I think where a lot of people are challenged here is that it may require rethinking their design process. Many designers don’t necessarily have a workflow or a design language in mind, they do their designs by feel, or by some organic workflow that’s emerged over time. BEM and OOCSS were good about enforcing a process and instilling a design language. But then people think that those tools are the only way to express that design language, or that the language can’t be further simplified. They forget that they’re just tools in the toolbox.

    • 106

      Yes, well articulated.

      You break your design elements down into irreducible complexity and then look at how those elements fit together

      For me, this means working closely with basic HTML elements as they’re spec’ed rather than imposing extraneous “semantic” conventions on them.

      BEM and OOCSS were good about enforcing a process and instilling a design language. But then people think that those tools are the only way to express that design language

      Indeed, and it concerns me that one can adopt an entire design language for writing HTML web pages without even checking the spec’ to make sure any of it really works properly (ie. is accessible and future-proof etc.)

  41. 107

    A great read and inspiring article, I’m glad someone took the time to make a stand for focussing on semantics and what HTMl already has to offer “out of the box” and what seems to be overlooked by most frameworks.

    I do have some reservations about this idealistic approach though, as far as specificity goes.

    For example: how would you handle styling a paragraph in a blockquote in an aside element in a sidebar with this approach?

    “.sidebar aside blockquote p” ?

    Wouldn’t that be a little too specific?

    I think you overlook the fact that classes can be used very effectively as namespacing tools. To get back to my example, a class of “.pull-quote” could be used, reducing the selector to:

    “.sidebar .pull-quote p”.

    But what about other (block-level) items in my pull-quote, like ul’s? You surely won’t make a second rule selector for that I hope!

    That’s when classes become effective and where OOCSS takes the advantage:

    “.sidebar .pull-quote__content”.

    Voila, one class to target all children elements of a pull-quote, regardless of their mark-up. I think that’s an important point. Writing good CSS should be element-agnostic if possible. Yours is everything but that, which means a change in HTML will very likely mean a change in CSS.

    Someone brought up the h2/h3 example, which you misunderstood:

    “<h2 class=”h3>”: is actually a great example, as it just tells the browser: “hey, I know this is an h2 on a semantic level, but just show it like an h3 in this context”.

    Other than that, a good thought provoking read ;-)

    • 108

      Heydon Pickering

      August 23, 2013 1:59 am

      Some interesting remarks. Thoughts:

      For example: how would you handle styling a paragraph in a blockquote in an aside element in a sidebar with this approach?

      “.sidebar aside blockquote p” ?

      Wouldn’t that be a little too specific?

      I think you overlook the fact that classes can be used very effectively as namespacing tools. To get back to my example, a class of “.pull-quote” could be used, reducing the selector to:

      “.sidebar .pull-quote p”.

      That’s only going to be applicable in situations where you have blockquotes both directly in your sidebar and in your aside-in-your-sidebar and that these should be treated differently. I don’t think that’s going to happen very often. In most situations blockquote p will suffice – perhaps to increase blockquote paragraph font-size a little. I mean, how many different blockquote styles am I really going to need on one site?

      That’s when classes become effective and where OOCSS takes the advantage:

      “.sidebar .pull-quote__content”.

      Voila, one class to target all children elements of a pull-quote, regardless of their mark-up.

      Actually, that only targets “all children elements” of .sidebar that have the class .pull-quote__content. You’d have to go and put that on manually.

      To target all elements in .sidebar or .pull-quote, I’d use one of

      .sidebar * {
       ...
      }
      
      .pull-quote * {
       ...
      }
      

      And to target all direct children (which is often handy to avoid recursion)…

      .sidebar > * {
       ...
      }
      
      .pull-quote > * {
       ...
      }
      
      • 109

        Somehow I’m under the impression that you never work with complex designs. In my experience pull-quotes DO vary greatly depending on the context (e.g. main article content, sidebar, comments, in an impact/hero area, etc.

        These are very real use cases and since they are all “almost” the same in layout, they do require small changes in CSS (font-size, margins, padding, colors, etc.).

        This makes using classes much more effective and efficient, but I think I can she worth you if it comes to very simplistic use-cases ;-)

        Again, great read and I think it can be used very well for a solid layer of base styles.

        • 110

          Heydon Pickering

          August 23, 2013 6:10 am

          Thanks for your constructive comments.

          Yes, I personally like to push things, but I think an extensive normalization set used for generic styles and flow relationships is pretty essential.

  42. 111

    Matthew Schenker

    August 23, 2013 2:33 am

    Thanks for a very smart article! This is what makes web design/development so exciting: creative people making sure that we never “settle” into ways of doing things so much that we forget to analyze and question what we do, why we do it, and how we do it.

    This technique certainly has appeal to me. I especially see the benefits when paired with a PHP framework, as it allows dynamic use of CSS (I use the terrific ProcessWire CMF).

    But I wonder about more complex layouts. Are there any cases where this approach would take more CSS code to accomplish layouts, as compared with just using classes?

    This also gets me thinking about CSS pre-processors. I have never found a CSS pre-processor that felt quite right to me. I suppose the author would advocate against using them?

    Thanks again!

  43. 112

    Thanks for a great article. It reconfirms my belief, as a fairly unexperienced web developer, that this OO phase of CSS will and should come full circle in due time. I`m actually an experienced OO backend developer (7 years professionally), but I appreciate the declarative approach off CSS where we above all should strive for consistency and thus simplicity. CSS should be more than powerful enough when used as intended if we put the effort into simplifying our styles instead of …componentifying. I`m positive articles as good as this will help it come full circle faster.

  44. 113

    Thanks for a great article. It reconfirms my belief, as a fairly unexperienced web developer, that this OO phase of CSS will and should come full circle in due time. I`m actually an experienced OO backend developer (7 years professionally), but I appreciate the declarative approach off CSS where we above all should strive for consistency and thus simplicity. CSS should be more than powerful enough when used as intended if we put the effort into simplifying our styles instead of …componentifying.

    NB! The performance bickering is laughable at best. Have one ever experienced delays in the rendering of CSS? Is that why the web is slow? Just another bad excuse to herd.

    • 114

      Heydon Pickering

      August 23, 2013 6:07 am

      Haha, yes!

      HTML elements are components; there’s rarely any added “componentifying” (great word) required, except for grid scaffolding.

      Agreed on performance. Sometimes it’s a red herring, other times it’s a political device used by OOCSSers to justify standards-agnostic markup… At least when I neglect web standards its by accident/ignorance! :-P

  45. 115

    Koji Kumpulainien

    August 23, 2013 9:23 am

    Very informative article, and I agree with your mindset. Well done.

    I only had one issue, and it may be a little off topic, but relating to accessibility… Not all screen readers read css content. So in your example where you display error messages, those may or may not be accessible (depending on the version of the reader, and the browser being used). Was that a practical solution? Or just an example?

    Thanks!

  46. 116

    Thanks for the compelling thoughts, and providing some counter arguments to the current class trend. This is exactly how I used to construct my documents, but I’ve since switched to only using class hooks (BEM notation or some variant) in my CSS. No element or attribute selectors, just classes. It creates a loose coupling between HTML and CSS and it’s helped me with specificity issues, and reusing components.

    A few things:
    Components should be encapsulated and not leak their style information everywhere, modifying other elements they are not coupled to. If we didn’t have so many style variations, this wouldn’t such an issue, but we do. Plus, we can’t do this:

    <ProductHeader>
    <title></title>
    <price></price>
    </ProductHeader>

    How is that for semantic? But we’ve shed XML and classes tend to fill the void that would be possible with a custom spec.

    One last thing I’ll mention is that classes provide easy hooks for screen scrapers. Meta elements, role, data-, and rel attributes do help, but classes are easily accessible and more performant.

    • 117

      Heydon Pickering

      August 24, 2013 1:31 am

      It creates a loose coupling between HTML and CSS and it’s helped me with specificity issues, and reusing components.

      So it’s CSS to help you write better CSS. That’s great, but do you see the issue of self-referentiality? It sounds like you’ve cut CSS off from HTML so that you can manage the CSS better as its own concern.

      If we didn’t have so many style variations, this wouldn’t such an issue, but we do. Plus, we can’t do this:

      <ProductHeader>
      <title></title>
      <price></price>
      </ProductHeader>

      Have you heard of web components? If not, I’d give them a Google!

      • 118

        Yes, cut CSS off of the html. That is the exact point.

        CSS should be reusable and used within a system of components.

        It doesn’t matter your system you create / use as long as your CSS is organized.

        • 119

          Heydon Pickering

          August 27, 2013 9:23 am

          CSS should be reusable and used within a system of components.

          Yes. That system of components is called “HTML”.

  47. 120

    Brilliant, thank you for (finally) making the very important distinction between function and form so clear. It’s like there was always something not quite right about the big HTML & CSS picture for me, but I just couldn’t quite articulate it as brilliantly as you have in this article.

  48. 122

    I completely disagree.

    Class-based markup is a way to restore sanity to complex web projects.

    Elements can be all over the place. An input with type submit, a link and a button element can have classes applied to make them appear the same.. as a button.

    Before class-based markup was the standard, CSS was a tangled web of element selectors, class selectors and id selectors. It makes CSS complex, messy are difficult to debug.

    You don’t make a good case for abandoning the standard..

  49. 123

    BRAVO ! (especially for the <a>/<button> part)
    Use HTML tags for the reason they are made for. Stop using <a> tag for every single interactive elements! This is what I am trying to explain everyday in my job.
    The best article, I read for months. Thanks!

  50. 124

    Interesting article. But I think there’s room for both approaches! I’d argue that you should aim to get as much as possible of your CSS done in the style you describe – what you are basically doing is creating executable “brand guidelines” for your app.

    But when it comes to needing specific styling in certain contexts or for certain components, judicious use of classes feels like the way to go.

  51. 125

    No one else has done it yet, so here it is… your rules as a SCSS mixin. https://gist.github.com/jhogue/6370800

    I started using it to test sites while in development, along with a modified version of Holmes which I have been using for a bit now. http://www.tomato-root.com/sandbox/holmes/

  52. 127

    Lewis Cowles (@LewisCowles1)

    September 5, 2013 5:02 am

    Well in an abstract sense I totally agree, but are you suggesting we should (even if we do it deliberately), never break these rules? It just sounds a bit like a grammar Nazi turned web designer turned blogger’s article. Sure We all 100% get that while things are not working in 100% of browsers we need to support, we occasionally do bad things like

    (a.l.a bootstrap)
    <a href=’/controller/method/5′>Something</a>

    instead of

    (a.l.a standard HTML5)
    <form action=’/controller/method/5′ method=’post’>
    <button>Something</button>
    </form>

    really if we take things this far, as far as I am concerned we are no better than grammar Nazi’s that dictate on the English dialects, language is a dynamic, changeable thing, embrace it, have fun and I hope a distilled version of this is taken up everywhere…

    • 128

      The original solution is better in just about every conceivable way.

      A “grammar nazi” would prefer it.

  53. 129

    Just would like to thank you Heydon, I’ve always found the accepted CSS “classitis” to be ugly, and just bad, especially since Sass and LESS which introduced nested selectors.

    And I *never ever* witnessed CSS performance issues appearing after writing CSS more semantically. Bringing up the “performance” argument is a case of premature optimization, “the root of all evil”.

    • 130

      This method is too idealistic for me and though it can work is too unreliable to ever implement. My main gripe is related to the h1/h2/h3 issue. If my page headers are marked up with for example h2’s and are styled simply with the h2 type selector what happens if I need to change half of these h2’s to h3’s? You could add the h3 type selector to the CSS but what if I have a bunch of h3’s that are styled entirely different? Surely it is much more future proof to just say .header uses a certain set of CSS rules and .header__alt (or however you markup your classes) uses another.

      Using type selectors means you are relying on your content to be of a certain nature in order to make it look a certain way. Is that not tying content to presentation?

  54. 131

    Heydon, this article articulated very thoroughly an idea that’s been under the surface of my mind for a while, but not fully fleshed out until now. Judging by the comments it looks like many others feel the same way.

    With that said, while this approach is clearly ideal, in practice, I am encountering some challenges that I wanted to share with you, and hopefully get your thoughts on. I am currently developing a WordPress theme and attempting to put these ideas to practice. Here are a couple of simple examples that illustrate the challenges I’m having with abandoning classes:

    1) WP normally adds a series of classes to the body tag, identifying the type of page you are on: single, archive, page, etc. Let’s say I wanted to do something as simple as use a particular background image on pages and a different one on posts – how could I do this without these classes?

    2) WP has different post formats: audio, video, normal, etc. Let’s say on my blog index, I would like to include a small icon corresponding to the post format on the top right of each post’s article element. How could I do this without classes?

    I’m sure that you can imagine many other examples like this. My issues have mostly been about how to accomplish certain design tasks with this approach. It’s not always as simple as having an icon on a link based on the filetype. There are more macro issues that need to be dealt with which classes are very useful for. How can we get around this?

    Thanks!

  55. 132

    A common design element is to highlight the link in the navigation for the current page. How would one do this without classes? Is there a semantic attribute indicating that a link points to the current document?

    Granted, it’s pointless to have a link to the currently viewed page in your nav, but sometimes unavoidable. Also, consider a dropdown menu of links. If you are viewing a child page you might want that child link to be highlighted as well as the parent link. This seems even less doable semantically and without classes.

    Any ideas?

    • 133

      tabindex attribute

    • 134

      I have been discussing this issue with Leonie Watson.

      Website navigation has long been lacking a semantic way of saying “you are here”. She is proposing a new ARIA property called “aria-current” which will announce the link in a navigation block which represents the current page or – alternatively – the current “step” in a process such as a multi-page form etc.

      It would probably announce “current page link” in the first of these scenarios.

      • 135

        that would be an excellent addition. for now i’ve decided to remove the link and simply output the text in a span when on that page instead – since it is not necessary to link to the current page and it could also be styled differently.

  56. 136

    One recurring theme I’m seeing in the author’s comments is performance is secondary. I have a serious issue with that and it is a trend that has been going on for quite some time and really needs to stop.

    I’m not arguing that trying to create semantic code is a bad thing, and I fully agree on proper markup particularly when it comes to accessibility. But where I draw the line is suggesting that performance be secondary to semantics. With the trend towards mobile first performance is paramount and anywhere you can eke out a bit more speed is good.

    The author is making assumptions about the user it seems, and again a trend that is frustrating. Everyone has broadband now, everyone has fast computers now… not true. My office connection is quite slow by today’s standards and it’s VERY obvious how few developers think performance is an important factor these days when I browse the web. Many pages take upwards of 30 seconds just to start appearing.

    Some of the reasoning is suspect too. Portable CSS? Really? You do that a lot do you? This has to be the biggest non-issue used as reasoning in the article.

    Overall it was well written and a lot of the bits made sense, it was more the arguments supporting it in the comments I have issue with. I’ve learned some things and I appreciate that but I can’t see myself writing complex selectors instead of classes any time soon just for the sake of semantic code at the expense of even a tiny bit of performance or clarity.

    • 137

      One recurring theme I’m seeing in the author’s comments is performance is secondary.

      Absolutely not. I have been clear that I think performance is really important. That’s why I don’t waste any time chasing down performance issues that don’t exist, like selector performance.

  57. 138

    I’m writing a semantic CSS framework that takes a lot of these ideas and concatenates them into a single framework: https://github.com/herrshuster/Semantic-CSS-Framework . Any input is appreciated

  58. 140

    This method is too idealistic for me and though it can work is too unreliable to ever implement. My main gripe is related to the h1/h2/h3 issue. If my page headers are marked up with for example h2′s and are styled simply with the h2 type selector what happens if I need to change half of these h2′s to h3′s? You could add the h3 type selector to the CSS but what if I have a bunch of h3′s that are styled entirely different? Surely it is much more future proof to just say .header uses a certain set of CSS rules and .header__alt (or however you markup your classes) uses another.

    Using type selectors means you are relying on your content to be of a certain nature in order to make it look a certain way. Is that not tying content to presentation?

  59. 141

    Nice article. How would you select elements with different themes like “default button”, “primary button”, “action button”, etc.?

  60. 142

    I like this article ,thanks a lot!

  61. 143

    What a great article! I fear that unfortunately, those who need it the most won’t spend the time on an article of such (understandable) length. The Web is suffering at the hands of a vast majority who want to churn out code without thinking about why the web was created and not take the time to read these “painful” blog posts. (It’s a lot easier to be sold some new, easy to digest piece of hipster library that will make all your things “lightwieght” and cure cancer, than to be told it’s going to take time to think, appreciate and design your markup).

    Another benefit to “pure” HTML is that it functions well as an API – in fact, a semantic HTML document is more REST than any JSON API (they’re all RPC, across the board) that I’ve seen.

    Just recently I read that Gawker banned strikethrough markup from their articles, because it was “HTML styling”. So sad (not that I care much for the site, but it’s perpetuating the problem).

    What do you think about this?

    <a rel="first" …
    <a rel="next" …
    <a rel="page 3" ..

    and so on.

    In this case I feel like the class is an interesting way to accomplish this, though "first page" is just as an appropriate rel. An aside class=”recent news” seems perfectly semantic too. So class isn’t always evil. It’s tough when you want to mash-up several microformats on a single page. Each component might be loaded separately, with it’s own HTTP request (and perhaps content type), but there is a risk of collision if they are’t classified *somehow* – just not with “presentation” nonsense. I was severely disappointed by Semantic UI. Agreed: there is no such thing as “semantic CSS”, rather, I thought it was going to be a library that *understood* this and got out of your way. I was hopeful at first, because they claim on their homepage that you can use “any element”. Their dropdown “enhancement” says differently.

    Also, that link to nicolasgallagher.com seriously calls in to question whether he understands the basic principles of HTML/The Web. I mean, great job with normalize.css, but seriously, what the heck?

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top