Question
I want to write a CSS selector that matches elements that do not have a specific class. For example, given 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 to write a CSS rule that selects 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?
In the real HTML, 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 exclude elements in CSS using the :not() pseudo-class. You will learn how to target elements that do not have a certain class or attribute, how selector specificity works in this situation, and how this pattern is used in real stylesheets such as print styles, component styling, and UI exclusions.
Concept
CSS can select elements not only by what they are, but also by what they are not. The main tool for this is the :not() pseudo-class.
If you want to match elements that do not have the class printable, you can use:
:not(.printable)
This means:
.targets a class.printablemeans “elements with the classprintable”:not(.printable)means “elements that do not have the classprintable”
This matters because real interfaces often need exclusion rules, such as:
- hide everything except printable content
- style all buttons except disabled ones
- target inputs that are not checked
- apply layout rules to items that are not marked special
You can also exclude attributes in the same way:
:not([disabled])
That matches elements that do not have a disabled attribute.
A key detail: :not() does not magically mean “every element on the page” unless your selector says so. It filters whatever selector it is attached to. For example:
*:not(.printable)
means “all elements except those with printable.”
And:
div:not(.printable)
means “all div elements except those with printable.”
Mental Model
Think of :not() like a filter on a guest list.
*means “everyone is invited”.printablemeans “people wearing a printable badge”*:not(.printable)means “everyone except people wearing that badge”
So :not() does not create a list by itself. It removes items from a list you already selected.
Another way to think about it:
- First choose the group
- Then remove the ones you do not want
That is exactly how CSS applies :not().
Syntax and Examples
The basic syntax is:
selector:not(condition)
Exclude a class
*:not(.printable) {
outline: 1px solid red;
}
This matches every element that does not have the printable class.
With your HTML:
<html class="printable">
<body class="printable">
<h1 class="printable">Example</h1>
<nav></nav>
<a href="#">Print me!</a>
<p class="printable">Text</p>
</body>
</html>
The selector *:not(.printable) would match:
nava
Exclude an attribute
input:not([disabled]) {
border: 1px solid green;
}
This styles only inputs that do not have the disabled attribute.
Exclude a specific type
*:not(nav) {
font-family: Arial, sans-serif;
}
This matches all elements except nav.
Practical print example
If you want to hide everything except printable content, a common rule is:
@media print {
*:not(.printable) {
display: none;
}
}
However, in real layouts this can be too broad because hiding parent elements can also hide children unexpectedly. Often a more targeted print strategy is better.
Step by Step Execution
Consider this CSS:
*:not(.printable) {
color: red;
}
And this HTML:
<div class="printable">A</div>
<div>B</div>
<p>C</p>
Here is what happens step by step:
-
*starts by matching all elements.div.printabledivp
-
:not(.printable)removes any element with theprintableclass.div.printableis removeddivstayspstays
-
The final matched elements are:
- second
div p
- second
-
CSS applies
color: red;only to those remaining elements.
Result:
Akeeps its normal colorBbecomes redCbecomes red
Another example with attributes:
button:not([disabled]) {
cursor: pointer;
}
Step by step:
- Match all
buttonelements - Remove those with a
disabledattribute - Apply
cursor: pointeronly to enabled buttons
Real World Use Cases
Print styles
A very common use of :not() is in print stylesheets:
@media print {
.page *:not(.printable) {
visibility: hidden;
}
}
This can be used to suppress menus, ads, sidebars, or controls.
Forms
Style only fields that users can interact with:
input:not([disabled]),
select:not([disabled]),
textarea:not([disabled]) {
background: white;
}
Navigation and menus
Highlight links except the current page:
nav a:not(.active) {
opacity: 0.7;
}
Cards and lists
Add spacing to all items except featured ones:
.card:not(.featured) {
border-color: #ddd;
}
Buttons
Apply hover styles only to buttons that are not disabled:
button:not([disabled]):hover {
background: #333;
color: white;
}
Real Codebase Usage
In real projects, developers often use :not() as a small exclusion tool, not as the entire styling strategy.
Common patterns
Guard-style exclusions
Developers often apply a default style and exclude a special case:
.button:not(.button--secondary) {
background: royalblue;
color: white;
}
This is similar to a guard clause in programming: “apply this unless it is the special case.”
Form validation
input:not([type="checkbox"]):not([type="radio"]) {
width: 100%;
}
This is common when text-like inputs should share layout rules but checkboxes and radios should not.
Progressive enhancement
.js-enabled .menu-item:not(.is-open) .submenu {
display: none;
}
This avoids hiding currently open items.
Utility-class exclusions
.stack > *:not(.visually-hidden) + *:not(.visually-hidden) {
margin-top: 1rem;
}
This pattern is used in design systems so spacing is not added around hidden utility elements.
Good practice
- Use
:not()when the excluded case is small and clear - Prefer descriptive class names
- Avoid overly broad selectors like
*:not(...)unless you truly want global behavior - Test carefully in print and layout scenarios because parent-child relationships matter
Common Mistakes
1. Forgetting to define the base selector
Broken example:
:not(.printable) {
color: red;
}
This is valid CSS, but beginners often misunderstand it. It means “any element that is not .printable,” which may be much broader than intended.
If you only want certain elements, be explicit:
body *:not(.printable) {
color: red;
}
2. Hiding too much with display: none
Broken example:
@media print {
*:not(.printable) {
display: none;
}
}
This may hide container elements and cause printable children to disappear too.
Safer approaches include:
- targeting specific sections
- styling a wrapper element
- using a dedicated print layout
3. Confusing “does not have this class” with “is not inside this class”
These are different:
*:not(.printable)
This means the element itself does not have the class.
.printable *
This means elements inside an element with that class.
4. Overusing universal selectors
This can be expensive and hard to maintain:
*:not(.printable) {
margin: 0;
}
Usually it is better to target a narrower scope.
5. Assuming :not() fixes poor HTML structure
If your print behavior depends on excluding many unrelated elements, the better solution may be to add a dedicated wrapper:
<div class="print-area">
...content...
</div>
Then style the wrapper directly instead of excluding many other elements.
Comparisons
| Selector | Meaning | Example | Best use |
|---|---|---|---|
.printable | Elements with the class | .printable | Target included items |
:not(.printable) | Elements without the class | *:not(.printable) | Exclude one class from a group |
[disabled] | Elements with an attribute | input[disabled] | Match by attribute presence |
:not([disabled]) | Elements without an attribute | input:not([disabled]) | Match enabled fields |
.container .item | Descendant selector | .menu a | Match by location in the DOM |
.container:not(.wide) | Exclude a class on the same element | .card:not(.featured) | Same-element filtering |
:not() vs adding a positive class
| Approach | Example | Pros | Cons |
|---|---|---|---|
Exclusion with :not() | *:not(.printable) | Quick for small exclusions | Can become broad and hard to reason about |
| Positive targeting | .printable | Clear intent | Requires styling only included elements |
| Wrapper-based targeting | .print-area * | Easier to maintain | Needs better HTML structure |
In many real projects, positive targeting or a wrapper-based approach is easier to maintain than excluding many items globally.
Cheat Sheet
/* Elements without a class */
*:not(.printable) {}
/* Specific element without a class */
div:not(.printable) {}
/* Elements without an attribute */
input:not([disabled]) {}
/* Multiple exclusions */
input:not([type="checkbox"]):not([type="radio"]) {}
/* Exclude an active item */
a:not(.active) {}
Rules to remember
:not()excludes matching elements- It filters the selector before it
*:not(.printable)means all elements except those withprintablediv:not(.printable)means onlydivelements without that class- You can exclude classes, attributes, element types, and more
- Be careful with
*because it is very broad - In print layouts, hiding everything except one class can fail if parent elements are hidden
Quick advice
- Use
:not()for small, clear exclusions - Prefer narrower selectors over global ones
- Consider wrapper classes for print or layout-specific styling
FAQ
Can CSS select elements that do not have a class?
Yes. Use the :not() pseudo-class, such as *:not(.printable).
How do I select elements that do not have an attribute in CSS?
Use :not([attribute]). For example, input:not([disabled]) selects enabled inputs.
Is :not(.class) valid CSS?
Yes. It is a standard CSS pseudo-class and is widely used.
What is the difference between :not(.printable) and .printable *?
:not(.printable) checks whether the element itself lacks the class. .printable * selects elements inside an element with that class.
Why does *:not(.printable) sometimes hide more than expected in print CSS?
Because if a parent element is hidden, its children disappear too, even if a child would otherwise match your intended rule.
Should I use :not() or add a special class to the elements I want?
If the included elements are few and well-defined, adding a positive class or wrapper is often easier to maintain. Use :not() when the exclusion is simpler than the inclusion.
Can :not() be combined with other selectors?
Yes. For example, button:not([disabled]):hover is very common.
Mini Project
Description
Create a small print-friendly article page where some content should appear in print and some content should stay on screen only. This project demonstrates how to use :not() to exclude non-printable elements and why selector scope matters.
Goal
Build a page where article content is printable, while navigation and action links are excluded from print styling.
Requirements
- Create an HTML page with a heading, paragraph text, a navigation area, and a print link.
- Add a
printableclass to the content you want treated as printable. - Use
:not()in CSS to style or hide elements that are not printable. - Include a print media rule.
- Keep the example simple and fully working.
Keep learning
Related questions
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Can HTML Checkboxes Be Readonly? Understanding readonly vs disabled in HTML Forms
Learn why HTML checkboxes do not support readonly, how disabled differs, and practical ways to prevent changes while still submitting values.
Can You Change `input type="date"` Format in HTML?
Learn how HTML date inputs format values, why you cannot force DD-MM-YYYY, and how to display custom date formats safely.