Selectors, Specificity and the Cascade
Master selector types, combinators, pseudo-classes, pseudo-elements, specificity, inheritance, and cascade resolution.
Element, Class, ID and Universal Selectors
CSS selectors determine which elements receive declarations. The universal selector * matches every element. Type selectors target HTML elements, class selectors target elements with a class, and ID selectors target a specific ID.
Classes are generally preferred for reusable styling. IDs have high specificity and are better reserved for unique document identities or application hooks when appropriate.
* {
box-sizing: border-box;
}
p {
color: #334155;
}
.card {
padding: 1rem;
}
#main-header {
min-height: 64px;
}card class, and the element with a specific ID.- Classes are the primary reusable styling hook.
- IDs have higher specificity than classes and element selectors.
Which selector targets elements with the class `card`?
Attribute Selectors
Attribute selectors target elements based on their attributes or attribute values. They are particularly useful for form controls, data attributes, links, and state represented through attributes.
input[type="email"] {
border-color: steelblue;
}
button[disabled] {
opacity: 0.5;
}
[data-theme="dark"] {
color-scheme: dark;
}
[href^="https://"] {
text-decoration: underline;
}^=, ends-with $=, and contains *=.- Attribute selectors can target both presence and values.
- They are useful when styling semantic states represented through attributes.
What does `[disabled]` select?
Combinators
Combinators describe relationships between elements. A descendant selector uses whitespace, a child combinator uses >, an adjacent sibling uses +, and a general sibling uses ~.
Understanding relationships is important because overly broad descendant selectors can create unexpected styling and make CSS harder to maintain.
.card p {
margin-block: 0.5rem;
}
.card > header {
padding: 1rem;
}
h2 + p {
margin-top: 0;
}
h2 ~ p {
color: #64748b;
}- Whitespace means descendant.
>means direct child.+means immediately following sibling.~means later sibling.
What does `.card > p` select?
Pseudo-Classes
Pseudo-classes represent element states or structural conditions. Common examples include :hover, :focus-visible, :active, :disabled, :checked, :first-child, :nth-child(), and :not().
Interactive states should consider keyboard users. For example, replacing a visible focus indicator with only :hover creates an accessibility problem.
button:hover {
transform: translateY(-1px);
}
button:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
li:nth-child(2n) {
background: #f8fafc;
}
input:not(:placeholder-shown) {
border-color: green;
}- Use
:focus-visiblefor accessible keyboard focus indicators. - Structural pseudo-classes can reduce unnecessary classes in markup.
Which pseudo-class is specifically useful for keyboard-visible focus styling?
Pseudo-Elements
Pseudo-elements style conceptual parts of an element rather than actual DOM elements. Common examples include ::before, ::after, ::first-letter, ::first-line, ::selection, and ::marker.
Generated content using ::before and ::after should not be used as the only place to store essential information because generated content may not provide the same semantic guarantees as real HTML content.
.badge::before {
content: "";
display: inline-block;
width: 0.5rem;
height: 0.5rem;
margin-inline-end: 0.5rem;
border-radius: 50%;
background: currentColor;
}- Pseudo-elements represent conceptual parts of an element.
- Do not hide critical semantic content exclusively inside generated content.
Which syntax represents a pseudo-element?
Specificity Calculation
Specificity determines which competing selectors have greater priority. A useful mental model is a four-part weight: inline styles, IDs, classes/attributes/pseudo-classes, and elements/pseudo-elements.
For example, #app .card p is more specific than .card p. Specificity should be kept manageable because deeply specific selectors make overrides difficult.
The !important flag overrides normal declarations but should be used sparingly because it makes the cascade harder to reason about.
p {
color: black;
}
.card p {
color: blue;
}
#article .card p {
color: red;
}- IDs carry much more specificity than classes.
- Avoid escalating specificity to solve architecture problems.
- Use
!importantonly when there is a clear reason.
Which selector has greater specificity?
Inheritance and the Cascade
Some CSS properties naturally inherit from parent elements, while others do not. Typography properties such as color and font-family commonly inherit, whereas properties such as margin, padding, and border generally do not.
The cascade resolves conflicts by considering origin and importance, specificity, scoping rules, and source order. Modern CSS also introduces layers through @layer, providing an explicit mechanism for organizing cascade precedence.
@layer reset, base, components, utilities;
@layer base {
body {
font-family: system-ui, sans-serif;
}
}
@layer utilities {
.hidden {
display: none;
}
}- Inheritance passes certain properties from parent to child.
- Cascade layers can make large CSS systems more predictable.
Which property commonly inherits from a parent?