CSS Combinators
Overview
Combinators allow you to target elements based on their exact relationship to other elements in the DOM tree. Instead of adding a unique class to every single element, combinators let you write highly efficient rules like 'Target all paragraph tags that are strictly direct children of the article tag'. This drastically reduces HTML bloat.
Syntax
/* 1. Descendant Selector (Space): Targets ANY nested children, no matter how deep */
article p {
color: gray;
}
/* 2. Child Selector (>): Targets ONLY direct, first-level children */
ul > li {
list-style: none;
}
/* 3. Adjacent Sibling Selector (+): Targets the very NEXT sibling element */
/* Example: Styles the paragraph immediately following an h2 */
h2 + p {
margin-top: 0;
}
/* 4. General Sibling Selector (~): Targets ALL following sibling elements */
/* Example: Styles every paragraph that comes after an img in the same container */
img ~ p {
padding-left: 20px;
}Common Pitfalls
- Over-nesting descendant selectors (e.g.,
body main article .card ul li a). This forces the browser's engine to perform massive, slow DOM lookups to verify the path. Keep your combinators shallow (maximum 3 levels deep). - Confusing the Child (
>) and Descendant (space) selectors. If you use.card > p, it only styles paragraphs directly inside the card. If there is a<div>wrapping the paragraph inside the card, the rule will instantly break.
Interview Questions
.container > ul li a?Crucially, browsers evaluate CSS selectors from RIGHT to LEFT. It first finds every <a> tag on the page, then checks if its ancestor is an <li>, then an <ul>, and finally checks if the <ul> is a direct child of .container. This is why overly complex selectors hurt performance.
Real-World Example
Using the adjacent sibling selector to style form error messages only when they appear directly below an invalid input.
/* Standard input */
input { border: 1px solid gray; }
/* The error message is hidden by default */
.error-msg { display: none; color: red; }
/* If the input is invalid, immediately show the sibling error message! */
input:invalid + .error-msg {
display: block;
}Check Your Knowledge
Test your understanding of CSS Combinators with these quick questions.