A CSS combinator connects two selectors to express a DOM relationship—such as elements nested inside a card or paragraphs sitting immediately after a heading. Using combinators cuts down repetitive class names while keeping styles scoped to the exact context you want.
): .card p matches every p anywhere inside .card, even deeply nested ones.>): .menu > li matches only immediate li children of .menu, skipping nested sub-menus.+): h2 + p matches a p that appears immediately after an h2 sharing the same parent.~): h2 ~ p matches all p siblings following an h2 under the same parent./* Only top-level navigation items */
.primary-nav > ul > li {
display: inline-block;
}
/* Remove top margin on paragraph immediately following a heading */
article h2 + p {
margin-top: 4px;
font-size: 1.05rem;
}
/* Stack spacing between every sibling element except the first */
.form-stack > * + * {
margin-top: 14px;
}
:has() Parent Selector BonusModern browsers also support :has() as a relational pseudo-class—for example, .card:has(img) styles a card only when it contains an image, solving scenarios traditional downward combinators never could.
>: .accordion p unintentionally styles nested sub-accordions unless scoped with .accordion > p..main > .content > div > ul > li > a are brittle and slow to refactor. Keep selectors shallow.+ with ~: Remember + matches strictly the very next sibling element, whereas ~ matches all matching later siblings..stack > * + * applies margin-top to every direct child that follows another sibling—spacing items evenly without leaving extra margin above the first item.
Traditional + and ~ only look forward in DOM order, though modern :has() lets you style an earlier element when a later sibling matches (label:has(+ input:required)).
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.