Skip to main content

Command Palette

Search for a command to run...

CSS Selectors 101: Targeting Elements with Precision

Published
8 min read
A

I'm a Software engineer and recently graduated (2025) in computer engineering, I'm more into Fullstack Developement using Angular, Nodejs, Express js, Mongodb, currently getting my hands on React js and Next js. Connect me on Linkedin here: https://linkedin.com/in/amanpatel2529

Writing CSS without selectors is like trying to give instructions in a crowded room without using anyone’s name.

You shout:
“Hey… someone… become blue!”

Nobody knows who you mean.

Selectors are how you tell the browser exactly which elements you want to style:

p{
  color: blue;
}

Here p is the selector. It says:

“Find all <p> elements and make their text blue.”

In this guide we’ll cover:

  • Why selectors are needed

  • Element, class, ID, group and descendant selectors

  • Basic selector priority and where your CSS lives (inline, internal, external, !important)

  • How these fundamentals show up in atomic CSS, Bootstrap, Tailwind CSS, and shadcn/ui


Why do we need CSS selectors?

HTML only describes structure:

<h1>My Blog</h1>
<p>Welcome to my blog.</p>

CSS adds presentation (colors, spacing, fonts).
Selectors are the bridge between them.

Real‑world example would be:

  • You’re a teacher in a classroom.

  • “All students, open your books.” → element selector.

  • “Students wearing red T‑shirts, stand up.” → class selector.

  • Roll number 7, come here.” → ID selector.

Selectors are different ways of addressing elements on the page.


Element selectors – by tag name

Element (type) selectors choose elements by HTML tag name.

HTML:

<h1>Welcome to Chaicode</h1>
<p>This is a paragraph.</p>
<p>This is another paragraph.</p>

CSS:

p{
  color: blue;
}

All <p> elements turn blue.

More examples:

body{
  font-family: system-ui, sans-serif;
}

h1{
  font-size: 2.5rem;
}

a{
  text-decoration: none;
}

Use element selectors for broad, default styles:

  • “All paragraphs look like this.”

  • “All headings use this font.”


Class selectors – reusable labels

Classes are labels you can share across many elements.

HTML:

<p class="highlight">Important information.</p>
<p>Normal text.</p>
<p class="highlight">Another important line.</p>

CSS:

.highlight {
  background-color: yellow;
}

.highlight is a class selector.
It targets any element with class="highlight".

Result:

  • Only the two “highlighted” paragraphs get a yellow background.

  • The middle paragraph stays normal.

You can reuse a class on different tags:

<h2 class="highlight">Warning</h2>
<p class="highlight">Please read carefully.</p>

Both share the same CSS.

When to use:
Whenever you want reusable styling you can apply to multiple elements.


ID selectors – one unique element

An id is meant to be unique on a page.

HTML:

<h1 id="main-title">My Blog</h1>
<p>Welcome to my blog.</p>

CSS:

#main-title {
  text-transform: uppercase;
  color: darkred;
}

#main-title is an ID selector.
It targets the element with id="main-title" (ideally just one).

Use IDs for one‑off special cases:
the main hero section, a specific banner, a unique button.

For reusable styles, prefer classes over IDs.


Group selectors – same style, different selectors

If several selectors share the same styles, you can group them with commas.

Instead of:

h1{
  font-family: system-ui;
}

h2{
  font-family: system-ui;
}

h3{
  font-family: system-ui;
}

Write:

h1,
h2,
h3 {
  font-family: system-ui;
}

This says:

“Apply this font family to h1, h2, and h3.”

You can group any selectors:

p,
li,
a {
  font-size: 16px;
}

Group selectors keep your CSS shorter and easier to maintain.


Descendant selectors – elements inside other elements

Sometimes you only want to style elements inside a certain container.

HTML:

<div class="card">
  <h2>Card title</h2>
  <p>This paragraph should be gray.</p>
</div>

<p>This paragraph should stay black.</p>

CSS:

.card p {
  color: gray;
}

Read it as:

“Select all <p> elements that are inside .card.”

Result:

  • The paragraph inside .card becomes gray.

  • The paragraph outside .card stays black.

Another example:

nav a {
  color: white;
}

All <a> links inside <nav> become white, links outside don’t.

Descendant selectors help you scope your styles to specific sections.


Selector priority (specificity): ID vs class vs element

Sometimes multiple selectors match the same element.
Which style wins?

Example:

p{
  color: black;
}

.highlight{
  color: blue;
}

#main-text{
  color: red;
}

HTML:

<p id="main-text" class="highlight">Hello</p>

All three selectors apply:

  • p

  • .highlight

  • #main-text

The final color will be red.

Very high‑level rule:

#id selectors are stronger than .class selectors,
which are stronger than element selectors.

So:

#id > .class > element

There are more rules (inline styles, !important, etc.),
but this simple order will already fix many beginner bugs.


Where your CSS lives: inline, internal, external, and !important

Selectors are one part of the story.
Where the CSS is written also matters when rules conflict.

Common places to write CSS:

  1. External stylesheet – separate file like style.css

     <link rel="stylesheet" href="style.css">
    
  2. Internal stylesheet – inside a <style> tag in your HTML <head>:

     <style>
       p { color: green; }
     </style>
    
  3. Inline style – directly in the element:

     <p style="color: blue;">Hello</p>
    

If all three try to style the same property on the same element, and their selectors are otherwise equal, the rough strength order is:

!important > inline style > internal <style> > external stylesheet > browser default

Mini example

external.css

p{
  color: red;
}

index.html

<head>
  <link rel="stylesheet" href="external.css">
  <style>
    p { color: green; }
  </style>
</head>
<body>
  <p style="color: blue;">Hello world</p>
</body>

Who wins?

  • External says red

  • Internal says green

  • Inline says blue

The text shows as blue (inline is stronger than internal and external).

Now if you change external.css to:

p{
  color: red !important;
}

Then red wins even over the inline style="color: blue".

That’s what !important does: it jumps to the front of the line.

Use !important sparingly—mainly for quick overrides or debugging.
If you use it everywhere, your CSS becomes hard to reason about.

Combine this with the earlier rule and you get a simple mental model:

  • !important is strongest

  • Then inline style

  • Then internal <style>

  • Then external CSS

  • Within each layer, #id > .class > element


How these basics show up in modern CSS: Atomic CSS & frameworks

Today most projects don’t write plain CSS from scratch only.
We also use:

  • Atomic / utility CSS

  • Frameworks like Bootstrap and Tailwind CSS

  • Component libraries like shadcn/ui

Under the hood, all of these are still just CSS selectors, mostly class selectors.

Let’s connect the dots.


Atomic CSS – many tiny class selectors

Atomic CSS (utility‑first CSS) means:

  • Each class does one small job (one property or a handful).

  • You compose many small classes on an element.

Example (simple atomic CSS you might write yourself):

.mt-4        { margin-top: 1rem; }
.text-center { text-align: center; }
.text-blue   { color: blue; }

HTML:

<p class="mt-4 text-center text-blue">
  Utility classes are tiny building blocks.
</p>

Each of .mt-4, .text-center, .text-blue is a class selector
that targets any element using that class.

Atomic CSS encourages:

  • Many small, predictable class selectors

  • Very little custom “one‑off” CSS

Tailwind CSS is the most popular real‑world example of this idea.


Bootstrap – prebuilt class selectors via CDN

Bootstrap is a classic CSS framework that comes with lots of ready‑made class selectors like:

  • btn, btn-primary, container, row, col, alert, etc.

Using Bootstrap quickly with a CDN

In a basic HTML file, you can include Bootstrap using its CDN link:

<head>
  <!-- Always copy the latest from getbootstrap.com -->
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
  >
</head>

Now you can write:

<div class="container mt-4">
  <h1 class="mb-3">Bootstrap Example</h1>
  <button class="btn btn-primary">Save</button>
</div>

Here:

  • .container, .mt-4, .mb-3, .btn, .btn-primary are Bootstrap class selectors.

  • You’re not writing the CSS yourself, you’re using existing selectors.

Your knowledge of class selectors tells you exactly how these work:
any element with those classes will get the framework’s styles.


Tailwind CSS – atomic CSS at scale

Tailwind CSS is a utility‑first (atomic) CSS framework.

Instead of writing:

.btn {
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
  background-color: #3b82f6;
  color: white;
}

You write all styling directly as classes:

<button class="px-4 py-2 rounded-md bg-blue-500 text-white">
  Save
</button>

Each piece is a tiny utility:

  • px-4 → horizontal padding

  • py-2 → vertical padding

  • rounded-md → border radius

  • bg-blue-500 → background color

  • text-white → text color

Under the hood Tailwind generates CSS like:

.px-4       { padding-left: 1rem; padding-right: 1rem; }
.py-2       { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.rounded-md { border-radius: 0.375rem; }
.bg-blue-500{ background-color: #3b82f6; }
.text-white { color: #ffffff; }

Again: class selectors everywhere.

Quick Tailwind via CDN (for practice)

For quick learning (not production), you can use:

<head>
  <script src="https://cdn.tailwindcss.com"></script>
</head>

Then:

<div class="min-h-screen flex items-center justify-center bg-slate-100">
  <h1 class="text-3xl font-bold text-slate-800">
    Hello Tailwind
  </h1>
</div>

You are still just attaching classes to elements; Tailwind’s selectors do the rest.


shadcn/ui – Tailwind classes turned into components

shadcn/ui is a React component library built on top of Tailwind CSS.

  • You run a CLI command to add a component (Button, Card, Dialog, etc.)

  • It generates actual React components in your project

  • Those components use Tailwind utility classes inside

Simplified example:

<button
  className="inline-flex items-center justify-center rounded-md
             bg-primary px-4 py-2 text-sm font-medium
             text-primary-foreground shadow-sm"
>
  Button
</button>

Each of those class names (inline-flex, items-center, bg-primary, etc.)
maps to a Tailwind utility → CSS class selector.

Stack view:

  • Selectors (especially classes) – core CSS concept

  • Tailwind – big collection of atomic class selectors

  • shadcn/ui – prebuilt React components that combine Tailwind classes

So even in modern setups, selectors are still doing all the styling work.


Recap

You’ve seen that:

  • Selectors are how you choose which HTML elements get which CSS.

  • The basic selectors you must know are:

    • Element: p, h1, div

    • Class: .highlight

    • ID: #main-title

    • Group: h1, h2, h3

    • Descendant: .card p, nav a

  • Selector strength roughly follows: #id > .class > element

  • CSS source order & location matters:
    !important > inline > internal <style> > external stylesheet

  • Atomic CSS and frameworks (Bootstrap, Tailwind, shadcn/ui) mostly rely on class selectors behind the scenes

Once you’re comfortable targeting elements with precision,
everything else in CSS—layouts, animations, responsive design, component libraries—becomes much easier.