CSS
Web Development
HTML
Web Design
Coding Tips

How can I use a not:first-child selector?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

The CSS selector :not(:first-child) targets every element that is not the first child of its parent container. It combines the negation pseudo-class :not() with :first-child to apply styles to all siblings except the first one. This is commonly used for adding spacing between list items, applying separators, or styling repeated components where the first element needs different treatment.

css
li:not(:first-child) {
  margin-top: 12px;
}

That single rule adds vertical spacing between list items without affecting the first one, eliminating the need for a separate class or an override rule.

How :not(:first-child) Works

The :first-child pseudo-class matches an element that is the first child of its parent. The :not() pseudo-class inverts whatever selector is passed to it. Combined, :not(:first-child) matches every child element that is not in the first position.

html
1<ul>
2  <li>Apple</li>    <!-- first-child, NOT matched -->
3  <li>Banana</li>   <!-- matched -->
4  <li>Cherry</li>   <!-- matched -->
5</ul>
css
li:not(:first-child) {
  color: #666;
}

In this example, "Banana" and "Cherry" receive the gray color. "Apple" retains the default color because it is the first child and therefore excluded by :not().

Practical Use Cases

Adding Separators Between Items

A common pattern is adding a top border to all items except the first to create visual separators:

css
1.menu-item:not(:first-child) {
2  border-top: 1px solid #e0e0e0;
3  padding-top: 8px;
4}

This avoids the extra top border above the first item that you would get with a blanket border-top rule.

Spacing Between Sections

When stacking sections on a page, you often want vertical spacing between them but not above the first one:

html
1<main>
2  <section class="content-block">Hero</section>
3  <section class="content-block">Features</section>
4  <section class="content-block">Pricing</section>
5</main>
css
.content-block:not(:first-child) {
  margin-top: 48px;
}

This is cleaner than applying margin-top to all sections and then overriding it on the first one with margin-top: 0.

Styling Form Fields

In a form with stacked inputs, you can add spacing between fields without a wrapper:

css
.form-group input:not(:first-child) {
  margin-top: 16px;
}

:not(:first-child) vs :not(:first-of-type)

These two selectors look similar but behave differently when the parent contains mixed element types.

html
1<div>
2  <h2>Title</h2>
3  <p>First paragraph</p>
4  <p>Second paragraph</p>
5</div>
css
1/* Matches <p> elements that are NOT the first child of <div> */
2/* Both <p> tags match, because <h2> is the actual first child */
3p:not(:first-child) {
4  color: blue;
5}
6
7/* Matches <p> elements that are NOT the first <p> in <div> */
8/* Only "Second paragraph" matches */
9p:not(:first-of-type) {
10  color: red;
11}
SelectorWhat It ChecksWhen to Use
:not(:first-child)Is this element the first child overall?Uniform lists of the same element type
:not(:first-of-type)Is this the first of its element type?Mixed-content containers with headings, paragraphs, etc.

Use :not(:first-of-type) when the parent contains different element types and you want to target all but the first of a specific type.

Combining With Other Selectors

:not() can be combined with classes, attributes, and other pseudo-classes for more precise targeting.

css
1/* All nav links except the first child */
2nav a:not(:first-child) {
3  margin-left: 16px;
4}
5
6/* All cards except the first child that also have .highlighted */
7.card.highlighted:not(:first-child) {
8  border-left: 4px solid #0066cc;
9}
10
11/* Exclude both first and last child */
12li:not(:first-child):not(:last-child) {
13  border-bottom: 1px solid #ccc;
14}

In CSS Selectors Level 4 (supported in modern browsers), :not() accepts a comma-separated list:

css
1/* Exclude first and last child in a single :not() */
2li:not(:first-child, :last-child) {
3  padding: 8px 0;
4}

Specificity

The :not() pseudo-class itself does not add specificity. However, the selector inside it does contribute. So :not(:first-child) has the same specificity as :first-child alone, which is one pseudo-class (specificity 0-1-0).

css
1/* Specificity: 0-1-1 (one element + one pseudo-class) */
2li:not(:first-child) { color: red; }
3
4/* Specificity: 0-1-1 (same weight) */
5li:first-child { color: blue; }

This means you will not run into unexpected specificity conflicts when using :not(:first-child) alongside :first-child rules. They have equal specificity, and normal cascade order applies.

Alternative Approaches

The Adjacent Sibling Selector

Before :not() was widely supported, developers used the adjacent sibling combinator to achieve similar results:

css
1/* Apply margin-top to every li that follows another li */
2li + li {
3  margin-top: 12px;
4}

This works for consecutive siblings of the same type. It does not require :not() and has broader legacy browser support, though this is rarely a concern today.

The Lobotomized Owl Selector

A general-purpose pattern that applies spacing between all adjacent siblings:

css
* + * {
  margin-top: 1.5em;
}

This is a broader solution that goes beyond :not(:first-child) but solves the same underlying problem of "spacing between items without extra space at the start."

Browser Compatibility

:not(:first-child) is supported in all modern browsers, including Chrome, Firefox, Safari, Edge, and Opera. It has been supported since IE 9 for the single-argument form. The Level 4 multi-argument form (:not(A, B)) is supported in Chrome 88+, Firefox 84+, and Safari 14+.

BrowserSingle-Arg :not()Multi-Arg :not()
Chrome4+88+
Firefox3.5+84+
Safari3.1+14+
Edge12+88+
IE9+Not supported

Common Pitfalls

Using :not(:first-child) when you actually mean :not(:first-of-type) is the most frequent mistake. In mixed-content containers, :first-child checks position among all siblings, not just siblings of the same type.

Forgetting that :not() does not add its own specificity can lead to confusion when debugging style overrides. The specificity comes from the selector argument inside :not(), not from :not() itself.

Applying :not(:first-child) at the wrong nesting level produces unexpected results. If you write div :not(:first-child), the space means any descendant that is not a first child, not just direct children. Use div > :not(:first-child) for direct children only.

Relying on :not(:first-child) for layout spacing instead of CSS gap is outdated in flexbox and grid contexts. If the parent is a flex or grid container, gap is simpler and more maintainable:

css
1.flex-container {
2  display: flex;
3  flex-direction: column;
4  gap: 12px;
5}

Summary

  • :not(:first-child) selects all elements except the first child of their parent.
  • Use it for spacing, separators, and conditional styling on repeated elements.
  • Use :not(:first-of-type) when the parent contains mixed element types.
  • The adjacent sibling selector (li + li) is a classic alternative for same-type sibling spacing.
  • In flexbox and grid layouts, prefer gap over margin-based :not(:first-child) patterns.
  • Specificity of :not(:first-child) equals one pseudo-class, same as :first-child alone.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.