Title
Article content.
OverviewCSS is really good at many things, but it’s really, really good at two specific things: selecting elements and styling them. That’s the raison d’être for CSS and why it’s a core web language. In this guide, we will cover the different ways to select elements — because the styles we write are pretty much useless without the ability to select which elements to apply them to.
The source of truth for CSS selectors is documented in the Selectors Module Level 4 specification. With one exception (which we’ll get to), all of the selectors covered here are well-covered by browsers across the board, and most certainly by all modern browsers.
In addition to selectors, this guide also looks at CSS combinators. If selectors identify what we are selecting, you might think of combinators as how the styles are applied. Combinators are like additional instructions we give CSS to select a very particular element on the page, not totally unlike the way we can use filters in search engines to find the exact result we want.
Quick referenceCommon Selectors
/* Universal */* { box-sizing: border-box;}/* Type or Tag */p { margin-block: 1.5rem;}/* Classname */.class { text-decoration: underline;}/* ID */#id { font-family: monospace;}/* Relational */li:has(a) { display: flex;}
Common Combinators
/* Descendant */header h1 { /* Selects all Heading 1 elements in a Header element. */}/* Child */header > h1 { /* Selects all Heading 1 elements that are children of Header elements. */}/* General sibling */h1 ~ p { /* Selects a Paragraph as long as it follows a Heading 1. */}/* Adjacent sibling */h1 + p { /* Selects a Paragraph if it immediately follows a Heading 1 */}/* Chained */h1, p { /* Selects both elements. */}
General SelectorsWhen we talk about CSS selectors, we’re talking about the first part of a CSS ruleset:
/* CSS Ruleset */selector { /* Style rule */ property: value;}
See that selector? That can be as simple as the HTML tag we want to select. For example, let’s select all <article> elements on a given page.
/* Select all <article> elements... */article { /* ... and apply this background-color on them */ background-color: hsl(25 100% 50%);}
That’s the general process of selecting elements to apply styles to them. Selecting an element by its HTML tag is merely one selector type of several. Let’s see what those are in the following section.
Element selectorsElement selectors are exactly the type of selector we looked at in that last example: Select the element’s HTML tag and start styling!
That’s great and all, but consider this: Do you actually want to select all of the <article> elements on the page? That’s what we’re doing when we select an element by its tag — any and all HTML elements matching that tag get the styles. The following demo selects all <article> elements on the page, then applies a white (#fff) background to them. Notice how all three articles get the white background even though we only wrote one selector.
CodePen Embed FallbackI’ve tried to make it so the relevant for code for this and other demos in this guide is provided at the top of the CSS tab. Anything in a @layer can be ignored. And if you’re new to @layer, you can learn all about it in our CSS Cascade Layers guide.
But maybe what we actually want is for the first element to have a different background — maybe it’s a featured piece of content and we need to make it stand out from the other articles. That requires us to be more specific in the type of selector we use to apply the styles.
Let’s turn our attention to other selector types that allow us to be more specific about what we’re selecting.
ID selectorsID selectors are one way we can select one element without selecting another of the same element type. Let’s say we were to update the HTML in our <article> example so that the first article is “tagged” with an ID:
```
``
Now we can use that ID to differentiate that first article from the others and apply styles *specifically* to it. We prepend a hashtag character (#`) to the ID name when writing our CSS selector to properly select it.
/* Selects all <article> elements */article { background: #fff;}/* Selects any element with id="featured" */#featured { background: hsl(35 100% 90%); border-color: hsl(35 100% 50%);}
There we go, that makes the first article pop a little more than the others!
CodePen Embed FallbackBefore you go running out and adding IDs all over your HTML, be aware that IDs are considered a heavy-handed approach to selecting. IDs are so specific, that it is tough to override them with other styles in your CSS. IDs have so much specificity power than any selector trying to override it needs at least an ID as well. Once you’ve reached near the top of the ladder of this specificity war, it tends to lead to using !important rules and such that are in turn nearly impossible to override.
Let’s rearrange our CSS from that last example to see that in action:
/* Selects any element with id="featured" */#featured { background: hsl(35 100% 90%); border-color: hsl(35 100% 50%);}/* Selects all <article> elements */article { background: #fff;}
The ID selector now comes before the element selector. According to how the CSS Cascade determines styles, you might expect that the article elements all get a white background since that ruleset comes after the ID selector ruleset. But that’s not what happens.
CodePen Embed FallbackSo, you see how IDs might be a little too “specific” when it comes to selecting elements because it affects the order in which the CSS Cascade applies styles and that makes styles more difficult to manage and maintain.
The other reason to avoid IDs as selectors? We’re technically only allowed to use an ID once on a page, per ID. In other words, we can have one element with #featured but not two. That severely limits what we’re able to style if we need to extend those styles to other elements — not even getting into the difficulty of overriding the ID’s styles.
A better use case for IDs is for selecting items in JavaScript — not only does that prevent the sort of style conflict we saw above, but it helps maintain a separation of concerns between what we select in CSS for styling versus what we select in JavaScript for interaction.
Another thing about ID selectors: The ID establishes what we call an “anchor” which is a fancy term for saying we can link directly to an element on the page. For example, if we have an article with an ID assigned to it:
```
``` …then we can create a link to it like this:
<a href="featured">Jump to article below ⬇️</a><!-- muuuuuuch further down the page. --><article id="featured">...</article>
Clicking the link will navigate you to the element as though the link is anchored to that element. Try doing exactly that in the following demo:
CodePen Embed FallbackThis little HTML goodie opens up some pretty darn interesting possibilities when we sprinkle in a little CSS. Here are a few articles to explore those possibilities.
**Article** on Jun 23, 2020 On Adding IDs to Headings selectors Chris Coyier **Article** on Aug 24, 2011 When (and when not to) use an anchor tag? selectors Chris Coyier **Article** on Jan 5, 2015 Link in Header? Or Header in Link? selectors Chris Coyier **Article** on Jan 17, 2023 Hash Tag Links That Don’t Headbutt The Browser Window selectors Chris Coyier **Article** on May 7, 2019 You can get pretty far in making a slider with just HTML and CSS selectors Chris Coyier **Article** on Apr 8, 2021 The `ping` attribute on anchor links selectors Chris Coyier Class selectors**Class selectors** might be the most commonly used type of CSS selector you will see around the web. Classes are ideal because they are slightly more specific than element selectors but without the heavy-handedness of IDs. You can read a deep explanation of how the CSS Cascade determines specificity, but the following is an abbreviated illustration focusing *specifically* (get it?!) on the selector types we’ve looked at so far.
That’s what makes class selectors so popular — they’re only slightly more specific than elements, but keep specificity low enough to be manageable if we need to override the styles in one ruleset with styles in another.
The only difference when writing a class is that we prepend a period (.) in front of the class name instead of the hashtag (#).
/* Selects all <article> elements */article { background: #fff;}/* Selects any element with class="featured" */.featured { background: hsl(35 100% 90%); border-color: hsl(35 100% 50%);}
Here’s how our <article> example shapes up when we swap out #featured with .featured.
CodePen Embed FallbackSame result, better specificity. And, yes, we can absolutely combine different selector types on the same element:
```
``
Do you see all of the possibilities we have to select an
article)#someID).featured)The following articles will give you some clever ideas for using class selectors in CSS.
**Article** on Jan 25, 2020 The Difference Between ID and Class selectors Chris Coyier **Article** on Sep 28, 2022 Multiple Class / ID and Class Selectors selectors Chris Coyier **Article** on Nov 15, 2018 Scaling CSS: Two Sides of a Spectrum selectors Chris Coyier **Article** on Apr 22, 2019 Could Grouping HTML Classes Make Them More Readable? selectors Chris Coyier But we have even more ways to select elements like this, so let’s continue.
Attribute selectorsID and class selectors technically fall into this attribute selectors category. We call them “attributes” because they are present in the HTML and give more context about the element. All of the following are attributes in HTML:
```