Question
I want to write a CSS selector that matches all elements that do not have a specific class. For example, with this HTML:
<html class="printable">
<body class="printable">
<h1 class="printable">Example</h1>
<nav>
<!-- Some menu links... -->
</nav>
<a href="javascript:void(0)" onclick="self.print()">Print me!</a>
<p class="printable">
This page is super interesting and you should print it!
</p>
</body>
</html>
I would like a selector that targets all elements that do not have the printable class. In this example, that would match the nav and a elements.
Is this possible in CSS?
Also, in the real HTML I am working with, there will be many more elements without the printable class than with it.
Short Answer
By the end of this page, you will understand how to use the CSS :not() pseudo-class to select elements that do not have a certain class or attribute. You will also learn the limits of this approach, how it behaves with descendant elements, and how to apply it safely in real stylesheets.
Concept
CSS includes a pseudo-class called :not() that lets you match elements that do not meet a condition.
For this question, the key idea is:
:not(.printable)
This selector matches any element that does not have the class printable.
You can also use :not() with attributes, such as:
:not([disabled])
which matches elements that do not have the disabled attribute.
Why this matters
In real projects, you often need to:
- style everything except a special group
- hide non-printable parts of a page during printing
- exclude buttons, ads, menus, or helper UI from certain layouts
- target elements that are missing an attribute or class
The :not() selector is useful because it lets you express exclusion directly in CSS instead of adding extra classes everywhere.
Important detail
*:not(.printable) means:
- select every element
- except elements that themselves have class
printable
It does not mean “exclude anything inside a .printable element.” It only checks the element being matched.
That distinction is very important when styling nested content.
Mental Model
Think of :not() like a filter at a doorway.
- Every element walks toward the doorway.
- The filter checks one rule.
- If the element matches the excluded rule, it is blocked.
- If it does not match the excluded rule, it gets through.
For example:
*:not(.printable)
is like saying:
"Let in every element except those wearing the
printablebadge."
An element is judged by its own badge, not by its parent’s badge.
Syntax and Examples
The basic syntax is:
selector:not(condition)
Exclude a class
*:not(.printable) {
color: gray;
}
This matches every element that does not have class printable.
Exclude an attribute
input:not([disabled]) {
border: 1px solid green;
}
This styles only input elements that are not disabled.
Practical example for printing
@media print {
*:not(.printable) {
display: none;
}
}
This hides all elements that do not have the printable class.
More specific version
Sometimes you only want to target certain elements:
body *:not(.printable) {
opacity: 0.5;
}
This checks all descendants inside body and matches only those without the class.
Example using your HTML
<html class="printable">
<body class="printable">
<h1 class="printable">Example</h1>
<nav>Menu</nav>
<a href="#">Print me!</a>
<p class="printable">Text</p>
</body>
</html>
*:not(.printable) {
outline: 1px solid red;
}
Matched elements include:
nava
And also any other element in the document that does not have printable.
Not matched:
htmlbodyh1p
because they do have that class.
Step by Step Execution
Consider this HTML:
<div class="printable">Report</div>
<nav>Menu</nav>
<a href="#">Print</a>
<p class="printable">Important text</p>
And this CSS:
*:not(.printable) {
background: yellow;
}
Step-by-step
- CSS starts checking each element in the document.
- For
<div class="printable">, the element has classprintable.:not(.printable)fails.- The rule does not apply.
- For
<nav>, the element does not have classprintable.:not(.printable)passes.- The rule applies.
- For
<a href="#">, the element does not have classprintable.- The rule applies.
- For
<p class="printable">, the element has classprintable.- The rule does not apply.
Result
Only these elements are styled:
<nav>Menu</nav>
<a href="#">Print</a>
One subtle case
If you have this:
<div class="printable">
<span>Inside printable block</span>
</div>
and use:
*:not(.printable) {
color: red;
}
the <span> will be matched because the span itself does not have class printable, even though its parent does.
That is often surprising to beginners.
Real World Use Cases
Here are common situations where :not() is useful:
Print styles
Hide navigation, buttons, and controls when printing:
@media print {
.page *:not(.printable) {
display: none;
}
}
Form styling
Style all inputs except disabled ones:
input:not([disabled]) {
background: white;
}
Navigation and UI exclusions
Apply spacing to all list items except the last one:
li:not(:last-child) {
margin-bottom: 8px;
}
Content theming
Style all cards except featured cards differently:
.card:not(.featured) {
opacity: 0.8;
}
Data tables
Highlight rows that are not marked hidden:
tr:not(.hidden) {
background: #fff;
}
Real Codebase Usage
In real codebases, developers often use :not() in a few practical patterns.
1. Excluding special cases
Instead of creating many extra classes, developers often write one general rule and exclude special elements:
.button:not(.button-secondary) {
background: blue;
color: white;
}
2. Guarding styles
A rule can apply broadly while protecting elements that should behave differently:
input:not([type="checkbox"]):not([type="radio"]) {
width: 100%;
}
3. Print and export layouts
Pages often contain controls that should not appear in output:
@media print {
.toolbar,
.sidebar,
.actions {
display: none;
}
}
Sometimes this is clearer than trying to hide everything with :not().
4. Combining with utility classes
In modern CSS, utility classes are common. Developers may exclude one utility state from a base rule:
.alert:not(.is-hidden) {
padding: 12px;
}
5. Scoped selection
Developers usually avoid global selectors like *:not(...) unless necessary, because broad selectors can be harder to reason about. More often, they scope them:
.article-content :not(.printable) {
font-family: Arial, sans-serif;
}
Scoping helps keep styles predictable.
Common Mistakes
Mistake 1: Thinking :not(.printable) excludes children of .printable
Broken assumption:
<div class="printable">
<span>Text</span>
</div>
*:not(.printable) {
color: red;
}
Many beginners expect the span not to match. But it does match, because the span itself does not have class printable.
How to avoid this:
- remember that CSS matches each element individually
- if needed, write a more specific structure-based selector
Mistake 2: Using :not() too broadly
*:not(.printable) {
display: none;
}
This can affect many more elements than expected, including layout wrappers and nested content.
How to avoid this:
- scope the selector to a specific container
- test with realistic HTML structure
Mistake 3: Confusing class absence with attribute absence
A class is part of the class attribute, but .printable and [class] are different ideas.
:not(.printable) /* element does not have class printable */
:not([class]) /* element has no class attribute at all */
These are not equivalent.
Mistake 4: Overusing exclusion when inclusion is clearer
Sometimes this is harder to maintain:
*:not(.printable) {
display: none;
}
A clearer pattern may be:
.printable {
display: block;
}
or explicitly hiding known UI areas:
nav, .toolbar, .actions {
display: none;
}
Mistake 5: Forgetting browser support differences in older CSS levels
Modern browsers support :not() well, but older CSS versions had more restrictions on what could go inside it.
Safe beginner usage:
:not(.printable)
:not([disabled])
These are straightforward and widely used.
Comparisons
| Selector | Meaning | Example Match | Common Use |
|---|---|---|---|
.printable | Elements with class printable | <p class="printable"> | Include a special group |
:not(.printable) | Elements without class printable | <nav> | Exclude a special group |
[class] | Elements that have any class attribute | <div class="box"> | Match elements with classes |
:not([class]) | Elements with no class attribute | <nav> | Find unclassed elements |
[disabled] | Elements with a disabled attribute | <input disabled> | Target disabled controls |
:not([disabled]) | Elements without a disabled attribute | <input> | Style active controls |
:not() vs adding a helper class
| Approach | Example | Best when |
|---|---|---|
Use :not() | button:not(.secondary) | One exception from a general rule |
| Use a helper class | .non-printable | You want explicit control and easier maintenance |
*:not(.printable) vs explicit selectors
| Approach | Pros | Cons |
|---|---|---|
*:not(.printable) | Short and expressive | Can match too much |
nav, a, .toolbar | Clear and predictable | Needs manual updates |
In many real projects, explicit selectors are easier to maintain when the excluded group is small and known.
Cheat Sheet
Core syntax
:not(selector)
Common examples
:not(.printable)
input:not([disabled])
li:not(:last-child)
button:not(.secondary)
Match elements without a class
*:not(.printable)
Match elements without an attribute
input:not([disabled])
Important rule
:not() checks the current element, not its parent or children.
Useful reminders
.printable= has classprintable:not(.printable)= does not have classprintable[class]= has any class attribute:not([class])= has no class attribute at all
Safer practice
Prefer scoped selectors when possible:
.article *:not(.printable)
instead of:
*:not(.printable)
Printing example
@media print {
nav,
.toolbar,
.actions {
display: none;
}
}
This is often clearer than hiding everything except one class.
FAQ
Can CSS select elements that do not have a certain class?
Yes. Use the :not() pseudo-class:
:not(.printable)
How do I select all elements without the printable class?
Use:
*:not(.printable)
This matches every element that does not have that class.
Does :not(.printable) exclude children inside a .printable element?
No. It only checks the element being matched. A child inside .printable still matches if the child itself does not have the class.
Can I use :not() with attributes?
Yes. For example:
input:not([disabled])
This matches inputs that are not disabled.
Is *:not(.printable) a good idea for print CSS?
Sometimes, but it can be too broad. If you know which elements should be hidden, explicit selectors like nav, .toolbar, .sidebar are often easier to maintain.
What is the difference between :not(.printable) and :not([class])?
:not(.printable)means the element does not have classprintable:not([class])means the element has noclassattribute at all
Can :not() contain multiple conditions?
Yes, depending on the selector and browser support. A common pattern is chaining:
input:not([type="checkbox"]):not([type="radio"])
This excludes both checkboxes and radio buttons.
Mini Project
Description
Build a simple print-friendly article page. The page contains content that should be printable and interface elements that should stay on screen only. This project demonstrates how to use :not() and how to decide when explicit selectors may be clearer than broad exclusion rules.
Goal
Create a small page where printable content remains visible in print mode while navigation and action links are hidden.
Requirements
- Create an HTML page with a heading, article text, a navigation block, and a print link.
- Add the class
printableto the content that should remain visible for printing. - Write CSS that visually distinguishes printable and non-printable parts on screen.
- Add a print stylesheet using
@media print. - Ensure the navigation and print link do not appear when printing.
Keep learning
Related questions
Angular ngClass Conditional Class Binding Explained
Learn how to use Angular ngClass for conditional classes, fix common binding mistakes, and understand why this template error happens.
CSS Font Scaling Relative to Container Size: %, em, rem, vw, and Responsive Text
Learn how CSS font scaling really works and how to make text responsive using %, em, rem, vw, clamp(), and media queries.
CSS Parent Selector Explained: Selecting a Parent <li> from an <a>
Learn whether CSS has a parent selector, how :has() works, and practical alternatives for styling a parent li from a child anchor.