Chapter 12: Selectors, Pseudo-Classes, and Pseudo-Elements
Selectors are the language you use to point at parts of a page. They decide which elements receive which rules, forming the bridge between structure and design. Once you understand how selectors read the document and how pseudo-classes and pseudo-elements extend that reach, you gain a level of precision that makes your CSS feel almost conversational. This chapter explores the most common selectors, the flexible world of attribute targeting and the expressive tools that let you style states, highlights and tiny details without changing your HTML.
Common selectors
Basic selectors form the foundation of most stylesheets. They include element selectors such as p and nav, class selectors such as .card and ID selectors such as #intro. These three types appear constantly because they map directly to the structure of the HTML. When combined, they let you narrow or broaden your reach with ease.
p {
margin: 1rem 0;
}
.card {
padding: 1rem;
border: 1px solid #ccc;
}
#intro {
font-size: 1.25rem;
}
Descendant selectors target elements that sit somewhere inside other elements. They use spaces to show each step in the path. A space means “contained within”, not “listed alongside”. If you used commas instead, the selector would simply become a list of separate targets rather than a chain. Reading a descendant selector feels like walking through nested boxes until you reach the element you want.
nav ul li a {
text-decoration: none;
color: #0044aa;
}
Attribute selectors
Attribute selectors allow you to style elements based on the presence or value of their attributes. This can be especially helpful for forms, links, data tables and custom structures where classes alone might not explain the purpose of each element. By matching attributes, your CSS gains a little more insight into what an element represents.
a[target="_blank"] {
color: #cc0000;
}
input[type="email"] {
border-color: #4488cc;
}
[data-level="warning"] {
background-color: #fff4e0;
}
Pseudo-classes and pseudo-elements
Pseudo-classes describe temporary or structural states such as hovering, focusing, selecting or visiting a link. They behave almost like small conditionals inside your stylesheet. When a user interacts with an element or when an element sits in a particular situation, the browser applies the matching rule.
a:visited {
color: purple;
}
input:focus {
outline: 2px solid #0057cc;
}
Pseudo-elements reach into parts of an element that do not exist as separate nodes in the HTML. They let you style the first letter of a paragraph, add decorative content or mark the beginning of sections with small symbols. This makes it possible to enrich a design without adding extra markup.
p::first-line {
font-weight: bold;
}
.article-title::after {
content: " ✦";
color: #888;
}
Common pseudo-classes
Pseudo-classes describe conditions or states that an element can be in. Some relate to user interaction, some to document structure and others to form behaviour or link history. This list gathers the most commonly used pseudo-classes so you can see the landscape at a glance. It is not every pseudo-class ever created, yet it covers the ones you will meet in everyday work.
Interaction and user input
:hoverwhen a pointing device rests over an element:activewhen an element is being pressed:focuswhen an element has keyboard or programmatic focus:focus-visiblewhen focus should be visibly indicated:focus-withinwhen an element or any of its descendants has focus
Link history
:linkan unvisited link:visiteda link that has been visited
Form and validation states
:checkedradio buttons and checkboxes that are selected:indeterminatetri-state checkboxes:disabledelements that are disabled:enabledthe opposite of:disabled:requiredform controls marked as required:optionalform controls that are not required:validinputs that pass validation:invalidinputs that fail validation
Structural pseudo-classes
:first-childthe first child of its parent:last-childthe final child of its parent:nth-child(n)matches the nth child:nth-last-child(n)counts from the end:first-of-typefirst element of its type inside a parent:last-of-typelast element of its type:nth-of-type(n)nth element of its type:only-childwhen an element is the sole child:only-of-typewhen an element is the sole child of that type:emptyelements with no children at all
State and logic
:rootthe top element of the document (thehtmltag):not(...)matches everything except what is inside the brackets:is(...)simplifies writing long selector lists:where(...)similar to:isbut always low specificity:has(...)parent selector that matches when descendants meet a condition
Content and media
:fullscreenwhen an element is in fullscreen mode:targetwhen an element is the target of a URL fragment:playingaudio or video currently playing:pausedaudio or video paused
These pseudo-classes give you a vocabulary for states that HTML cannot express alone. Combined with pseudo-elements, they let your styles react to structure, interactivity and user behaviour without adding a single extra element to your markup.
Hover and focus states that feel natural
Interactions should feel steady and reassuring. A good hover state lets readers know which elements respond to clicks or taps. A good focus state supports keyboard navigation and helps assistive technologies reveal where attention currently sits. These states work best when they are clear but not abrupt. Soft color changes, gentle underlines or subtle shadows guide the user without startling them.
a:hover {
text-decoration: underline;
}
button:hover {
background-color: #e8e8e8;
}
button:focus {
outline: 3px solid #2a7fff;
outline-offset: 2px;
}