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.
| Selector | Matches |
|---|---|
p | every paragraph |
.card | every element with the class card |
#menu | the 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.
| Combinator | Example | Matches |
|---|---|---|
| descendant (a space) | nav a | any a anywhere inside nav |
| child | nav > a | an a directly inside nav |
| next sibling | h2 + p | the p immediately after an h2 |
| later sibling | h2 ~ p | any 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.
| Selector | Matches |
|---|---|
[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
Line by line
nav > amatches only the link directly insidenav, so the nested link keeps its usual colour.h2 + pmatches only the paragraph that immediately follows the heading.p.notematches the paragraph that has the classnote.
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 acardelement. - Adding a space by accident:
p .notemeans a.noteinside ap, which is different fromp.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
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.