Question

CSS :not() Selector for Elements Without a Class or Attribute

csshtmlcss-selectors

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 printable badge."

An element is judged by its own badge, not by its parent’s badge.

Take Quiz

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:

  • nav
  • a

And also any other element in the document that does not have printable.

Not matched:

  • html
  • body
  • h1
  • p

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

  1. CSS starts checking each element in the document.
  2. For <div class="printable">, the element has class printable.
    • :not(.printable) fails.
    • The rule does not apply.
  3. For <nav>, the element does not have class printable.
    • :not(.printable) passes.
    • The rule applies.
  4. For <a href="#">, the element does not have class printable.
    • The rule applies.
  5. For <p class="printable">, the element has class printable.
    • 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;
}
Take Quiz

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

SelectorMeaningExample MatchCommon Use
.printableElements 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

ApproachExampleBest when
Use :not()button:not(.secondary)One exception from a general rule
Use a helper class.non-printableYou want explicit control and easier maintenance

*:not(.printable) vs explicit selectors

ApproachProsCons
*:not(.printable)Short and expressiveCan match too much
nav, a, .toolbarClear and predictableNeeds manual updates

In many real projects, explicit selectors are easier to maintain when the excluded group is small and known.

Take Quiz

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 class printable
  • :not(.printable) = does not have class printable
  • [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 class printable
  • :not([class]) means the element has no class attribute 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.

Take Quiz

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

Keep learning

Related questions

View more