Share a declaration without repeating a rule
The universal selector * matches elements regardless of their type. A comma-separated selector list applies the same declarations to several selectors. These tools solve different problems: one selects broadly, while the other groups explicit targets.
A predictable sizing baseline
*,
*::before,
*::after {
box-sizing: border-box;
}
h1, h2, h3 {
line-height: 1.2;
color: #172554;
}The first rule includes pseudo-elements explicitly because * by itself does not select them. The second applies a shared heading style without repeating three declaration blocks. It does not mean an h1 inside an h2 inside an h3; commas mean separate alternatives.
Keep global resets deliberate
A rule such as * { margin: 0; padding: 0; } removes many browser defaults, including useful spacing in lists and headings. If you use it, you must restore sensible spacing for those elements. A smaller reset that changes only the properties you need is easier to reason about.
Grouping versus descendants
.card, .panel { border: 1px solid #cbd5e1; }
.card .panel { padding: 1rem; }The first rule matches either kind of component. The second only matches a panel located somewhere inside a card. A missing comma therefore changes which elements receive a style.
Specificity and maintenance
The universal selector contributes no specificity. Each selector in a traditional comma-separated list is considered independently for matching and specificity. Be careful when adding an unsupported or malformed selector to a normal selector list: parsing errors can invalidate the whole rule, unlike forgiving selector-list contexts.
Practice
- Group input, select and textarea to inherit the surrounding font.
- Add a border-box baseline and compare the measured width of a padded card.
- Write a selector list for .error and .warning, then explain why .error .warning would be different.
- Inspect a list after a global margin reset and restore spacing intentionally.