CSS Universal Selector * - Performance and Practical Use
The CSS universal selector * matches every element. Learn its real performance impact, common reset uses, and when scoping with :where(*) is the safer choice.
Detailed Explanation
What * Actually Does
The universal selector matches every element in the document. By itself it's used for resets and inheritable defaults:
* {
box-sizing: border-box;
margin: 0;
}
It also appears as a wildcard inside compound selectors:
.grid > * { /* every direct child */ }
[data-foo] * { /* every descendant of any element with data-foo */ }
The "Performance" Myth
Old-school CSS guides warned that * was slow. Modern browsers (Blink, WebKit, Gecko) match selectors right-to-left and use highly optimized hash maps for the rightmost compound. A bare * is essentially free; the cost only adds up if you write deeply qualified selectors that force the engine to walk the tree:
* * * { color: red; } /* still fine */
.deep > * + * + * { } /* slightly slower because of sibling walks */
In practice you should never feel * performance unless you're writing pathological selectors on a five-figure-node DOM.
Specificity Is Zero
* contributes (0, 0, 0) to specificity. That makes it ideal for resets — anything else will override it.
Owl Selector * + *
The "lobotomized owl" pattern from Heydon Pickering uses the universal + adjacent-sibling combo to add a top margin between flow elements:
.flow > * + * { margin-top: 1.5em; }
It's a single rule that creates consistent vertical rhythm without per-element styles.
Scope With :where(*)
If you want a wide-reaching rule but worry about specificity collisions, wrap in :where():
:where(*) {
font-family: system-ui, sans-serif;
}
The selector still matches every element but contributes zero specificity (which it would have anyway in this case — but it documents intent).
When NOT to Use *
- Inside very large ancestor selectors that force a walk:
section nav ul li *— costly because the engine matches every element then climbs four ancestors. - For inheritable properties, prefer setting them on
htmlor:rootso inheritance does the work.
Use Case
Use the universal selector for box-sizing resets, the owl pattern for vertical spacing, and as a wildcard inside compound selectors (".grid > *", "[data-tooltip] *"). The performance fear is outdated; pick "*" when it expresses intent more clearly than alternatives.