AD JB Toolbox 01 EN

CSS Tutorial / CSS Combinators and Pseudo-Classes

Combinators select elements by their relationships in the HTML structure, while pseudo-classes select states or structural conditions. A child selector differs from a descendant selector, and :first-child refers to the first child element rather than the first element of a particular type.

Read parent, child, descendant, and sibling relationships

In the following structure, section is the parent of h2, paragraph A, div, and paragraph C. Paragraph B is a child of div, which is a descendant of section. A and C are siblings because they have the same parents, but A and B are not siblings because they have different parents. The HTML structure is more important than whether it looks close on the screen.

<section class="garden">
  <h2>Visitor Information</h2>
  <p>A: Operating hours</p>
  <div>
    <p>B: Greenhouse Guide</p>
  </div>
  <p>C: What you need</p>
</section>
section.garden
├─ h2
├─ p  ← A
├─ div
│  └─ p  ← B
└─ p  ← C
relationship notation selector Paragraph selected Paragraph not selected
space: descendant .garden p A, B, C p outside this section
>: direct child .garden > p A, C B takes the div one step further
+: the next sibling h2 + p A B has different parents and there is a div before C.
~: subsequent sibling h2 ~ p A, C B has a different parent than h2.

A combinator normally targets the element on its right. h2 + p styles the p immediately following an h2 as a sibling. Whitespace text nodes from indentation or line breaks do not interrupt this element-sibling relationship. For further detail, see Basic CSS Selectors: Type, Class, ID, and Attributes.

Compare descendant and child selectors

.garden p { color: #087f5b; }
.garden > p { border-left: 4px solid #087f5b; padding-left: 12px; }

The first rule makes all p in garden green. It contains B even if there is a div in the middle. The second rule adds a left border and margin only to the direct children A and C. Since color and border-left are different properties, A and C can have both green and border.

A descendant selector suits shared paragraph styling throughout a section. A direct-child selector can exclude paragraphs inside nested cards. Structure changes affect these matches; avoid chaining unnecessary child combinators that make the stylesheet depend on a rigid depth. See MDN: Combinators.

Compare next and subsequent siblings

h2 + p { background-color: #fff4cc; }
h2 ~ p { font-style: italic; }

The first rule gives paragraph A, the next element sibling of the heading, a yellow background. The second italicizes A and C because both are later p siblings of h2. B has a different parent and therefore does not match. Neither sibling combinator selects an earlier sibling.

If you insert <div>Additional notice</div> between h2 and A, the yellow background will disappear because A is no longer the immediate sibling. However, the condition that it follows h2 within the same parent holds, so the slant remains. Seeing this difference will save you from having to memorize + and ~ as “similar selectors.”

Select states and positions with pseudo-classes

a:hover { background-color: #fff4cc; }
a:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 3px; }
.plants li:first-child { font-weight: bold; }
.plants li:nth-child(odd) { background-color: #e9f7ef; }

:hover selects the state in which the pointer is raised. :focus-visible selects the state in which the browser determines that focus display is necessary, and is useful for checking when moving through tabs on the keyboard. :focus selects the focused state itself, so the meaning of the two is not completely the same. This example specifies an additional outline without removing the default focus indicator. You can continue practicing how to distinguish color and focus by state in an actual link in CSS Link States and Visible Keyboard Focus.

When you hover your mouse over the link, the background turns yellow, and when you tab to the link, a blue outline appears. In a touch environment, hover cannot be guaranteed to be always experienced by the user. Leave essential information, such as operating hours or link names, still readable by default.

:first-child selects if it is the first child element of its parent. :nth-child(odd) selects cases where the order of child elements is odd, such as 1, 3, or 5. The list of plants above only has li, so mint number 1 becomes bold and creates a background for items 1 and 3. If you use even instead of odd, numbers 2 and 4 are the targets.

p:first-child means “a p element that is its parent's first child,” rather than “the first p.” The first child of section in this example is h2, so .garden > p:first-child matches no paragraph. nth-child counts all sibling elements, not just elements with the same tag. Use a condition such as nth-of-type when you need positions within one element type. The MDN pseudo-class reference explains these state and position conditions.

Run the complete example

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Small Garden</title>
  <style>
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
    .garden p { color: #087f5b; }
    .garden > p { border-left: 4px solid #087f5b; padding-left: 12px; }
    h2 + p { background-color: #fff4cc; }
    h2 ~ p { font-style: italic; }
    .plants li:first-child { font-weight: bold; }
    .plants li:nth-child(odd) { background-color: #e9f7ef; }
    a:hover { background-color: #fff4cc; }
    a:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 3px; }
  </style>
</head>
<body>
<h1>Small Garden</h1>
  <section class="garden">
    <h2>Visitor Information</h2>
    <p>A: We open at 9am every day.</p>
    <div>
      <p>B: Please observe quietly in the greenhouse.</p>
    </div>
    <p>C: Bring a water bottle and comfortable shoes.</p>
  </section>
  <ul class="plants">
    <li>1: Mint</li>
    <li>2: Basil</li>
    <li>3: Rosemary</li>
    <li>4: Time</li>
  </ul>
  <a href="#contact">Go to the contact section</a>
  <h2 id="contact">Contact</h2>
  <p>Ask at the information desk.</p>
</body>
</html>

When you save and run, A·B·C are green, and only A·C has a left border. A has a yellow background, and A·C has italic text. The plant list has the first item in bold and the odd-numbered items have a light background. Check the links using the mouse and keyboard respectively. The letters A~C in front of paragraphs are letters written directly in the text to compare selection results.

Change the structure and test each condition

  1. Add one div between h2 and A. Verify that only the background of A disappears, leaving the italics and borders. After practicing, delete the added div.
  2. Make B a direct child of section by removing only the div tag surrounding paragraph B. Make sure B also has a left border and slant. Only A is still correct in the + condition. After confirmation, restore the div.
  3. Replace :nth-child(odd) with :nth-child(even). Check that the list background moves from numbers 1 and 3 to numbers 2 and 4, and that the bold letters for first-child still remain in number 1.
  4. Put your mouse away, click inside the page and tab to the link. Make sure the focus outline is visible and you can move to the contact section with Enter. If the browser address bar has focus, it returns to the page first.

Please check each condition separately. Changing only the color value to expand the selection range or adding hover to the keyboard focus issue will not solve the cause. In developer tools, you can compare with the ability to force the state to be turned on, but in the end, it is better to check the results visible to the user through actual tab movement and mouse movements.

More in This Category
CSS Tutorial / CSS Grid Basics: Tracks, Lines, and Item Placement

CSS Tutorial / CSS Grid Basics: Tracks, Lines, and Item Placement

Create a two-dimensional grid, distinguish lines, tracks, cells, and areas, and use fr, minmax(), and spans to place items.

CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

Refactor a small stylesheet without changing its layout, compare nesting and cascade layers, and check relative file paths and selector specificity.

CSS Tutorial / Flexbox Basics: Containers, Items, and Axes

CSS Tutorial / Flexbox Basics: Containers, Items, and Axes

Create a Flexbox container, distinguish direct children from nested content, and compare row, column, and their main and cross axes.

CSS Tutorial / Fluid CSS Layouts with min, max, and clamp

CSS Tutorial / Fluid CSS Layouts with min, max, and clamp

Build a bounded fluid layout, compare flexible sizes and spacing, and check that longer content fits without introducing horizontal page scrolling.

CSS Tutorial / CSS Overflow, Long Text Wrapping, and Ellipsis

CSS Tutorial / CSS Overflow, Long Text Wrapping, and Ellipsis

Compare scrolling, clipping, long-word wrapping, and single-line ellipsis, including keyboard access and minimum-size issues in layout containers.

CSS Tutorial / CSS Width, Height, min/max Limits, and box-sizing

CSS Tutorial / CSS Width, Height, min/max Limits, and box-sizing

Compare content-box and border-box sizing, percentage heights, fluid width limits, and the consequences of fixed heights for growing text.

CSS Tutorial / CSS position: relative, absolute, fixed, and sticky

CSS Tutorial / CSS position: relative, absolute, fixed, and sticky

Compare positioning modes in a complete example, identify containing blocks, and troubleshoot sticky limits and overlapping content.

CSS Tutorial / CSS Form States: Focus, Validation, disabled, and readonly

CSS Tutorial / CSS Form States: Focus, Validation, disabled, and readonly

Compare form states, create accessible labels and error messages, and inspect which enabled, disabled, and read-only fields enter submitted form data.

CSS Tutorial / CSS Link States and Visible Keyboard Focus

CSS Tutorial / CSS Link States and Visible Keyboard Focus

Compare link states in a working multi-file example, inspect keyboard focus, and understand browser privacy restrictions on visited-link styles.

CSS Tutorial / Apply CSS with Inline, Internal, and External Styles

CSS Tutorial / Apply CSS with Inline, Internal, and External Styles

Compare three ways to apply CSS, create a working external stylesheet, and diagnose common file-path and loading problems.