How to Order CSS Selectors

Published on January 30, 2013 (↻ June 10, 2024), filed under (RSS feed for all categories).

This and many other posts are also available as a pretty, well-behaved ebook: On Web Development. If the optimization of CSS is of particular import to you, I’ve collected several concepts in a brief book: CSS Optimization Basics.

There are a number of ways to write style sheets. The domain of style guides, many of them go into some detail. What I, despite my work on a number of guides, including the Google HTML and CSS style guide, have so far missed, is a conclusive reference to sort selectors and rules. I’ve mostly operated with a rough sketch, but that sketch is rough as it’s far from being comprehensive.

In this document I’m proposing an order for selector and rule sorting, for anyone who has a need for more structure. A firm believer in the usefulness of alphabetical sorting of declarations, I don’t deem alphabetical sorting particularly useful for selectors. Unfortunately that suggests a slightly more complicated set of rules.

I’m writing for inspiration; please share your thoughts. (I might be slow but am sure to respond.)

Contents

  1. Specificity Has the Right of Way
  2. Part I: General Sorting
    1. By Purpose
    2. By Importance
    3. From Generic to Specific
  3. Part II: Element Sorting
    1. Universal
    2. Document
    3. Metadata
    4. Sectioning and Structuring
    5. Headings
    6. Lists
    7. Media
    8. Forms
    9. Tables
    10. Phrasing
    11. Misc
    12. Attributes
  4. Examples
    1. High-Level Sorting
    2. Example Style Sheet
  5. Working With This Sorting
  6. Update (February 7, 2014)
  7. Update (September 24, 2023)

Specificity Has the Right of Way

Before we begin, note that the location of a rule can make a difference: If two declarations have the same weight, origin, and specificity, the latter specified wins. Always keep this in mind when ordering style sheets, especially when moving a rule from one end of a style sheet to the other. Rare as they are, sometimes you will need to make exceptions.

Part I: General Sorting

The following are high-level sorting ideas. They may overlap. This sorting applies to selectors for any given rule, rules themselves, and also sections, that is, groups of rules (consider using comments to mark sections).

1. By Purpose

First, group conceptually: What are rules and sections about? All the general site styling should be in one section or module. Grid styling in another. Navigation handling in yet another.

If a rule conceptually belongs to two or more groups, consider going by the first selector, or spawning a “General” or “Misc” section.

2. By Importance

Then, sort by importance. More important rules and sections should come before less important ones.

3. From Generic to Specific

Next, sort by impact: What affects the higher number of elements, and higher-level elements, should come before the more specific selectors. Although you could have the same number of elements on which either selector matches, this applies to the different types of selectors, too: Go from type selectors over class selectors over attribute selectors (that are not targeting @class or @id) to ID selectors.

For sequences of simple selectors, or “complex” selectors like p em or .error strong, sort by the first simple selector, then the next, &c.

❧ When sorting rules, use the first selector of each rule to determine the rule’s location, both within a section and within the style sheet. Do this after all the rules’ selectors have been sorted. That also means that when writing something like section.warning instead of .warning, the position of the rule within the style sheet could change, as you’d end up sorting by the element (section) and not the class (.warning).

Part II: Element Sorting

This is a suggestion how to sort specific selectors precisely. Similar to the high-level sorting, it applies to all selectors, per rule, and per section.

The list features selectors for elements from HTML [as of November 2022]—on request I could add all the other elements. In parentheses: elements that are normally hidden and not normally styled. In square brackets: non-HTML elements.

1. Universal

  • *
  • Pseudo classes (if not applied to specific elements)
  • Pseudo elements (if not applied to specific elements)

2. Document

  • html

3. Metadata

  • (head)
  • (title)
  • (base)
  • (link)
  • (meta)
  • (style)
  • (script)
  • (noscript)
  • (template)
  • (slot)

4. Sectioning and Structuring

  • body
  • header
  • footer
  • nav
  • main
  • article
  • aside
  • section
  • p
  • pre
  • blockquote
  • figure
  • figcaption
  • address
  • details
  • summary
  • search
  • div

5. Headings

  • hgroup
  • h1
  • h2
  • h3
  • h4
  • h5
  • h6

6. Lists

  • ul
  • ol
  • li
  • dl
  • dt
  • dd
  • menu
  • [menuitem]

7. Media

  • canvas
  • object
  • embed
  • img
  • picture
  • audio
  • video
  • [(param)]
  • (source)
  • track
  • map
  • area
  • [svg]
  • [math]
  • iframe

8. Forms

  • form
  • fieldset
  • legend
  • label
  • input
  • button
  • select
  • optgroup
  • option
  • datalist
  • textarea
  • output

9. Tables

  • table
  • caption
  • colgroup
  • col
  • thead
  • tfoot
  • tbody
  • tr
  • th
  • td

10. Phrasing

  • a
  • strong
  • em
  • b
  • i
  • u
  • s
  • sup
  • sub
  • small
  • abbr
  • dfn
  • mark
  • del
  • ins
  • q
  • cite
  • data
  • progress
  • time
  • meter
  • code
  • var
  • samp
  • kbd
  • [keygen]
  • bdi
  • bdo
  • ruby
  • rt
  • rp
  • span

11. Misc

  • hr
  • (br)
  • (wbr)
  • dialog

12. Attributes

  • .class
  • #id

The suggestion is based on experience and well some common sense, yet it’s indeed a little arbitrary. We have to start somewhere.

Examples

High-Level Sorting

We can picture high-level sorting by transforming a few random rules from

#bio {}
#bio, p {}
.authors {}
html {}
#gallery, .authors {}

into

/* Comes first because of purpose: */
html {}
/* Reversed order to go from generic to specific; also more important: */
p, #bio {}
/* Reversed order to go from generic to specific; moved to allow grouping with other .authors rule: */
.authors, #gallery {}
/* Grouped with .authors/#gallery rule, and following after because more specific: */
.authors {}
/* Comes last because it’s most specific: */
#bio {}

Example Style Sheet

Here’s a complete example using World’s Highest Website’s [2013] default style sheet, following the rules of this document as well as the Google HTML and CSS style guide:

@import url(//fonts.googleapis.com/css?family=Droid+Sans:400,700);

@media screen {

  * {
    margin: 0;
    padding: 0;
  }

  html {
    background: #000;
    color: #ccc;
    font: 87.5%/1.7 'droid sans', optima, arial, sans-serif;
    text-align: center;
  }

  body {
    margin: 1em 0;
  }

  h1,
  h2 {
    font-size: 1em;
    font-weight: normal;
  }

  h1 {
    background: url(../../media/logo.jpg) no-repeat;
    height: 366px;
    text-indent: -999em;
    width: 620px;
  }

  h2,
  p {
    margin: 0 .5em;
  }

  p + p {
    text-indent: 1em;
  }

  p#ref {
    background: url(../../media/end.jpg) no-repeat bottom center;
    margin: 1.5em 0 0;
    padding-bottom: 179px;
  }

  ul {
    margin: .5em 0 .5em 1.5em;
  }

  ul#lang {
    list-style: none;
    margin: .5em 0 1em 1.5em;
  }

  ul#lang li {
    display: inline;
  }

  a,
  strong,
  em,
  kbd {
    color: #fff;
  }

  strong {
    font-size: 1.3em;
    line-height: 1.0;
  }

  em {
    font-style: normal;
  }

  kbd {
    font-family: 'droid sans', optima, arial, sans-serif;
  }

  #show {
    margin: auto;
    text-align: left;
    width: 619px;
  }

  #whws {
    background: url(../../media/tape.gif) repeat-y top center;
    font-size: 100cm;
    height: 4734em;
    line-height: 1.0;
    margin: 42px 0;
  }

  #whws + div {
    position: relative;
  }

}

/* Print rules omitted */

Working With This Sorting

Independent of the examples, I’m still thinking how to best demonstrate work with this rule set. First, it’s not trivial, and second, it depends on your preferences. You could use it to determine the location of each rule while writing your style sheets. You could take care of sorting by sections first, to then sort the rest. You could sort once you’re done with everything. You could also just use the selector order as proposed in part II. I welcome thoughts on whether any how-to on this would be useful, and on how to make that how-to itself most useful.

Thanks Tony Ruscoe for reviewing and helping to improve this article.

Update (February 7, 2014)

This order did not so far cover RTL selectors. [If the later logical properties don’t already answer any sorting questions, and until I get to update the article,] I suggest a “local” placement as with

#example {
  text-align: left;
}

[dir=rtl] #example {
  text-align: right;
}

Update (September 24, 2023)

This article should and may be updated.

One of the more interesting gaps I observed is around the :is() and :where() pseudo-classes, which I’ve found to best be handled by ignoring them. That is, for the purposes of this selector order, :is(a, b) would be treated as a, b, and be sorted accordingly.

(I also tend to use :is() and :where() only once there are at least three selectors to be condensed by them, but this is an early rule that I have to formalize somehow, before considering it for an update as part of this document.)

Was this useful or interesting? Share (toot) this post, or support my work by buying one of my books (they’re affordable, and many receive updates). Thanks!

About Me

Jens Oliver Meiert, on September 30, 2021.

I’m Jens (long: Jens Oliver Meiert), and I’m a frontend engineering leader and tech author/publisher. I’ve worked as a technical lead for companies like Google and as an engineering manager for companies like Miro, I’m close to W3C and WHATWG, and I write and review books for O’Reilly and Frontend Dogma.

I love trying things, not only in web development (and engineering management), but also in other areas like philosophy. Here on meiert.com I share some of my views and experiences.

If you want to do me a favor, interpret charitably (I speak three languages, and they can collide), yet be critical and give feedback for me to learn and improve. Thank you!

Comments (Closed)

  1. On January 30, 2013, 16:18 CET, Jean-Philippe Martin said:

    Very helpful. Let’s hope a common “standard” emerge.

  2. On February 4, 2013, 14:33 CET, Are Nybakk said:

    Good to see that others are seeing this problem. I have countless times had to deal with terrible CSS messes being left by others.

    I agree with your general sorting rules. There are times the answer isn’t quite clear, though, but that’s fine if you at least organize the rules in a modular manner. I personally prefer dividing all my CSS rules into separate style sheets and combine them in the production environment.

    Even though looseness is a good thing in general, it presents problems. CSS is a bad technology, plain and simple, just like HTML, but that’s another discussion.

  3. On July 29, 2013, 18:44 CEST, Cesidio DiBenedetto said:

    At the moment, I am encountering this same problem while trying to fix/re-factor a custom library. I have been thinking along the same lines as you and hope that some general consensus can be reached that allow for a “standard” to be arrived at, as Jean-Philippe Martin commented.