Grow your CSS skills. Land your dream job.

Beginner Concepts: How CSS Selectors Work

Published by Chris Coyier

Are you new to CSS? This article is for you! Perhaps the biggest key to understanding CSS is understanding selectors. Selectors are what allows you to target specific HTML elements and apply style to them. Let's not think about style right now though, let's just focus on the selecting.

In the examples below, the CSS would be in a file called something like style.css that is referenced from an HTML document called something like index.html. They are separate files, which is the great thing about CSS, keeping the design away from the document.

Here's what that HTML file would be like:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>We're learning selectors!</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  
  <h1 id="yay">Yay</h1>

<body>
</html>

And the CSS file would contain just the selector blocks like you'll see below.


ID selector

#happy-cake {

}
<!-- WILL match -->
<div id="happy-cake"></div>

<!-- WILL match -->
<aside id="happy-cake"></aside>

<!-- Will NOT match -->
<div id="sad-cake">Wrong ID!</div>

<!-- Will NOT match -->
<div class="happy-cake">That's not an ID!</div>

Leveling Up

ID selectors are the most powerful type of selector in terms of CSS specificity. Meaning that they beat out other types of selectors and the styles defined within win. That sounds good, but that's typically considered bad, because it's nice to have lower-specificity selectors that are easier to override when needed.


Class Selector

.module {

}
<!-- WILL match -->
<div class="module"></div>

<!-- WILL match -->
<aside class="country module iceland"></aside>

<!-- Will NOT match -->
<div class=".module">The dot is for CSS, not HTML</div>

<!-- Will NOT match -->
<div class="bigmodule">Wrong class</div>

Leveling Up

Class selectors are your friend. They are probably the most useful and versatile selectors out there. In part because they are well supported in all browsers. In part because you can add multiple classes (just separated by a space) on HTML elements. In part because there are JavaScript things you can do specifically for manipulating classes.


Tag Selector

h2 {

}
<!-- WILL match -->
<h2>Hi, Mom</h2>

<main>
  <div>
     <!-- WILL match -->
     <h2>Anywhere</h2>
  </div>
</main>

<!-- Will NOT match -->
<div class="h2">Wrong tag, can't trick it</div>

<!-- Will NOT match -->
<h2class="yolo">Make sure that tag has a space after it!</h2>

Leveling Up

Tag selectors are at their most useful when changing properties that are unique to that HTML element. Like setting the list-style on a <ul> or tab-size on a <pre>. Also in reset stylesheets where you are specifically trying to unset styles that browsers apply to certain elements.

Don't rely on the them too much though. It's typically more useful to have a class define styling that you can use on any HTML element.


Attribute Selector

[data-modal="open"] {

}
<!-- WILL match -->
<div data-modal="open"></div>

<!-- WILL match -->
<aside class='closed' data-modal='open'></aside>

<!-- Will NOT match -->
<div data-modal="false">Wrong value</div>

<!-- Will NOT match -->
<div data-modal>No value</div>

<!-- Will NOT match -->
<div data-modal-open>Wrong attribute</div>

Leveling Up

You might argue that attribute selectors are even more useful than classes because they have the same specificity value, but can be any attribute not just class, plus they can have a value you can select by.

Hardly an issue anymore, but attribute selectors aren't supported in IE 6.


Positional Selectors

:nth-child(2) {

}
<ul>
  <li>nope</li>
  <!-- WILL match -->
  <li>yep, I'm #2</li>
  <li>nope</li>
</ul>

Leveling Up

There are several different positional selectors beyond :nth-child. Using simple expressions (like 3n = "every third") you can select elements based on their position in the HTML. You can play with that idea here or check out some useful recipes.


Other Pseudo Selectors

:empty {

}
<!-- WILL match -->
<div></div>

<!-- WILL match -->
<aside data-blah><!-- nothin' --></aside>

<!-- Will NOT match -->
<div> </div>

<!-- Will NOT match -->
<div>
</div>

Leveling Up

:empty is one of many pseudo selectors, which you can recognize by the colon (:) in them. They typically represent something that you couldn't know by just the element and attributes alone.

Note that these are slightly different than pseudo elements, which you can recognize by the double colon (::). They are responsible for adding things to the page by the things they select.


More Leveling Up

Selectors can be combined together. For instance:

.module.news {  
  /* Selects elements with BOTH of those classes */
}
#site-footer::after {
  /* Adds content after an element with that ID */
}
section[data-open] {
  /* Selects only section elements if they have this attribute */
}

There are also selector combinators like ~ and + and > that affect selectors, like:

.module > h2 {
  /* Select h2 elements that are direct children of an element with that class */
} 
h2 + p {
  /* Select p elements that are directly following an h2 element */
}
li ~ li {
  /* Select li elements that are siblings (and following) another li element. */
}

Here on CSS-Tricks there is an entire Almanac that covers all the selectors in CSS, as well as properties.

Comments

  1. Phan An
    Permalink to comment#

    For “Attribute Selector”, shouldn’t the CSS read [data-modal="true"] instead?

  2. #site-footer::after {
      /* Adds content after an element with that ID */
    }
    

    Double colon is not recognized on IE, right? Gotta use the single colon syntax.

    • That is true for IE 8 yep. I think it’s nice presenting the concept with the different between selector and element with the different number of colons though. It’s always choosy in a beginner article what to cover and what not to, lest overwhelm.

  3. jimmy
    Permalink to comment#

    Very well written Chris.

    You should note that IDs must only be used once per page,because a lot of begginers don’t know that :)

    • jimmy
      Permalink to comment#

      *same IDs

    • Weirdly enough, while that’s absolutely a best practice, CSS doesn’t really care about that.

    • few
      Permalink to comment#

      why should it? having a unique id is a restriction for html documents not css.

    • jimmy
      Permalink to comment#

      That is what I meant. I know CSS doesn’t care and that is all OK.
      The name of the ID should be unique in a HTML document.

      And this can potentially be confusing for beginners.

      Validator will throw an error if you have this in same page. But it is not a big deal :)

    • jimmy
      Permalink to comment#

      That is what I meant. I know CSS doesn’t care and that is all OK.
      The name of the ID should be unique in a HTML document.

      And this can potentially be confusing for beginners.

      <!-- WILL match -->
      
      
      <!-- WILL match -->
      
      

      Validator will throw an error if you have this in same page. But it is not a big deal :)

    • jimmy
      Permalink to comment#

      fuck ,sorry about this Chris.

      I meant on ID happy-cake

    • Ricozor
      Permalink to comment#

      CSS don’t care multiple same IDs but javascript care ( javascript will focus the last one in the flow )
      that’s why multiple same IDs are forbiden.

  4. That :empty selector tho… #mindblown

    • I was thinking the same thing. I’m pretty good with pseudo selectors/elements, but I didn’t even know about that one!

    • Rene
      Permalink to comment#

      :empty is great but be aware that white space can/should be rendered as a text node in the dom. As soon as there is a textnode in an element, :empty will be false on that element.
      This behaviour does differ between browsers last time I checked(maybe also depending on type of element).

      I wouldn’t like to rely on this selector, it’s too invisible when working on the html and an extra newline is easily added.

      In the almanac as well: http://css-tricks.com/almanac/selectors/e/empty/

  5. Thanks Chris for creating a post geared at the beginner CSS developer…I teach CSS and a lot of concepts in CSS that some blog writers take for granted are completely foreign to newbies just starting out in CSS…Post like these really help…

    Thanks for sharing your knowledge…

  6. While I am not a CSS beginner myself, this is a solid overview on working with selectors. Good link to pass on to a few folks I know in the process of learning this stuff. Thanks as always, Chris!

  7. me
    Permalink to comment#

    short. simple :)

  8. andredupond
    Permalink to comment#

    this is a nice “game” to practice : http://flukeout.github.io/ !
    you have to select the woobling item. To begin the 3 first answers to type in the blinking blue field are :
    plate
    bento
    plate#fancy

    enjoy beginners !

  9. This is a perfect representation of my big “AHA” moment with CSS. Odd as it may seem, realizing that “selector” actually meant that you are “selecting” something was a huge step for me in understanding how CSS worked.

  10. Jocely
    Permalink to comment#

    Thanks for the article. I had no clue about those last three selectors.

  11. Priya
    Permalink to comment#

    Thanks Chris. This is great article.

  12. Arif
    Permalink to comment#

    Thanks Chris. What a Useful article.

  13. Hemanthmalli
    Permalink to comment#

    Very useful information for the persons who are learning CSS.

  14. Thank you for putting it all in one place. Several tutorials I had a look at were rather convoluted and I have visited CSS tricks a few times now to get my head cleared up again, in fact it nicely showed up in Google once I knew how to pose the question or I would not have found you back in May or June.

  15. Permalink to comment#

    Honestly I have always been hesitant to use those special selectors. Will they work in all browsers?

  16. TerryLee
    Permalink to comment#

    what’s different with “.class:after” and “.class::after” ? one “:” and two “::” ? why?

    • Adrian
      Permalink to comment#

      TerryLee, the “.class:after” is the old CSS2 syntax for pseudo selectors.
      The “.class::after” is the new CSS3 syntax. And the reason it has two “::” is to clearly differentiate a pseudo-class from a pseudo-element.
      For example “a:active” is a pseudo-class which targets the active state of an anchor.
      Imagine using “a:after” for adding some content after an anchor. It will just be confusing for some people. And because of that, it’s better to use “a::after”. Still, note that IE8 still uses the old CSS2 syntax with just one “:”.

Leave a Comment

Posting Code

  • Use Markdown, and it will escape the code for you, like `<div class="cool">`.
  • Use triple-backticks for blocks of code.
    ``` 
    <div>
      <h1>multi-line block of code</h1>
      <span>be cool yo.</span>
    </div>
    ```
  • Otherwise, escape your code, like <code>&lt;div class="cool"&gt;</code>. Markdown is just easier though.

Current ye@r *

*May or may not contain any actual "CSS" or "Tricks".