Michael Douglas Brett - Web Development

Hi, I'm Michael. I'm a front-end web developer based in the UK. This is my site.

What Are The Differences Between Classes And IDs?

FEDIQ CSS

Mar 16th 2016

Another week(ish), another question from the Front End Developer Interview Questions. The original question was: 'What is the difference between classes and IDs in CSS?', but I'm going to stray slightly out of bounds and talk about IDs and classes in terms of HTML and the DOM as well. There are two reasons for this:

IDs

IDs are global attributes, which means that they can be used on any HTML element. An ID is the unique identifier for an element, so it can only be used once. Don't do this:

<ul>
  <li id="listItem">Item 1</li>
  <li id="listItem">Item 2</li>
</ul>

Interestingly, according to the spec:

The value must not contain any space characters... There are no other restrictions on what form an ID can take; in particular, IDs can consist of just digits, start with a digit, start with an underscore, consist of just punctuation, etc.

which means this is valid:

<a href="https://www.somelink.com" id="¯\_(ツ)_/¯">Some link</a>

IDs can be targets for styling, scripting and used as fragment identifiers (for anchor tags, in urls etc). The DOM api method Document.getElementById() will return a reference to the element, provided that the ID exists at the time the method is called (otherwise it will return null).

The ID selector in CSS can be written as follows:

ul#myList
#myList
*#myList

The last two formulations mean pretty much the same thing.

Classes

Also global attributes, the biggest difference between classes and IDs is that you can have as many values as you want in a space separated list. Plus, class attribute values are reusable - so you can do this:

<ul class="productList productList__saleItems">
  <li class="listItem">Item 1</li>
  <li class="listItem">Item 2</li>
</ul>

In the ID attribute specification, there is no requirement for the value to have any meaning - but this is not best practice when it comes to classes:

...authors are encouraged to use values that describe the nature of the content, rather than values that describe the desired presentation of the content.

So don't do something like this...

<button class="green">Submit form</button>

...because this could be in your stylesheet:

button.green {
  background-color: blue;
}

However unlikely it is that you would write such a rule, it is easy to see why the potential for it to be written could cause problems. Semantics and class-naming (in fact naming in general) is a huge topic that would derail this post (and probably crops up later in the FEDIQ set). If you want to read about that instead of classes vs. IDs, this is a good article on the subject: https://css-tricks.com/semantic-class-names/.

In the snippet above, I used the . to signify a class (.green). Up until I started mooching around in the spec, I thought that was the only way to do it (it's the only way I'd ever seen it done). It turns out that the . notation is equivalent for the longer selector notation, *|E[class~=value]. There are quite a few selector notation rules (which, in hindsight, was obvious given :pseudo-class et al) and listing them all here would probably be too much duplication, but if you fancy a deep dive into the spec (who wouldn't?) - follow this link.

While using Document.getElementById() returns a reference to the element, using Document.getElementsByClassName() in your scripts returns an array-like, live NodeList of all the elements with a matching class attribute. "Array-like" because a NodeList isn't actually an array, although it resembles one at first glance, the methods you would expect an array to have are missing (for e.g forEach).

Back to the original question

Aside from the selector differences outlined above, what really separates IDs and classes in CSS (which is what the FEDIQ asks) is their specificity value. Specificity is how browsers work out how styles should be applied to elements. All things being equal, styles are applied via the cascade and the last item in the cascade wins. For example...

p {
  color: black;
}

// ... further CSS

p {
  color: red;
}

... the paragraph text will be red, but it's more complex when multiple selectors come into play. There is a formula for how the specificity value of selectors is calculated, but the main thing to know is that IDs are of higher value than classes.

Take this bit of rough HTML:

<div id="wrapper">
  <!-- A bunch of HTML -->
  <div>
    <p>Some text<p>
    <p class="standoutText">Pay attention to this line!</p>
  </div>
  <!-- more HTML -->
</div>

If the CSS for this is as follows...

#wrapper p {
  color: black;
}

// ... further CSS

p.standoutText {
  color: red;
}

... you might end up scratching your head as to why your line with the standoutText class is not displayed in red text. This is an overly simplified illustration of real problems at scale. Huge codebases with multiple authors run the risk of building in specificity gotchas, if safeguards are not put in place (like limiting - or even outright banning - the use of IDs for styling). You ultimately want to keep your specificity graph as smooth as possible.

There's a lot more to be said about classes and IDs, but I think that's enough for one post. I encourage anyone interested in the subject to take a deep dive into the specs. You are guaranteed to learn something.

Next: 'Explain event delegation'.