Web Development · Foundations
CSS Selectors
On this page 9 sections
In 30 seconds
A CSS selector A CSS pattern used to identify elements in a document tree. Full entry → is the part of a rule that says which HTML elements the declaration block can style. p selects paragraph elements, .note selects elements whose class includes note, and #summary selects the element with that ID. [disabled] selects elements that have a disabled attribute. A space joins selectors as a descendant relationship: article p matches paragraphs inside an article. Selectors identify matches; cascade and specificity decide conflicts later.
Why this matters
Selectors connect an HTML document's structure and attributes to CSS rules. Reading them accurately helps you find why a rule applies to one element but not another, and writing them carefully keeps a stylesheet tied to meaningful markup rather than arbitrary visual positions. They also prepare you for later work with the cascade and specificity: first determine which elements a selector matches, then reason about competing rules. A small, precise selector is often easier for a teammate to maintain and safer to reuse when a page changes.
The college version
Selectors are matching patterns
A CSS rule has a selector and a declaration block. The selector is a pattern evaluated against elements in the document tree; the block supplies declarations for the elements that match. In p { color: navy; }, p is a type selector A selector that matches elements by element name, such as p or button. Full entry →. It matches paragraph elements, not every node that happens to display text. This distinction matters because CSS works from the document's element structure and attributes. The same selector can match zero, one, or many elements. A selector is therefore not an instruction to create an element or a promise that a style will visibly win; it is a way of identifying candidate elements. Whether a declaration ultimately wins against another matching declaration belongs to the later topics of cascade and specificity. Keep those questions separate while learning matching. When debugging, begin with the concrete question: does this selector match this particular element in this document?
The basic selector forms are intentionally close to HTML vocabulary. A type selector uses an element name, such as button or h2. A class selector A selector beginning with . that matches an element carrying the named class token. Full entry → begins with a period, so .warning matches an element with class="warning"; an element may have several class tokens and can match several class selectors. An ID selector A selector beginning with # that matches an element with the named ID value. Full entry → begins with #, so #site-search matches an element whose ID value is site-search. IDs are commonly used as unique document identifiers, but the selector notation itself is about that value. These forms can be combined without spaces. For example, button.primary is a compound selector Simple selectors written together with no combinator, all of which must match one element. Full entry →: it matches a single button element that also has the primary class. It does not mean a primary element inside a button.
Attributes and relationships add precision
Attribute selectors inspect the attributes written on an element. [disabled] matches an element that has a disabled attribute, regardless of the attribute's spelling in CSS. [type="email"] matches elements whose type attribute has the value email. The equals form is useful when an HTML attribute carries an explicit category; the presence form is useful when the mere presence of an attribute is meaningful. Attribute selectors do not invent accessibility or behavior. They only match what the HTML already contains, so the underlying element and attribute must still be appropriate for the task.
A space between two selectors has a specific meaning: it is the descendant combinator Whitespace between selectors that matches an element with a matching ancestor. Full entry →. main a matches an anchor element if it occurs anywhere inside a main element, even if other elements lie between them. It does not match the main itself, and it does not require the anchor to be an immediate child. This is a relationship in the document tree, not a visual relationship on the screen. In <main><section><a href="/help">Help</a></section></main>, main a matches the link because main is an ancestor of the anchor. In contrast, maina would be a type selector for an element named maina, which is a different pattern altogether. Spaces in selectors deserve deliberate attention because removing one can change matching completely.
Build selectors from the markup outward
A reliable workflow starts with the HTML. Name the element or elements you mean to style, then choose the smallest stable detail that distinguishes them. If every call-to-action is a button with the class primary, button.primary expresses both facts. If the rule should apply only to email inputs, input[type="email"] states the element type and the attribute value. If the target is links inside an article, article a describes ancestry. Test the selector against multiple examples, including an element that looks similar but should not match.
Consider this markup: <article class="story"><h2>News</h2><p class="lead">Opening text</p><p>More text</p><a href="/read">Read</a></article>. p matches both paragraphs. .lead matches only the first paragraph. article .lead also matches that first paragraph because it is inside the article. article p.lead is a compound-and-descendant pattern: the selected element must be a paragraph with class lead and have an article ancestor. [href] matches the link because it has that attribute. None of these statements answers whether a competing rule takes precedence; they are matching facts. Separating matching from conflict resolution makes CSS inspection much less mysterious and keeps this lesson's boundary clear.

Eli explains
The same idea, in plain words
Explain it like I’m 10
Think of a web page as a school directory. CSS selectors are the ways you ask the directory for people: all students in grade six, everyone in the chess club, or the person with one particular locker number. A selector does not paint anything by itself. It points CSS to the entries that should receive a rule.
p is like asking for every paragraph-shaped entry. .note is like asking for every entry carrying a Note sticker. #summary is like using one exact name tag. [disabled] is like asking for every device marked Disabled. article p is like asking for paragraphs that appear somewhere inside an article folder.
When two rules point at the same entry, another set of CSS rules decides which one wins. That later decision is not what selectors do.
Picture it like this
A selector is a directory search filter: it identifies a group before any action is taken on that group.
Where the picture stops working
A real directory search may rank results or correct spelling. CSS selector matching does not guess an intended element, and the cascade—not the selector—settles competing style declarations.
Worked example
Start with <article><p class="lead">Welcome</p><p>Details</p><input type="email" disabled></article>. The selector p matches both paragraph elements. .lead matches only Welcome because only its class list contains lead. article p still matches both paragraphs: each has an article ancestor. input[type="email"] matches the input because it is an input and its type value is email; [disabled] also matches it because the attribute is present. p.lead matches one element, not two: no space means the same element must satisfy both the type and class conditions. This example asks only which elements match, not which rule would win if two declarations conflict.
Key takeaway
Selectors match elements from their names, attributes, and relationships in the document tree. Determine matching before moving on to cascade or specificity questions.
Quick check
3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.
What does the selector
Which selector matches an input whose type attribute is email?
Given <article><section><p>Text</p></section></article>, which statement about article p is correct?
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related
You’ll learn to
- Define a CSS selector and distinguish matching from conflict resolution.
- Identify type, class, ID, and attribute selectors in a CSS rule.
- Explain how a descendant combinator uses document ancestry.
- Apply a compound selector to determine which element matches.
- Diagnose why a selector does not match a proposed HTML element.
Common mistakes
Reading
button.primaryas a primary element inside a button.There is no space, so it is one button element that must also have class
primary.Assuming
article pmeans a direct child paragraph.A descendant can occur at any depth below the article; direct-child matching is a separate selector form.
Using
#when the HTML has a class value.Use
.for a class selector and#for an ID selector.Treating a selector match as proof that its declaration wins.
First establish matching; use cascade and specificity rules later to resolve conflicts.
Easily confused
`p.lead` vs. a descendant selector with `p` as ancestor and `.lead` as descendant
The first matches a paragraph that has class lead; the second matches an element with class lead inside a paragraph.
`[disabled]` vs. `[type="email"]`
The first tests attribute presence; the second tests a specific attribute value.
class selector vs. ID selector
A class selector uses .name; an ID selector uses #name and refers to an ID value.
Key vocabulary
- selector
- A CSS pattern used to identify elements in a document tree.
- type selector
- A selector that matches elements by element name, such as
porbutton. - class selector
- A selector beginning with
.that matches an element carrying the named class token. - ID selector
- A selector beginning with
#that matches an element with the named ID value. - attribute selector
- A selector that matches according to an element's attribute presence or value.
- compound selector
- Simple selectors written together with no combinator, all of which must match one element.
- descendant combinator
- Whitespace between selectors that matches an element with a matching ancestor.
Sources & references
- MDN Web Docs — CSS selectors and combinators — Mozilla / MDN Web Docs
- Selectors Level 4 — W3C
EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.
Researched 2026-08-20
Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.

