Question

CSS :not() Selector for Excluding a Class or Attribute

htmlcsscss-selectors

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
  • .printable means “elements with the class printable”
  • :not(.printable) means “elements that do not have the class printable”

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”
  • .printable means “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().

Take Quiz

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:

  • nav
  • a

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:

  1. * starts by matching all elements.

    • div.printable
    • div
    • p
  2. :not(.printable) removes any element with the printable class.

    • div.printable is removed
    • div stays
    • p stays
  3. The final matched elements are:

    • second div
    • p
  4. CSS applies color: red; only to those remaining elements.

Result:

  • A keeps its normal color
  • B becomes red
  • C becomes red

Another example with attributes:

button:not([disabled]) {
  cursor: pointer;
}

Step by step:

  1. Match all button elements
  2. Remove those with a disabled attribute
  3. Apply cursor: pointer only 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;
}
Take Quiz

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

SelectorMeaningExampleBest use
.printableElements with the class.printableTarget included items
:not(.printable)Elements without the class*:not(.printable)Exclude one class from a group
[disabled]Elements with an attributeinput[disabled]Match by attribute presence
:not([disabled])Elements without an attributeinput:not([disabled])Match enabled fields
.container .itemDescendant selector.menu aMatch 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

ApproachExampleProsCons
Exclusion with :not()*:not(.printable)Quick for small exclusionsCan become broad and hard to reason about
Positive targeting.printableClear intentRequires styling only included elements
Wrapper-based targeting.print-area *Easier to maintainNeeds better HTML structure

In many real projects, positive targeting or a wrapper-based approach is easier to maintain than excluding many items globally.

Take Quiz

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 with printable
  • div:not(.printable) means only div elements 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.

Take Quiz

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 printable class 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.
Take Quiz

Keep learning

Related questions

View more