Question

How to Use :not() and :first-child in CSS Selectors

csscss-selectors

Question

I have a div element that contains several ul elements.

If I want to apply CSS only to the first ul, this works:

div ul:first-child {
  background-color: #900;
}

But when I try to apply CSS to every ul except the first one, I tried the following selectors:

div ul:not:first-child {
  background-color: #900;
}
div ul:not(:first-child) {
  background-color: #900;
}
div ul:first-child:after {
  background-color: #900;
}

These do not seem to work as expected. How do I write a CSS selector that means: "select each element except the first"?

Short Answer

By the end of this page, you will understand how :first-child, :not(), and related CSS selectors work together. You will also learn why :not(:first-child) sometimes appears not to work, how child position is actually calculated, and which selector patterns are best for targeting all elements except the first.

Concept

In CSS, pseudo-classes like :first-child let you select elements based on their position in the DOM. The selector :first-child matches an element only if it is the very first child of its parent.

The :not() pseudo-class excludes elements that match a condition. So this selector:

ul:not(:first-child)

means:

  • select every ul
  • except those that are the first child of their parent

This is valid CSS.

The important detail is that :first-child does not mean "the first ul". It means "an element that is the first child among all siblings".

So if your HTML looks like this:

<div>
  <h2>Title</h2>
  <ul>...</ul>
  <ul>...</ul>
  <ul>...</ul>
</div>

then none of the ul elements are :first-child, because the h2 comes first.

That is why many developers think :not(:first-child) is broken when the real issue is that they are testing the wrong structural condition.

If your real goal is "every ul except the first ul", the more precise selector is often:

div ul:not(:first-of-type)

or sometimes:

div ul + ul

depending on the HTML structure.

This matters in real programming because CSS selectors often depend on document structure. If you misunderstand how sibling position works, your styling can silently affect the wrong elements or none at all.

Mental Model

Imagine children standing in a line inside a room.

  • :first-child means the person standing in position 1, no matter what type of person they are.
  • :first-of-type means the first person wearing a specific uniform, such as the first ul among its siblings.
  • :not(...) means everyone except the people matching the rule inside it.

So:

  • ul:first-child = a ul that stands in the very first position
  • ul:not(:first-child) = all ul elements that are not standing in position 1
  • ul:not(:first-of-type) = all ul elements except the first ul

That last one is often what people really mean.

Take Quiz

Syntax and Examples

The core selectors are:

/* A ul only if it is the first child of its parent */
ul:first-child {
  background: #900;
}

/* Every ul that is not the first child */
ul:not(:first-child) {
  background: #900;
}

/* Every ul except the first ul among siblings */
ul:not(:first-of-type) {
  background: #900;
}

/* Every ul that directly follows another ul */
ul + ul {
  background: #900;
}

Example 1: When :not(:first-child) works

<div>
  <ul>First</ul>
  <ul>Second</ul>
  <ul>Third</ul>
</div>
div ul:not(:first-child) {
  background-color: #900;
  color: white;
}

This styles:

  • Second
  • Third

because the first ul is also the first child of the div.

Example 2: When you actually need :first-of-type

<div>
  <h2>Menu</h2>
  <ul>First</ul>
  <ul>Second</ul>
  <ul>Third</ul>
</div>
div ul:not(:first-of-type) {
  background-color: #900;
  color: white;
}

This styles:

  • Second
  • Third

It does not style the first ul, even though that ul is not the first child of the div.

Example 3: A simple and readable pattern

div ul + ul {
  background-color: #900;
}

This means: style any ul that comes immediately after another ul.

If your ul elements are consecutive siblings, this is often the cleanest solution.

Step by Step Execution

Consider this HTML:

<div>
  <ul>One</ul>
  <ul>Two</ul>
  <ul>Three</ul>
</div>

And this CSS:

div ul:not(:first-child) {
  background-color: #900;
}

Step-by-step

  1. CSS looks for every ul inside a div.
  2. It checks the first ul:
    • Is it the first child of its parent? Yes.
    • Because of :not(:first-child), it is excluded.
  3. It checks the second ul:
    • Is it the first child? No.
    • It matches, so the style is applied.
  4. It checks the third ul:
    • Is it the first child? No.
    • It matches, so the style is applied.

Now compare with this HTML

<div>
  <p>Intro</p>
  <ul>One</ul>
  <ul>Two</ul>
  <ul>Three</ul>
</div>

Using the same selector:

div ul:not(:first-child) {
  background-color: #900;
}

What happens now?

  1. CSS finds each ul inside the div.
  2. The first ul is checked:
    • Is it the first child? No, because the p is first.
    • So it matches.
  3. The second ul also matches.
  4. The third ul also matches.

Result: all three ul elements are styled.

That is why understanding the parent-child structure is essential.

Real World Use Cases

This selector pattern is common in real layouts where you want repeated items styled differently after the first one.

Common examples

  • Add spacing between list sections except before the first one
  • Add borders to repeated cards except the first card
  • Style navigation items after the first item
  • Apply margins to stacked form sections except the top section
  • Add separators between content blocks

Example: add spacing between repeated blocks

.section + .section {
  margin-top: 24px;
}

This avoids adding unnecessary spacing before the first section.

Example: style every menu except the first

.sidebar ul:not(:first-of-type) {
  border-top: 1px solid #ddd;
  padding-top: 12px;
}

Example: add a divider between items

.item + .item {
  border-top: 1px solid #eee;
}

This is often more maintainable than styling everything and then trying to remove the style from the first item.

Take Quiz

Real Codebase Usage

In real projects, developers usually choose the selector that best matches the document structure rather than forcing :not() everywhere.

Common patterns

1. Adjacent sibling selector for spacing

.card + .card {
  margin-top: 16px;
}

This is extremely common because it naturally means "every card after the first card".

2. :not(:first-of-type) for repeated tags

article p:not(:first-of-type) {
  margin-top: 1rem;
}

Useful when the repeated elements are the same tag type.

3. Utility classes in component systems

.menu-list + .menu-list {
  border-top: 1px solid #ccc;
}

Teams often prefer class selectors over raw tag selectors because they are easier to maintain.

4. Guarding against fragile HTML structure

Instead of writing:

div ul:not(:first-child)

many codebases prefer:

.menu > ul + ul

This is more specific and less likely to break if another element is inserted before the first ul.

Practical advice

  • Use :first-child when actual first position matters.
  • Use :first-of-type when first element of a given tag type matters.
  • Use + when you mean "every repeated sibling after another one".
  • Prefer classes in larger codebases for safer styling.

Common Mistakes

1. Writing :not:first-child instead of :not(:first-child)

This is invalid because :not must contain parentheses.

/* Broken */
ul:not:first-child {
  color: red;
}
/* Correct */
ul:not(:first-child) {
  color: red;
}

2. Confusing :first-child with :first-of-type

<div>
  <h2>Title</h2>
  <ul>A</ul>
  <ul>B</ul>
</div>
/* This matches both ul elements, not just the second one */
ul:not(:first-child) {
  background: pink;
}

Why? Because neither ul is the first child.

Use this instead:

ul:not(:first-of-type) {
  background: pink;
}

3. Using :after to select a different element

ul:first-child:after {
  background-color: #900;
}

This does not target other ul elements. It targets a pseudo-element created after the first ul.

4. Forgetting that sibling structure matters

Selectors like ul + ul only work when one ul directly follows another ul.

<div>
  <ul>One</ul>
  <p>Break</p>
  <ul>Two</ul>
</div>
ul + ul {
  background: yellow;
}

This does not match Two, because it follows a p, not another ul.

5. Styling by tag name in large projects

div ul:not(:first-of-type) {
  margin-top: 10px;
}

This may accidentally affect unrelated lists. Prefer classes when possible:

.menu-list:not(:first-of-type) {
  margin-top: 10px;
}

Comparisons

SelectorMeaningBest used whenExample
:first-childElement is the very first child of its parentPosition among all siblings mattersul:first-child
:first-of-typeFirst element of that tag type among siblingsFirst ul, first p, first li, etc. mattersul:first-of-type
:not(:first-child)Every matching element except those that are first childYou want all matching elements that are not in first positionul:not(:first-child)
:not(:first-of-type)Every matching element except the first of that typeYou want all ul elements except the first ulul:not(:first-of-type)
+Adjacent sibling selectorYou want elements that directly follow another matching elementul + ul

Which one should you choose?

  • Use ul:not(:first-child) if the first item is literally the first child.
  • Use ul:not(:first-of-type) if you mean "every ul except the first ul".
  • Use ul + ul if the ul elements are consecutive and you want a simple selector.

Recommended rule of thumb

If you are styling repeated siblings, + is often the clearest. If you are targeting by element type regardless of other sibling types, use :first-of-type.

Take Quiz

Cheat Sheet

/* First child of parent */
selector:first-child

/* Not the first child */
selector:not(:first-child)

/* First element of this type */
selector:first-of-type

/* Not the first element of this type */
selector:not(:first-of-type)

/* Any selector directly after same sibling pattern */
selector + selector

Quick rules

  • :not() must use parentheses.
  • :first-child checks position among all siblings.
  • :first-of-type checks position among siblings of the same tag type.
  • A + B matches B only if it comes immediately after A.

Useful examples

ul:not(:first-child) { ... }
ul:not(:first-of-type) { ... }
ul + ul { ... }

Best choice for "every ul except the first ul"

ul:not(:first-of-type)

or

ul + ul

Common invalid syntax

ul:not:first-child

Common misunderstanding

/* This does not mean 'every ul except the first ul' in all cases */
ul:not(:first-child)

It only means "every ul that is not the first child of its parent."

FAQ

Why does ul:not(:first-child) not work sometimes?

Because :first-child checks whether the element is the parent's first child overall. If another element appears before the first ul, then that ul is not :first-child, so it also gets matched.

What is the difference between :first-child and :first-of-type?

:first-child means first among all siblings. :first-of-type means first of a specific tag type among siblings.

How do I select every ul except the first ul?

Usually use:

ul:not(:first-of-type)

If the ul elements are consecutive siblings, you can also use:

ul + ul

Is :not:first-child valid CSS?

No. :not must contain parentheses, like this:

:not(:first-child)

When should I use ul + ul instead?

Use it when each later ul comes directly after another ul. It is often simpler and easier to read.

Can I use classes instead of tag selectors?

Yes, and that is often better in real projects. For example:

.menu-list + .menu-list {
  margin-top: 1rem;
}

Does :after help select all but the first element?

No. :after creates or styles a pseudo-element attached to a selected element. It does not select sibling elements.

Take Quiz

Mini Project

Description

Build a small stacked menu layout where only the menu sections after the first one get a top border and extra spacing. This demonstrates the difference between :first-child, :first-of-type, and the adjacent sibling selector in a practical UI pattern.

Goal

Create a menu page where repeated list blocks are styled only when they come after the first block.

Requirements

  • Create a container with a heading and three ul elements.
  • Keep the first ul visually plain.
  • Add spacing and a top border to the second and third ul only.
  • Use a selector that remains correct even when a heading appears before the first ul.
Take Quiz

Keep learning

Related questions

View more