Web Development Tutorial

How To Use Relationships to Select HTML Elements with CSS

Practical guide to CSS combinators: descendant, child, general (+) and adjacent (~) sibling selectors, plus pseudo-classes like :first-child and :nth-child with examples.

Drake Nguyen

Founder · System Architect

3 min read
How To Use Relationships to Select HTML Elements with CSS
How To Use Relationships to Select HTML Elements with CSS

Introduction

CSS combinators are relationship-based CSS selectors that let you target elements based on their position in the DOM tree rather than only on classes or IDs. Using combinator selectors you can scope styles with precision: choose descendants, immediate children, or siblings, and combine those with CSS pseudo-classes such as :first-child, :last-child, :only-child, and :nth-child(). This guide explains how to use CSS combinators and shows clear examples for practical tasks like styling navigation, lists, and adjacent elements.

Prerequisites

  • Basic familiarity with CSS selectors and specificity.
  • An editor to create an index.html and a styles.css file.
  • A browser to test how selectors apply to the DOM.

Quick setup

Create two files: index.html and styles.css. Add the HTML body content and link the stylesheet in your page head (not shown here). The examples below focus on the element relationships so you can practice how each CSS combinator works.

Descendant combinator (space)

The descendant selector matches any element that has a specified ancestor. Use it to scope styles to elements nested anywhere within another element.


Descendant selector demo

Paragraph outside blockquote.

Paragraph inside blockquote.

/* styles.css snippet */ .descendant blockquote { border-left: 4px solid indigo; background: lavender; padding: 1rem; } .descendant p { line-height: 1.5; } .descendant blockquote p { font-size: 1.15rem; color: #222; }

Child combinator (>)

The child selector matches only elements that are direct children of a parent. Use it when you want to style top-level children but not deeper nested elements—for example, top-level navigation links.


Direct child paragraph (styled).

Nested paragraph (not matched).

/* CSS */ .child > p { color: forestgreen; /* child selector CSS example */ }

General sibling combinator (~)

The general sibling combinator selects elements that share the same parent and come after a specified element, regardless of whether they are adjacent. This is useful for dynamically ordered content where you want to style all following siblings.


First paragraph (anchor)

Nested - not a sibling of the anchor

Second paragraph (sibling)

Third paragraph (sibling)

/* CSS */ .general-sibling p ~ p { color: lightseagreen; /* CSS general sibling selector example */ } /* or using different element types: */ .general-sibling div ~ p { border-top: 1px solid #f00; }

Adjacent sibling combinator (+)

The adjacent sibling selector targets only the immediate next sibling. Use it when you need to style an element only if it follows another specific element.


Paragraph A

Paragraph B (gets a top rule because it follows A)

Paragraph C (does not follow the previous p directly)

/* CSS */ .adjacent-sibling p + p { border-top: 1px solid #000; padding-top: 1rem; } .adjacent-sibling div + p { border-top: 1px solid red; }

CSS pseudo-classes: first-child, last-child, only-child

Pseudo-class selectors refine selection by position within the parent. They are commonly used with combinators to handle edge cases in lists or generated content.


  • First item
  • Middle item
  • Last item
/* CSS */ ul { list-style: none; margin: 1rem 0; padding: 0; } ul li { padding: 0.5rem 0.75rem; background: hsl(120,50%,95%); border: 1px solid hsl(120,50%,80%);} ul > li:first-child { border-radius: 0.75rem 0.75rem 0 0; } ul > li:last-child { border-radius: 0 0 0.75rem 0.75rem; } ul > li:only-child { border-radius: 0.75rem; } /* Remove duplicate borders between adjacent list items */ ul li + li { border-top: none; }

nth-child pseudo-class

The :nth-child() pseudo-class targets children by position or by pattern. It supports keywords like odd and even, specific numbers, and arithmetic expressions (for example 3n).


  1. One
  2. Two
  3. Three
  4. Four
  5. Five
  6. Six
  7. Seven
/* CSS */ ol { padding: 0; list-style-position: inside; } ol li { padding: 0.25rem; } ol li:nth-child(even) { background: aliceblue; } ol li:nth-child(odd) { background: lavenderblush; } ol li:nth-child(4) { background: indigo; color: white; }

When to use each combinator

  • Descendant selector: scope styles to any nested element inside an ancestor.
  • Child selector: apply styles only to immediate children (navigation, header lists).
  • General sibling (~): style all subsequent siblings after a chosen element.
  • Adjacent sibling (+): style the element that directly follows another element.
  • Combine with pseudo-classes to handle first/last/only or positional patterns like nth-child.

Conclusion

Understanding CSS combinators and related CSS pseudo-classes gives you powerful, maintainable ways to select elements based on DOM relationships. Whether you are writing relationship-based selectors to style navigation links, create zebra-striped lists with nth-child, or add separators with adjacent sibling selectors, these techniques help keep your CSS targeted and semantic. Experiment with the snippets above to learn how CSS combinators behave in real pages.

Stay updated with Netalith

Get coding resources, product updates, and special offers directly in your inbox.