Skip to main content

Command Palette

Search for a command to run...

CSS Selectors 101: Targeting Elements with Precision

Published
10 min read
A

MERN Stack Developer

Introduction: The Problem of Styling

Imagine you're designing a website with hundreds of paragraphs, dozens of buttons, and multiple navigation menus. You want to:

  • Make all buttons blue

  • Style the main heading differently from subheadings

  • Change the color of text in the sidebar, but not in the main content

  • Make every third item in a list stand out

CSS selectors are the addressing system of web styling. They let you pinpoint exactly which HTML elements should receive your styles.

What Are CSS Selectors?

A CSS selector is a pattern that matches HTML elements on your page. Think of it as a filter or a search query that finds specific elements so you can apply styles to them.

structure of a CSS rule:

selector {
  property: value;
}

For example:

p {
  color: blue;
}

In this rule:

  • p is the selector (targeting paragraph elements)

  • color is the property (what you're styling)

  • blue is the value (how you're styling it)


Why CSS Selectors Are Essential

Before we dive into the types of selectors, let's understand why they are fundamental to web development:

1. Separation of Concerns Selectors let you keep your HTML structure separate from your styling. Your HTML describes what the content is, while CSS with selectors describes how it looks.

2. Efficiency Instead of styling each element individually with inline styles, you can target multiple elements at once:

/* Instead of adding style="" to 50 buttons... */
button {
  background-color: blue;
  color: white;
}

3. Consistency Selectors ensure consistent styling across your entire website. Change one rule, update hundreds of elements.

4. Maintainability When you need to update your design, you modify the CSS selectors and rules, not every individual HTML element.

5. Specificity and Control Different selector types give you different levels of control, from broad (style all paragraphs) to precise (style this one specific element).

Now let's explore the different types of selectors!


1. Element Selector

The element selector targets all elements of a specific type.

Syntax

elementname {
  /* styles */
}

Examples

Target all paragraphs:

p {
  font-size: 16px;
  line-height: 1.6;
}

Target all headings:

h1 {
  font-size: 32px;
  font-weight: bold;
  color: #333;
}

h2 {
  font-size: 24px;
  color: #555;
}

Target all links:

a {
  color: blue;
  text-decoration: none;
}

Before and After Example

HTML:

<p>First paragraph</p>
<p>Second paragraph</p>
<p>Third paragraph</p>

Without CSS (browser defaults):

  • Black text

  • Default font

  • Standard spacing

With Element Selector:

p {
  color: #2c3e50;
  font-size: 18px;
  margin-bottom: 20px;
}

After CSS:

  • All paragraphs are now dark gray (#2c3e50)

  • All have 18px font size

  • All have 20px spacing below them

Common Element Selectors

/* Typography */
h1, h2, h3, h4, h5, h6 { }
p { }
span { }

/* Layout */
div { }
section { }
article { }
header { }
footer { }
nav { }

/* Lists */
ul { }
ol { }
li { }

/* Tables */
table { }
tr { }
td { }
th { }

/* Forms */
input { }
button { }
textarea { }
select { }

/* Media */
img { }
video { }

2. Class Selector

The class selector targets elements with a specific class attribute. This is probably the most commonly used selector in CSS because it's flexible and reusable.

Syntax

.classname {
  /* styles */
}

Note the dot (.) before the class name!

HTML Setup

In your HTML, you add a class attribute to elements:

<p class="highlight">This paragraph is highlighted</p>
<p class="highlight">This one too</p>
<p>This one is not</p>

CSS Application

.highlight {
  background-color: yellow;
  font-weight: bold;
}

Multiple Classes

An element can have multiple classes, separated by spaces:

HTML:

<button class="btn primary large">Click Me</button>

CSS:

.btn {
  padding: 10px 20px;
  border: none;
  cursor: pointer;
}

.primary {
  background-color: blue;
  color: white;
}

.large {
  font-size: 18px;
}

The button gets styles from all three classes!

Before and After Example

HTML:

<div class="card">
  <h3>Card Title</h3>
  <p>Card content goes here</p>
</div>

<div class="card">
  <h3>Another Card</h3>
  <p>More content</p>
</div>

<div>
  <h3>Not a Card</h3>
  <p>Regular content</p>
</div>

Without CSS: All divs look the same—just plain text with no visual distinction.

With Class Selector:

.card {
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

After CSS:

  • First two divs have a card-like appearance with background, border, rounded corners, and shadow

  • Third div remains unstyled

  • Perfect for creating reusable UI components!

Naming Classes

Good class names:

.button { }
.nav-menu { }
.article-header { }
.text-center { }
.bg-blue { }
.div1 { }  /* not descriptive */
.thing { }  /* too vague */
.redText { }  /* describes appearance, not purpose */

Best practices:

  • Use descriptive, meaningful names

  • Use lowercase and hyphens (kebab-case)

  • Name based on purpose, not appearance

  • Keep names concise but clear


3. ID Selector

The ID selector targets a single, unique element on the page. Each ID should appear only once per page.

Syntax

#idname {
  /* styles */
}

Note the hash/pound symbol (#) before the ID name!

HTML Setup

<header id="main-header">
  <h1>Welcome to My Site</h1>
</header>

CSS Application

#main-header {
  background-color: #333;
  color: white;
  padding: 20px;
  text-align: center;
}

IDs vs Classes: Key Differences

FeatureIDClass
Symbol#.
Usage per pageOnce onlyMultiple times
SpecificityHigherLower
Best forUnique elementsReusable styles
Example#logo.button

Before and After Example

HTML:

<nav id="primary-navigation">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

<nav class="sidebar-nav">
  <ul>
    <li><a href="/profile">Profile</a></li>
    <li><a href="/settings">Settings</a></li>
  </ul>
</nav>

Without CSS: Both navigation menus look identical—just bullet lists.

With ID and Class Selectors:

#primary-navigation {
  background-color: #2c3e50;
  padding: 15px;
  position: fixed;
  top: 0;
  width: 100%;
}

#primary-navigation ul {
  list-style: none;
  display: flex;
  gap: 20px;
}

#primary-navigation a {
  color: white;
  text-decoration: none;
}

.sidebar-nav {
  background-color: #ecf0f1;
  padding: 10px;
  border-radius: 5px;
}

After CSS:

  • Primary navigation is a fixed header bar with horizontal layout

  • Sidebar navigation has a light background with vertical layout

  • Each maintains its unique styling


Important ID Rules

Rule 1: One ID per page

<!-- WRONG - ID used twice -->
<div id="special">First</div>
<div id="special">Second</div>

<!-- CORRECT - Each ID is unique -->
<div id="special-one">First</div>
<div id="special-two">Second</div>

Rule 2: IDs are case-sensitive

#Header { }  /* Different from... */
#header { }  /* ...this one */

Rule 3: No spaces in IDs

<!-- WRONG -->
<div id="my header">

<!-- CORRECT -->
<div id="my-header">

4. Group Selectors

Group selectors let you apply the same styles to multiple selectors at once. This keeps your CSS DRY (Don't Repeat Yourself).

Syntax

selector1, selector2, selector3 {
  /* styles apply to all */
}

Note the commas separating each selector!

Without Grouping (Repetitive)

h1 {
  color: #2c3e50;
  font-family: Arial, sans-serif;
}

h2 {
  color: #2c3e50;
  font-family: Arial, sans-serif;
}

h3 {
  color: #2c3e50;
  font-family: Arial, sans-serif;
}

With Grouping (Efficient)

h1, h2, h3 {
  color: #2c3e50;
  font-family: Arial, sans-serif;
}

/* Then add unique styles */
h1 { font-size: 32px; }
h2 { font-size: 24px; }
h3 { font-size: 20px; }

Mixed Selector Types

You can group different types of selectors together:

h1, .page-title, #main-heading {
  text-align: center;
  margin-bottom: 30px;
}

This targets:

  • All <h1> elements

  • All elements with class "page-title"

  • The one element with ID "main-heading"

Practical Examples

Example 1: Reset default margins

h1, h2, h3, h4, h5, h6, p, ul, ol {
  margin: 0;
  padding: 0;
}

Example 2: Button variations

.btn-primary, .btn-secondary, .btn-danger {
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 16px;
}

.btn-primary { background-color: blue; }
.btn-secondary { background-color: gray; }
.btn-danger { background-color: red; }

Example 3: Form elements

input, textarea, select {
  width: 100%;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-family: inherit;
}

Before and After Example

HTML:

<article>
  <h2>Article Title</h2>
  <p class="intro">This is the introduction...</p>
  <p>Main content paragraph...</p>
  <p class="conclusion">And the conclusion...</p>
</article>

Without Grouping:

.intro {
  font-weight: bold;
  font-style: italic;
  color: #555;
}

.conclusion {
  font-weight: bold;
  font-style: italic;
  color: #555;
}

With Grouping:

.intro, .conclusion {
  font-weight: bold;
  font-style: italic;
  color: #555;
}

5. Descendant Selectors

Descendant selectors target elements that are nested inside other elements. They let you create context-specific styles.

Syntax

ancestor descendant {
  /* styles */
}

Note: No comma, just a space between selectors!

Basic Example

HTML:

<nav>
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
  </ul>
</nav>

<footer>
  <ul>
    <li><a href="/privacy">Privacy</a></li>
    <li><a href="/terms">Terms</a></li>
  </ul>
</footer>

CSS:

/* Style links only in nav */
nav a {
  color: white;
  background-color: blue;
  padding: 10px;
}

/* Style links only in footer */
footer a {
  color: gray;
  font-size: 14px;
}

How It Works

The descendant selector looks for the second element anywhere inside the first element, no matter how deeply nested:

<div class="container">
  <p>Styled</p>
  <section>
    <article>
      <p>Also styled</p>
    </article>
  </section>
</div>
.container p {
  color: blue;
}

Both paragraphs turn blue because both are descendants (children, grandchildren, etc.) of .container.

Multiple Levels

You can chain descendant selectors:

/* Target links inside list items inside nav */
nav li a {
  text-decoration: none;
}

/* Target paragraphs inside articles inside main */
main article p {
  line-height: 1.8;
}

Combining with Other Selectors

Element + Class:

article .highlight {
  background-color: yellow;
}

Only highlights with class "highlight" that are inside articles.

Class + ID:

#sidebar .widget {
  border: 1px solid #ccc;
}

Only widgets inside the sidebar.

Class + Class:

.card .title {
  font-size: 20px;
  font-weight: bold;
}

Only titles inside cards.

Before and After Example

HTML:

<div class="blog-post">
  <h2>Post Title</h2>
  <p>Post introduction...</p>
  <div class="content">
    <p>Main content paragraph 1...</p>
    <p>Main content paragraph 2...</p>
  </div>
  <div class="comments">
    <p>Comment by user...</p>
    <p>Another comment...</p>
  </div>
</div>

Without Descendant Selectors: All paragraphs look the same.

With Descendant Selectors:

.blog-post .content p {
  font-size: 18px;
  line-height: 1.8;
  margin-bottom: 20px;
}

.blog-post .comments p {
  font-size: 14px;
  background-color: #f5f5f5;
  padding: 10px;
  border-left: 3px solid #ddd;
}

After CSS:

  • Content paragraphs are larger with generous spacing

  • Comment paragraphs are smaller with a gray background and left border

  • Same element type, completely different styling based on context!

Practical Use Cases

1. Navigation styling:

nav ul {
  list-style: none;
  padding: 0;
}

nav ul li {
  display: inline-block;
  margin-right: 15px;
}

nav ul li a {
  color: white;
  text-decoration: none;
}

2. Form sections:

.form-section label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

.form-section input {
  width: 100%;
  padding: 8px;
}

3. Card components:

.card img {
  width: 100%;
  border-radius: 8px 8px 0 0;
}

.card h3 {
  margin: 15px;
  color: #333;
}

.card p {
  margin: 0 15px 15px;
  color: #666;
}

When to Use Descendant Selectors

Use descendant selectors when:

  • Styling elements within a specific context

  • Creating component-specific styles

  • You need different styles for the same element in different locations

  • Building modular, scoped CSS

Be careful when:

  • The descendant chain is too long (harder to maintain)

  • You're selecting too broadly (might affect unintended elements)

  • Performance matters (descendant selectors are slower than classes)

Descendant vs Child Selector (Quick Note)

Descendant selector (space): Targets any nested element

div p { }  /* All paragraphs inside div, any depth */
div > p { }  /* Only paragraphs directly inside div */

6. Basic Selector Priority (Specificity)

When multiple CSS rules target the same element, the browser needs to decide which styles to apply. This is called specificity or selector priority.

The Basic Hierarchy

From lowest to highest priority:

1. Element selectors (lowest)

p { color: black; }

2. Class selectors

.text { color: blue; }

3. ID selectors (highest)

#special { color: red; }