Introduction
CSS selectors tell the browser which HTML elements to style.
Some selectors are very specific.
For example:
.card { padding: 24px;}
This targets elements with class="card".
Other selectors are much broader.
For example:
* { box-sizing: border-box;}
The * selector is called the universal selector.
It can target every element.
CSS also lets you group selectors together in a selector list:
h1,h2,h3 { line-height: 1.2;}
This applies the same declarations to more than one selector.
Universal selectors and selector lists are useful, but they should be used carefully.
Broad selectors can affect more elements than you expect.
Grouped selectors can save repetition, but they can also make mistakes spread across several elements at once.
This article explains how to use *, grouped selectors, and broad targeting in CSS.
What Is the Universal Selector?
The universal selector is written as an asterisk:
*
It means “select everything”.
For example:
* { box-sizing: border-box;}
This rule applies to every element on the page.
It can apply to headings, paragraphs, links, images, buttons, forms, sections, divs, spans, lists, tables, and more.
The universal selector is powerful because it is very broad.
That also means it can cause problems if you use it carelessly.
A Simple Universal Selector Example
HTML:
<h1>Welcome</h1> <p>This is a paragraph.</p> <a href=”about.html”>About us</a>
CSS:
* { color: blue;}
This makes the heading, paragraph, and link text blue.
The rule does not only affect one type of element.
It affects every element that can use the color property.
This is why the universal selector should usually be used for simple global rules, not detailed visual styling.
Why the Universal Selector Is Powerful
The universal selector can affect the whole document with one rule.
For example:
* { margin: 0;}
This removes margin from every element.
That includes:
bodyheadingsparagraphslistsformstablesfiguresblockquotessectionsarticles
This may be useful in a reset stylesheet, but it can also remove helpful default spacing.
A page with all margins removed may look cramped unless you add spacing back yourself.
Common Use: box-sizing: border-box
One of the most common uses of the universal selector is setting box-sizing.
Example:
*,*::before,*::after { box-sizing: border-box;}
This applies box-sizing: border-box to all elements and their pseudo-elements.
This rule is popular because it makes sizing more predictable.
With border-box, an element’s declared width includes its content, padding, and border.
For example:
.card { width: 300px; padding: 20px; border: 2px solid #cccccc;}
With box-sizing: border-box, the visible width stays at 300px.
Without it, the padding and border are added on top of the content width, making the element wider than 300px.
Why box-sizing Is a Good Universal Rule
The box-sizing rule is a good use of broad targeting because it creates a predictable layout foundation.
It does not force every element to have the same colour, size, margin, or font.
It simply changes how widths and heights are calculated.
That makes layouts easier to manage.
A common base rule is:
*,*::before,*::after { box-sizing: border-box;}
This is a practical and controlled use of the universal selector.
Universal Selector with Resets
The universal selector is sometimes used in CSS resets.
For example:
* { margin: 0; padding: 0;}
This removes default margin and padding from every element.
It creates a blanker starting point.
However, it also removes useful default spacing from elements such as:
headingsparagraphslistsblockquotesfieldsetsfigures
If you use this kind of reset, you should add your own spacing back.
For example:
p { margin-bottom: 1rem;} section { margin-bottom: 3rem;}
A reset should be followed by deliberate styling.
Universal Selector with Inherited Fonts
Another broad rule sometimes used in base CSS is:
button,input,select,textarea { font: inherit;}
This is not the universal selector, but it is a broad grouped rule.
It makes form controls inherit the page font.
You might be tempted to write:
* { font: inherit;}
This is usually too broad.
It may affect elements in ways you do not intend.
A more targeted selector list is better:
button,input,select,textarea { font: inherit;}
This targets only the form controls that commonly need font normalisation.
Be Careful with * { color: ... }
This rule is very broad:
* { color: navy;}
It applies to every element that can inherit or use the color property.
A better approach is usually to set text colour on the body:
body { color: navy;}
Many text elements inherit colour from the body.
This is usually cleaner and less forceful than applying color to every element directly.
Use inheritance when it makes sense.
Do not use the universal selector when a parent element can provide the same result more cleanly.
Be Careful with * { margin: 0; }
This rule removes all default margins:
* { margin: 0;}
It can be useful in some reset systems, but it can also make content harder to read.
For example, this HTML normally has readable spacing:
<h1>Article Title</h1> <p>First paragraph.</p> <p>Second paragraph.</p>
After removing all margins, the heading and paragraphs may sit too close together.
A more controlled approach is:
body { margin: 0;} p { margin-top: 0; margin-bottom: 1rem;} h1 { margin-top: 0; margin-bottom: 1.5rem;}
This removes the page edge margin but keeps readable content spacing.
Universal Selector Inside Another Selector
The universal selector can also be used inside another selector.
Example:
.card * { margin-top: 0;}
This selects every element inside .card.
HTML:
<article class=”card”> <h2>Card Title</h2> <p>Card text.</p> <a href=”lesson.html”>Read more</a></article>
The selector .card * targets the heading, paragraph, and link inside the card.
This can be useful, but it is still broad.
It affects every descendant inside .card, not just direct children.
Descendants vs Direct Children
This selector targets all descendants inside .card:
.card * { margin-top: 0;}
That means it can target elements nested deeply inside the card.
This selector targets only direct children:
.card > * { margin-top: 0;}
HTML:
<article class=”card”> <h2>Card Title</h2> <div> <p>Nested paragraph.</p> </div></article>
In this example, .card > * targets the <h2> and the <div> because they are direct children of .card.
It does not directly target the nested <p>.
The > symbol means direct child.
This can make broad targeting more controlled.
Useful Pattern: Spacing Direct Children
A common layout pattern is to add spacing between direct children.
Example:
.stack > * + * { margin-top: 1rem;}
This may look complex, but it has a useful meaning.
It selects every direct child inside .stack that has another direct child before it.
HTML:
<div class=”stack”> <h2>Title</h2> <p>First paragraph.</p> <p>Second paragraph.</p></div>
The first child does not get top margin.
The following children do.
This creates consistent spacing between items.
This is a more careful use of broad targeting.
What Is a Selector List?
A selector list lets you apply the same declarations to more than one selector.
For example:
h1,h2,h3 { line-height: 1.2;}
This applies the same line-height to all <h1>, <h2>, and <h3> elements.
The selectors are separated by commas.
A selector list helps avoid repeating the same declarations.
Instead of writing:
h1 { line-height: 1.2;} h2 { line-height: 1.2;} h3 { line-height: 1.2;}
you can write:
h1,h2,h3 { line-height: 1.2;}
This is shorter and easier to maintain.
Selector List Syntax
A selector list uses commas between selectors.
Example:
h1,h2,h3 { color: navy;}
Each selector is part of the same rule.
The declaration block applies to all of them.
Correct:
h1,h2,h3 { margin-top: 0;}
Incorrect:
h1h2h3 { margin-top: 0;}
Without commas, CSS reads the selector differently.
Commas are required when grouping separate selectors.
Grouping Type Selectors
You can group type selectors.
Example:
h1,h2,h3,p { margin-top: 0;}
This removes the top margin from headings and paragraphs.
Another example:
button,input,select,textarea { font: inherit;}
This applies the same font inheritance rule to several form controls.
Selector lists are useful when several element types need the same base style.
Grouping Class Selectors
You can group class selectors too.
Example:
.alert,.notice,.message { padding: 16px; border-radius: 6px;}
This applies the same padding and border radius to elements with any of these classes.
HTML:
<p class=”alert”>Important alert.</p><p class=”notice”>Useful notice.</p><p class=”message”>General message.</p>
All three elements receive the grouped styles.
You can then add separate styles for each type:
.alert { border: 1px solid red;} .notice { border: 1px solid orange;} .message { border: 1px solid blue;}
This avoids repeating the shared styles.
Grouping Mixed Selectors
A selector list can include different selector types.
Example:
h1,.page-title,#main-heading { line-height: 1.2;}
This rule applies to:
all h1 elementselements with class=”page-title”the element with id=”main-heading”
This is valid CSS.
However, mixed selector lists should be used carefully.
If selectors are too different in purpose, grouping them can make the stylesheet harder to understand.
Group selectors when they genuinely share the same styling reason.
Selector Lists Save Repetition
Without a selector list, you may repeat the same declarations:
h1 { font-family: Arial, sans-serif;} h2 { font-family: Arial, sans-serif;} h3 { font-family: Arial, sans-serif;}
With a selector list:
h1,h2,h3 { font-family: Arial, sans-serif;}
This is easier to maintain.
If you later change the font, you only change it once.
Selector lists are useful when the same style should apply to several selectors.
Group Only Shared Styles
A selector list should group styles that are genuinely shared.
Good:
h1,h2,h3 { line-height: 1.2;}
This makes sense because headings commonly share a tighter line height.
Less clear:
h1,button,.card,footer { margin-bottom: 20px;}
This groups unrelated elements.
It may work, but it is harder to understand.
If one selector needs to change later, the group may become awkward.
Only group selectors when the shared rule has a clear purpose.
Selector Lists and Mistakes
Be careful when writing selector lists.
This CSS is correct:
h1,h2,h3 { color: navy;}
This CSS is different:
h1 h2 h3 { color: navy;}
The second selector does not mean “h1, h2, and h3”.
It means an <h3> inside an <h2> inside an <h1>.
That is probably not what you want.
Use commas to group separate selectors.
Selector Lists and Invalid Selectors
In many cases, if one selector in a selector list is invalid, the whole selector list can fail.
For example:
h1,.invalid??,h2 { color: navy;}
The invalid selector can cause the browser to ignore the whole rule.
A safer approach is to avoid experimental or uncertain selectors inside large selector lists unless you know how they behave.
Keep selector lists clear and valid.
Broad Targeting
Broad targeting means writing selectors that affect many elements.
Examples:
* { box-sizing: border-box;}
p { margin-bottom: 1rem;}
h1,h2,h3,h4,h5,h6 { line-height: 1.2;}
Broad targeting is not bad by itself.
It is useful for base styles.
However, broad targeting should be deliberate.
Do not use broad selectors when you only want to style one component.
Good Broad Targeting
Good broad targeting creates a sensible foundation.
Examples:
*,*::before,*::after { box-sizing: border-box;}
body { margin: 0; font-family: Arial, sans-serif; line-height: 1.6;}
img { max-width: 100%; height: auto;}
button,input,select,textarea { font: inherit;}
These rules create a useful base for the whole page.
They are broad, but they have a clear purpose.
Risky Broad Targeting
Some broad targeting can cause unwanted effects.
Example:
* { border: 1px solid red;}
This adds a border to everything.
It might be useful temporarily for debugging, but it is not suitable as normal styling.
Another example:
div { padding: 20px;}
This affects every <div> on the page.
Since <div> is often used as a generic container, this can create unexpected spacing throughout the layout.
A class would usually be better:
.container { padding: 20px;}
Do Not Use * for Everything
The universal selector should not replace thoughtful selectors.
Less suitable:
* { font-size: 18px; color: navy; margin-bottom: 16px;}
This affects far too much.
It may change icons, buttons, form controls, layout elements, and nested components unexpectedly.
Better:
body { font-size: 18px; color: navy;} p { margin-bottom: 16px;}
Use inheritance and targeted selectors where possible.
Universal Selector and Performance
In modern browsers, simple use of the universal selector is usually not a major performance problem for normal websites.
The bigger concern is usually maintainability.
A rule like this:
* { margin: 0;}
may be easy to write, but it can make layout and spacing harder to manage if you are not careful.
The question is not only “Can the browser handle this?”
The better question is:
Is this selector clear?Is it necessary?Will it affect elements I did not intend to target?Will I need to undo it later?
Write broad selectors only when the broad effect is intentional.
Universal Selector and Specificity
The universal selector has very low specificity.
For example:
* { color: blue;} p { color: black;}
The paragraph will usually be black because the type selector p is more specific than *.
Another example:
* { box-sizing: content-box;} .card { box-sizing: border-box;}
Elements with class="card" use border-box because .card is more specific.
This low specificity is one reason the universal selector can be useful for base styles.
It is usually easy to override.
Selector Lists and Specificity
Each selector in a selector list keeps its own specificity.
Example:
h1,.page-title,#main-title { color: navy;}
The h1 selector has type selector specificity.
The .page-title selector has class selector specificity.
The #main-title selector has ID selector specificity.
They share the same declaration block, but each selector still matches elements according to its own specificity.
This matters when other CSS rules compete with them.
A Complete Example
HTML:
<!DOCTYPE html><html lang=”en”><head> <meta charset=”UTF-8″> <title>Universal Selector and Selector List Example</title> <link rel=”stylesheet” href=”styles.css”></head><body> <main class=”container”> <h1>CSS Selector Examples</h1> <p class=”intro”> This page uses a universal selector, grouped selectors, and careful broad targeting. </p> <section class=”card”> <h2>Universal Selector</h2> <p>The universal selector can apply a rule to every element.</p> </section> <section class=”card”> <h2>Selector Lists</h2> <p>Selector lists let several selectors share the same declarations.</p> </section> <form> <label for=”email”>Email address</label> <input type=”email” id=”email” name=”email”> <button type=”submit”>Subscribe</button> </form> </main> </body></html>
CSS:
/* Universal selector for predictable sizing */*,*::before,*::after { box-sizing: border-box;} /* Page defaults */body { margin: 0; font-family: Arial, sans-serif; line-height: 1.6; color: #222222;} /* Selector list for shared heading styles */h1,h2 { line-height: 1.2; margin-top: 0;} /* Selector list for form controls */button,input,select,textarea { font: inherit;} /* Broad but controlled image rule */img { max-width: 100%; height: auto;} /* Layout */.container { width: 90%; max-width: 900px; margin: 0 auto; padding: 40px 0;} /* Component */.card { padding: 24px; border: 1px solid #dddddd; margin-bottom: 24px;}
This example uses broad selectors for base styles and classes for component styling.
That balance keeps the CSS predictable.
How the Complete Example Works
This rule applies to all elements and pseudo-elements:
*,*::before,*::after { box-sizing: border-box;}
This creates predictable sizing.
This selector list applies shared heading styles:
h1,h2 { line-height: 1.2; margin-top: 0;}
This selector list applies font inheritance to form controls:
button,input,select,textarea { font: inherit;}
The .card class is used for repeated card styling:
.card { padding: 24px; border: 1px solid #dddddd; margin-bottom: 24px;}
The broad rules create a foundation.
The class rules style specific components.
Common Mistake: Using * Instead of body
Less suitable:
* { font-family: Arial, sans-serif; color: #222222;}
Better:
body { font-family: Arial, sans-serif; color: #222222;}
Many elements inherit font and colour from the body.
Using body is usually cleaner than forcing those styles onto every element.
Common Mistake: Removing All Spacing Without Replacing It
Less useful:
* { margin: 0; padding: 0;}
This removes useful default spacing from everything.
Better:
body { margin: 0;} p { margin-top: 0; margin-bottom: 1rem;} h1,h2 { margin-top: 0; margin-bottom: 1rem;}
This gives you control without making the page cramped.
Common Mistake: Forgetting Commas in Selector Lists
Incorrect:
h1 h2 h3 { color: navy;}
Correct:
h1,h2,h3 { color: navy;}
Without commas, the selector means something completely different.
Use commas when grouping separate selectors.
Common Mistake: Grouping Unrelated Selectors
Less clear:
h1,button,.footer,.card img { margin-bottom: 20px;}
This group mixes unrelated elements and purposes.
Better:
h1 { margin-bottom: 20px;} button { margin-bottom: 20px;} .footer { margin-bottom: 20px;} .card img { margin-bottom: 20px;}
Or better still, organise the spacing based on layout or component needs.
Grouping is useful only when the shared rule is genuinely meaningful.
Common Mistake: Broadly Styling All div Elements
Less suitable:
div { padding: 20px;}
This targets every <div> on the page.
Since <div> is often used for many different purposes, this can cause unexpected layout problems.
Better:
.container { padding: 20px;}
or:
.card { padding: 20px;}
Use classes when the style belongs to a specific layout or component.
Common Mistake: Using Universal Selector for Debugging and Forgetting to Remove It
A debugging rule might look like this:
* { outline: 1px solid red;}
This can help you see element boundaries.
However, it should usually be removed before publishing.
If you keep it, every element may show red outlines.
Debugging rules are useful temporarily, but they should not be left in production CSS unless intended.
Best Practices
Use the universal selector sparingly.
Use * for simple base rules such as box-sizing.
Avoid using * for detailed visual styling.
Use body for inherited global font and colour styles.
Use selector lists to reduce repeated declarations.
Separate selectors in a selector list with commas.
Group selectors only when they genuinely share the same styling purpose.
Avoid grouping unrelated selectors just because they currently share one value.
Be careful with broad rules such as div, section, or *.
Use classes for components and reusable styling.
Use direct-child patterns such as .container > * when broad targeting needs boundaries.
Inspect elements in browser developer tools if a broad selector causes unexpected styling.
Summary
The universal selector is written as:
*
It selects every element.
A common useful example is:
*,*::before,*::after { box-sizing: border-box;}
Selector lists let several selectors share one declaration block:
h1,h2,h3 { line-height: 1.2;}
The comma is important.
Without commas, the selector means something else.
Universal selectors and selector lists are useful for base styles, resets, shared typography, form control normalisation, and reducing repetition.
However, broad targeting should be deliberate.
The main idea is simple:
Use broad selectors for broad foundations.Use specific selectors for specific components.
When you use *, grouped selectors, and broad targeting carefully, your CSS becomes cleaner, more consistent, and easier to maintain.
