Himanshu SharmaCOBOX Technologies
Let’s talk

CSS · Lesson 3 of 29

Selectors

Target exactly the elements you want with type, class, id, descendant, child, group, attribute and pseudo-class selectors, with live examples.

14 minGetting startedUpdated 16 October 2026

By the end of this lessonWrite selectors that target elements by type, class, id, position and state, and combine them precisely.

Choosing what to style

A selector is the part of a rule that decides which elements it applies to. Get selectors right and CSS feels easy; get them wrong and styles land in the wrong places or refuse to apply. This lesson covers the selectors you will use 95% of the time.

The three basic selectors

html
<style>
  p { color: #555; }              /* type: every paragraph */
  .highlight { background: gold; } /* class: every element with class="highlight" */
  #intro { font-size: 1.3em; }    /* id: the one element with id="intro" */
</style>

<p id="intro">This paragraph is the introduction.</p>
<p>A normal paragraph.</p>
<p class="highlight">A highlighted paragraph.</p>
<h2 class="highlight">Classes work on any element</h2>
Selector Example Matches
Type p Every p element
Class .highlight Every element whose class list includes highlight
ID #intro The element with id="intro"
Universal * Every element

You can join a type and a class with no space to be more precise: p.highlight matches only paragraphs with that class. An element with class="card featured" is matched by both .card and .featured, and by .card.featured, which needs both classes at once.

Use classes for styling. They are reusable and easy to override. IDs are unique by definition, and their high specificity makes them hard to override later, which is why many teams avoid them in CSS altogether.

Combinators: elements in relation to others

Combinators select elements based on where they are in the HTML tree.

html
<style>
  nav a { color: white; text-decoration: none; }  /* any link inside nav */
  nav { background: #234; padding: 8px; }
  ul.steps > li { font-weight: bold; }             /* only direct children */
  h2 + p { font-style: italic; }                   /* the p right after an h2 */
</style>

<nav><a href="#">Home</a> · <a href="#">Courses</a></nav>
<a href="#">A link outside the nav stays blue</a>

<ul class="steps">
  <li>Step one
    <ul><li>A detail (not bold)</li></ul>
  </li>
  <li>Step two</li>
</ul>

<h2>Section title</h2>
<p>The first paragraph after the heading is italic.</p>
<p>The second one is not.</p>
Combinator Example Meaning
Space (descendant) nav a a anywhere inside nav
> (child) ul > li li directly inside ul, not deeper
+ (next sibling) h2 + p the p immediately after an h2
~ (later siblings) h2 ~ p every p after an h2, sharing its parent

Grouping with commas

When several selectors need the same styles, list them with commas instead of repeating the rule:

css
h1, h2, h3 {
  font-family: Georgia, serif;
  color: #222;
}

Attribute selectors

Match elements by their attributes and values:

css
input[type="email"] { border-color: teal; }  /* exact value */
a[href^="https"] { font-weight: bold; }      /* value starts with */
a[href$=".pdf"]::after { content: " (PDF)"; } /* value ends with */
img:not([alt]) { outline: 4px solid red; }   /* images missing alt text */

The last line is a handy trick while building a page: it outlines every image that is missing its alt text, so you can fix them. The ^= and $= patterns may remind you of regular expressions; the Regex Tester is useful when you get to real pattern matching in JavaScript.

Pseudo-classes: states and positions

A pseudo-class starts with a colon and matches an element in a particular state or position.

html
<style>
  a:hover { color: tomato; }
  button:focus-visible { outline: 3px solid orange; }
  li:first-child { color: green; }
  li:nth-child(even) { background: #eef; }
  input:invalid { border: 2px solid crimson; }
</style>

<p><a href="#">Hover over this link</a></p>
<button>Press Tab to focus me</button>
<ul>
  <li>First (green)</li><li>Second</li><li>Third</li><li>Fourth</li>
</ul>
<input type="email" placeholder="Type something that is not an email">

Common ones: :hover, :focus-visible (keyboard focus), :active (being pressed), :first-child, :last-child, :nth-child(n) (odd, even or a formula like 3n), :checked, :disabled, :invalid and :not(...).

Always style :focus-visible when you change how links or buttons look. Keyboard users rely on the focus outline to know where they are on the page.

Keep selectors short

A selector such as body div.main ul li a span works, but it is fragile (any change to the HTML breaks it) and very hard to override. Aim for one or two parts, usually a class: .menu-link. Short selectors are easier to read, faster to change and play nicely with the cascade, which is the next lesson.

Common mistakes

  • Forgetting the dot or hash: highlight { ... } looks for an element called <highlight>, which does not exist.
  • Adding a space by accident: p .note (paragraph containing a .note) is very different from p.note (a paragraph with class note).
  • Expecting > to reach deeper levels. It only matches direct children.
  • Removing focus outlines with outline: none and not replacing them.

Exercise

Paste this HTML into an editor and write CSS that: makes all links in the footer grey; makes only the direct li children of .menu bold; gives every second row of the table a light background; and turns any link to a PDF red.

html
<ul class="menu">
  <li>Home</li>
  <li>Shop
    <ul><li>Shoes</li><li>Bags</li></ul>
  </li>
</ul>
<table>
  <tr><td>Mon</td><td>10-6</td></tr>
  <tr><td>Tue</td><td>10-6</td></tr>
  <tr><td>Wed</td><td>Closed</td></tr>
  <tr><td>Thu</td><td>10-6</td></tr>
</table>
<footer>
  <a href="/privacy">Privacy</a> <a href="/price-list.pdf">Price list</a>
</footer>
Show one possible answer
css
footer a { color: grey; }
.menu > li { font-weight: bold; }
.menu li li { font-weight: normal; } /* nested items inherit bold, so reset them */
tr:nth-child(even) { background: #f2f2f2; }
a[href$=".pdf"] { color: red; }

The nested list items look bold at first even though > only matched the outer items. That is inheritance: text inside a bold item is bold too. You will learn exactly how it works in the inheritance lesson.

Key points

  • Type selectors (p) match every element of that type; class selectors (.card) match a class; id selectors (#main) match one element.
  • A space means 'inside' (nav a); > means 'direct child' (ul > li); a comma groups selectors (h1, h2).
  • Attribute selectors match on attributes, such as a[href^="https"].
  • Pseudo-classes match states and positions: :hover, :focus-visible, :first-child, :nth-child(2n).
  • Prefer classes for styling; keep selectors short so they stay easy to override.

Check yourself

1. Which selector matches every element with class="price"?
2. What does nav a match?
3. What does h1, h2 { color: navy; } do?
4. Which selector styles a button only while the mouse is over it?

Free tools for this lesson