Skip to content

CSS Tutorial CSS Pseudo-classes

CSS :not(), :is() and :has()

Lesson 122 of 182 2 min read By Deepak Paswan Updated Oct 4, 2026

These four make long selectors shorter and let you express things that used to be impossible.

:not(): everything except

index.html
HTML
<style>
  li:not(.done) { font-weight: bold; }
  li.done { color: #888; text-decoration: line-through; }
</style>
<ul><li>Write the post</li><li class="done">Pick a title</li><li>Add images</li></ul>

li:not(.done) matches list items that do not have the class done.

:is(): a shorter list of alternatives

These two are equal:

style.css
CSS
header a:hover, nav a:hover, footer a:hover { color: #d94a00; }

:is(header, nav, footer) a:hover { color: #d94a00; }

:where(): the same, with zero strength

:where() works like :is() but adds no specificity, so rules written with it are easy to override. It is excellent for base styles and resets. See CSS Specificity.

style.css
PHP
:where(h1, h2, h3) { margin-block: 0.5em; }

:has(): select a parent by its children

:has() is called “the parent selector”. It matches an element that contains something.

index.html
HTML
<style>
  .card { border: 1px solid #ddd; padding: 10px; margin-bottom: 8px; border-radius: 8px; }
  .card:has(.pic) { background: #fdf2e9; }
  .card:has(input:checked) { border-color: #1a5276; background: #f4f9fc; }
  .pic { display: inline-block; width: 30px; height: 30px; background: #d94a00; vertical-align: middle; }
</style>
<div class="card"><span class="pic"></span> A card with a picture</div>
<div class="card">A text-only card</div>
<div class="card"><label><input type="checkbox"> Select this card</label></div>

Tick the checkbox and the whole card changes. Without :has() that needed JavaScript.

Support

:is(), :where() and :not() work everywhere. :has() is supported by all current major browsers, but check Can I use if you have to support older ones.