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-childmeans the person standing in position 1, no matter what type of person they are.:first-of-typemeans the first person wearing a specific uniform, such as the firstulamong its siblings.:not(...)means everyone except the people matching the rule inside it.
So:
ul:first-child= aulthat stands in the very first positionul:not(:first-child)= allulelements that are not standing in position 1ul:not(:first-of-type)= allulelements except the firstul
That last one is often what people really mean.
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:
SecondThird
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:
SecondThird
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
- CSS looks for every
ulinside adiv. - It checks the first
ul:- Is it the first child of its parent? Yes.
- Because of
:not(:first-child), it is excluded.
- It checks the second
ul:- Is it the first child? No.
- It matches, so the style is applied.
- 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?
- CSS finds each
ulinside thediv. - The first
ulis checked:- Is it the first child? No, because the
pis first. - So it matches.
- Is it the first child? No, because the
- The second
ulalso matches. - The third
ulalso 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.
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-childwhen actual first position matters. - Use
:first-of-typewhen 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
| Selector | Meaning | Best used when | Example |
|---|---|---|---|
:first-child | Element is the very first child of its parent | Position among all siblings matters | ul:first-child |
:first-of-type | First element of that tag type among siblings | First ul, first p, first li, etc. matters | ul:first-of-type |
:not(:first-child) | Every matching element except those that are first child | You want all matching elements that are not in first position | ul:not(:first-child) |
:not(:first-of-type) | Every matching element except the first of that type | You want all ul elements except the first ul | ul:not(:first-of-type) |
+ | Adjacent sibling selector | You want elements that directly follow another matching element | ul + 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 "everyulexcept the firstul". - Use
ul + ulif theulelements 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.
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-childchecks position among all siblings.:first-of-typechecks position among siblings of the same tag type.A + BmatchesBonly if it comes immediately afterA.
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.
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
ulelements. - Keep the first
ulvisually plain. - Add spacing and a top border to the second and third
ulonly. - Use a selector that remains correct even when a heading appears before the first
ul.
Keep learning
Related questions
Angular ngClass Conditional Class Binding Explained
Learn how to use Angular ngClass for conditional classes, fix common binding mistakes, and understand why this template error happens.
CSS :not() Selector for Elements Without a Class or Attribute
Learn how to use the CSS :not() selector to target elements that do not have a specific class or attribute, with examples and common pitfalls.
CSS Font Scaling Relative to Container Size: %, em, rem, vw, and Responsive Text
Learn how CSS font scaling really works and how to make text responsive using %, em, rem, vw, clamp(), and media queries.