Selectors: choosing what to style

Introduction

A rule is only useful if it picks the right elements. A selector that is too broad changes things you did not intend to change, and one that is too narrow breaks the moment the page changes. Writing good selectors is a skill that pays off in every CSS file you will ever work on.

How it works

Simple selectors.

SelectorMatches
pevery paragraph
.cardevery element with the class card
#menuthe element with the id menu
*every element

A class and a type can be combined with no space: p.note matches paragraphs that have the class note. Two classes together, .card.featured, match elements having both.

Grouping. A comma applies one set of declarations to separate selectors, so h1, h2, h3 gives all three the same style. Each part of a group stands alone. A warning here: in a plain selector list, if one part is invalid, the browser discards the whole rule.

Combinators describe relationships.

CombinatorExampleMatches
descendant (a space)nav aany a anywhere inside nav
childnav > aan a directly inside nav
next siblingh2 + pthe p immediately after an h2
later siblingh2 ~ pany p after an h2, with the same parent

Why would you need >? With nested lists, ul li reaches every level, while ul > li stops at the first.

Attribute selectors match based on attributes, and they are perfect for form inputs, which all share one tag.

SelectorMatches
[required]has the attribute
[type="email"]has exactly this value
[href^="https"]value starts with this
[href$=".pdf"]value ends with this
[href*="news"]value contains this

The browser reads selectors from right to left. For nav ul li a, it first finds every a, and then walks upwards checking ancestors. Long chains also make your CSS depend on the exact shape of the HTML, so that a small change to the page breaks the styling. Prefer a short, meaningful class like .menu-link.

Syntax

.card { padding: 16px; }
nav > a { color: navy; }
input[type="email"] { border-color: teal; }
h1, h2 { font-family: serif; }

Example

console.log output from the page shows here.

Line by line

  1. nav > a matches only the link directly inside nav, so the nested link keeps its usual colour.
  2. h2 + p matches only the paragraph that immediately follows the heading.
  3. p.note matches the paragraph that has the class note.

Expected result

"Direct link" is crimson while "nested link" stays blue. The first paragraph after Prices is bold, and "A second paragraph." is teal.

In the real world

Component libraries such as Bootstrap are built mostly on class selectors, since classes can be reused anywhere and do not depend on where an element sits. Attribute selectors are common in form styling and for marking external links or PDF downloads.

Common mistakes

  • Leaving out the dot in .card, so that it looks for a card element.
  • Adding a space by accident: p .note means a .note inside a p, which is different from p.note.
  • Styling mainly with ids, which are too strong and cannot be reused.
  • Writing very long chains that break when the HTML changes.

Best practices

  • Use classes for almost all styling.
  • Keep selectors short, ideally one or two parts.
  • Name classes for their purpose.
  • Group selectors to avoid repeating declarations.

Summary

Selectors choose elements by type, class, id or attribute, and combinators relate them to each other. A space reaches anywhere inside, > reaches direct children, + and ~ reach siblings. Short class-based selectors are the easiest to maintain.

Quick check

1. What does p .note match?
2. Which selector matches only links directly inside nav?
3. Which selector matches links to PDF files?

Key takeaways

  • Prefer classes for most styling.
  • A space means anywhere inside, and > means directly inside.
  • Commas apply the same declarations to separate selectors.
  • Attribute selectors can target elements that have no class.

Practice problems for this lesson

My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.