Selectors

CSS Selectors are important to pick the correct HTML element when styling a web page. There are a lot of selectors available to make it possible to select the correct set of elements. By being able to select multiple elements we don’t need to create rules for every element. And in turn able to make our sites more dynamic.

For example, we could select all a tags to style them in a certain way instead of trying to pick everyone of them directly.

At the end of this post there is a section of HTML that can be used to try out each of the CSS examples.

This is by no means a complete list of selectors available. There are quite a few that are experimental. If you use any of the experimental, please don’t use them that if they don’t work the web site becomes unusable.

Universal Selector

This selector will select every element. There is some who don’t like the universal selector because it hits every element on the page and may slow down the rendering of the page.

* {
    margin: 10px;
}

Type Selectors

The simplest select is a tag selector. The below Example will make all h1 tags have a background color of green.

h1 {
    background-color: green;
}

Class Selectors

Selects all elements that have been given a specific class. Multiple elements can be given the same class. A period is placed before the class name to select it.

.headerSection {
    color: purple;
}

Id Selectors

Selects the element with that id. There should only be one element with that element. A # is placed before the id name.

#container {
    font-size: 1.5em;
}

Multiple Selectors

If two or more selectors will be getting the same styling, the selectors are separated by a comma. This can be type, class, or even more complex selectors.

h1, h2 {
    text-decoration: underline;
}

Combinators

Combinators allow you to select an element based on it’s location in comparison of another element.

Child Combinator

By using a > between the selectors, all of the second element that are a direct child of the first element. For the example below all the a will be picked if it’s an element directly inside an li. If the a was span which was inside an li it would not be selected.

li > a {
    background-color: orange;
}

Descendant Combinator

Placing a space between two selectors will selector all of the second selector that is a descendant of the first selector. So unlike the >, which only picks direct children, a space would select children of children.

The example below will select all h2 that is a descendant of an element that has the headerSection class.

.headerSection h2 {
    border: 1px solid blue;
}

Adjacent sibling Combinator

A + between the selector will select the second element if it is a adjacent sibling. The two elements must be children of the same element and right next to each other.

For the example below, all a that directly follow an ol would be selected.

ol + a {
    background-color: blue;
}

General sibling Combinator

A ~ between the selector will select the second element if it is a sibling. Sibling means two elements must be children of the same element.

For the example below, any a that is sibling of an ol and comes after would be selected.

ol ~ a {
    background-color: green;
}

Attribute Selectors

Selection can also be based on attribute an element has. In this example any element with an attribute of data-vegetable will be styled bold.

An attribute doesn’t need to have a value, it is common for an element to have a data-???? attribute so it can be selected by CSS or by JavaScript.

In this example I’ve added an attribute of data-vegetable to items in a list that are vegetables. By selecting them I could add an icon that shows a vegetable.

[data-vegetable] {
    font-weight: bold;
}

The value of the attribute can be used to narrow down the selection as well. In this example we’re selecting any elements that have a src attribute set to #First.

[src="#First"]{
    text-decoration: line-through;
}

By placing an ^ before the equal sign, any attribute value that starts what we provide will be slected. In this example any src that start with http will be select.

[href^="http"] {
  background-color: red;
}

The $= will select those that end with the value. In this example we’re selecting all src’s values that end with pdf. This is useful if you wanted to style links to pdf files.

[href$="pdf"]{
  border: 5px solid green;
}

We covered starts with ^= and ends with $=, and now contains *=. In this example we’d select google.com or https://en.wikipedia.org/wiki/google, because contain google.

[href*="google"]{
    border: 3px solid black;
}

Pseudo-classes

There is a good sized list of the pseudo-classes that are available. I’m going to cover some of the more useful ones. Check out the MDN page for Pseudo Classes.

First up is :hover. In the example, I’m using a type selector, but this could be a class or id selector instead. If the mouse hovers over the element the style will be applied.

a:hover {
    font-size: 2em;
}

When styling links, there are four pseudo-classes that should be kept in mind.

  • :hover - When the mouse hovers over the link
  • :visited - A link you’ve visited
  • :link - A link that hasn’t been visited
  • :active - Being activated, such as when the user clicks down but hasn’t released the mouse button yet.

The :checked is useful to find checkboxes that have been checked. Very little of the checkbox itself is easily styled. But by using the + we can effect the label of the checkbox.

The way to read this is, style every label that is immediately following an input that is checked.

input:checked + label {
  color: red;
}

:disabled and :enabled can match-up when you’re using JavaScript to toggle a button enabled or disabled. Here we’re adding a line-through any button that has been disabled.

button:disabled {
  text-decoration: line-through;
}

:valid and :invalid style based on the validation that HTML5 can do. Using these lets you decide what styling will be applied.

input:invalid {
    box-shadow: 0 0 10px rgba(255, 0, 0, 1);
}

So far we’ve looked at if an element has something. Well, what if we wanted to select elements that didn’t have something?

Well there is the :not pseudo class. This will select all p elements that don’t have the class notThisOne.

p:not(.notThisOne){
  font-variant: small-caps;
}

Sometimes you may want to style a certain set of elements that come in a numbered pattern. For example, every second row in a table, or every fifth element starting on the third element. Well, there a bunch of pseudo-classes that let you do exactly that. I’m not going to cover every one of them.

Here are some of them:

  • :first
  • :first-child
  • :first-of-type
  • :last-child
  • :last-of-type
  • :nth-child()
  • :nth-last-child()
  • :nth-last-of-type()
  • :nth-of-type()
  • :only-child
  • :only-of-type

The first, last and only versions are straight forward enough. p:first would select the first p tag.

But what’s up with nth and what goes in the parenthesis? The simplest would be odd and even. Yep, you can say p:nth-child(odd) and it’d select all odd paragraphs.

The other pattern is An+B. A is the number for the pattern. B is the row that pattern is starting.

Some examples:

  • :nth-child(7)
    • Selects the seventh element
  • :nth-child(2n+1)
    • Start at the first element and every other after. (1, 3, 5)
  • :nth-child(2n)
    • Even elements (2, 4, 6)
  • :nth-child(5n)
    • Every 5th element (5, 10, 15)
  • p:nth-child(n)
    • Selects every p element but at a higher specificity then just using p
  • :nth-child(-n+3)
    • The first element (1, 2, 3)

As you can see this is very powerful. While I think it’s can be confusing, it’s worth learning. This can let you style lists, tables and large amount of content without having to dig into the HTML to add classes spread throughout.

I think the most common use is the put stripes on a table.

tr:nth-child(even){
    background-color: grey;
}

Pseudo-elements

Pseudo-elements are elements that aren’t actually in the HTML but we can style them anyway. For the Pseudo-classes we use a single :. For Pseudo-elements we use double ::. This difference was adding late in the standard so most browser allow either to be used.

Even though there isn’t an element actually surrounding the first line of the p element, we can ask the browser to identify the first line and style it.

p::first-line{
    font-size: 1.5em;
}

Dropcaps are a great design. But before the new pseudo-element ::first-letter came around some HTML needed to be added to allow the dropcaps. Now it’s fairly easy to add. Well, easy in that nothing appears in the HTML, only in the CSS.

p::first-letter {
  color: #903;
  float: left;
  font-family: Georgia;
  font-size: 75px;
  line-height: 75px;
  padding-top: 4px;
  padding-right: 8px;
  padding-left: 3px;
}

Every element has an ::before and ::after. These psuedo-elements let you attach things to an element. Keep in mind, while the user can see them, they are not part of the HTML. With either the ::before or ::after a content needs to be provided, even if it’s an empty string. Without the content the psuedo-element will not appear.

[href$="pdf"]::after {
  content:"\00ae";
  border: 1px dashed blue;
}

Ok, what the heck did a put in for the content value? It’s called an HTML entities. It’s a special code that tell the browser what character to place there. Estelle Weyl’s blog post about HTML entities is a great post describing and listing a very useful collection of these codes.

In this case I used a Registration symbol.

The psuedo element doesn’t need to be paired with another selector. Here I’m saying if any of the text is selected by the user, style it with a yellow background instead of the default coloring.

::selection {
    background-color: yellow;
}

Resources

HTML code

Here is a CodePen pen that already has the HTML and CSS loaded. Click on the Edit on CodePen in the upper right hand corner and you’ll be able to edit the pen and try the selectors out. Forking the pen will allow you to save the edits to your account.

See the Pen Selectors by Russ Eby (@RussEby) on CodePen.

Just in case you want to try it out somewhere else, here’s the HTML code.

<div id="container">
    <div class="headerSection">
        <h1>Title</h1>
        <h2>Sub-Title</h2>
    </div>
    <ol>
        <li><a src="#First">First</a></li>
        <li><a src="#Second">Second</a></li>
        <li><span><a src="#Third">Third</a></span></li>
    </ol>
    <a src="http://bing.com">Bing</a>
    <ul>
        <li data-quantity="5" data-vegetable>Onions</li>
        <li data-quantity="2" data-fruit>Apple</li>
    </ul>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatibus, aperiam tempora? Consectetur mollitia totam cupiditate praesentium minus, distinctio nulla possimus, quam repellendus fugit expedita quis est voluptatum minima provident commodi.</p>
  <p class="notThisOne">Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur vero, eveniet cum quas illo tenetur delectus distinctio. Vitae iure nihil debitis adipisci quo beatae repellat doloribus distinctio quod molestias! Ex?</p>
    <div>
        <a href="instructions.pdf">Instructions</a>
    </div>
  <div>
    <input type="checkbox" name="my-checkbox" id="opt-in">
    <label for="opt-in">Check me!</label>
  </div>
</div>
<div>
  <a href="http://altavista.com">Altavista</a>
  <ol>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
  </ol>
  <a href="google.com">Google</a>
</div>
<button disabled>Click Here</button>
<input type="text" required>

<table>
  <thead>
    <tr>
      <th>First</th>
      <th>Second</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>2</td>
    </tr>
        <tr>
      <td>3</td>
      <td>4</td>
    </tr>
        <tr>
      <td>5</td>
      <td>6</td>
    </tr>
        <tr>
      <td>7</td>
      <td>8</td>
    </tr>
    <tr>
      <td>9</td>
      <td>10</td>
    </tr>
  </tbody>
</table>