Selecting elements: type, class and ID
A CSS rule has two halves: which elements, and what to do to them. This lesson is entirely about the first half, because getting it wrong is the commonest reason CSS "does not work".
Type selectors
The simplest selector is an element's name:
p {
color: dimgray;
}
Every <p> on the page, styled. No dot, no hash — just the tag name as it
appears in the HTML.
h1 { color: darkgreen; }
ul { margin: 0; }
button { cursor: pointer; }
Type selectors are blunt by design. They are right for setting a baseline — all paragraphs on this site look like this — and wrong the moment you want some paragraphs different from others.
Class selectors
A class labels elements as a kind. In the HTML:
<p class="price">350 rupees</p>
<p class="price">280 rupees</p>
<p>Open until six.</p>
In the CSS, a dot in front of the name:
.price {
font-weight: bold;
color: crimson;
}
The two prices are bold and red. The third paragraph is untouched.
The dot never goes in your HTML
This is the mistake that catches nearly everyone, and it is worth stating as plainly as possible.
Wrong:
<p class=".price">350 rupees</p>
Right:
<p class="price">350 rupees</p>
The dot is CSS punctuation meaning "class". It is not part of the name. Put
it in the HTML and you have created a class literally called .price — dot
included — which .price in your stylesheet will never match.
And because CSS fails silently, nothing tells you. The rule is valid, the stylesheet loads, and the text simply is not red. If a class rule is doing nothing, check the HTML attribute before you touch the CSS.
The same applies to # for IDs.
Several classes on one element
Separate them with spaces:
<p class="price discounted">280 rupees</p>
That is two classes, price and discounted — not one class with a space in
it. Both rules apply:
.price {
font-weight: bold;
color: crimson;
}
.discounted {
text-decoration: line-through;
}
The element is bold, red and struck through. This is what makes classes powerful: you compose small, single-purpose styles rather than writing one big rule per element.
ID selectors
An ID names one specific element. In the HTML:
<section id="todays-menu">
In the CSS, a hash:
#todays-menu {
border-top: 2px solid darkgreen;
}
An ID must be unique in the document — one element, one ID, once per page.
Use classes for styling, not IDs
Both work. Prefer classes anyway, and the reason is specificity.
An ID selector is dramatically harder to override than a class — roughly, one ID
outweighs any number of classes. Style your layout with IDs and you will spend
next month fighting your own stylesheet, reaching for !important to undo
something you wrote in week one.
The one-line version: classes are reusable and easy to override; IDs are
neither. Keep IDs for what they are actually good at — linking to a section
with #todays-menu, and connecting a <label> to its form field.
Combining selectors
Stick a class onto a type selector to narrow it:
p.price {
color: crimson;
}
That is paragraphs that have the class price — no space between them. A
<span class="price"> would not match.
Two classes together, again with no space:
.price.discounted {
color: darkorange;
}
Elements that have both classes. Only the element carrying both.
The space is the thing to watch, and it changes the meaning completely:
.card .title { } /* a .title somewhere INSIDE a .card */
.card.title { } /* one element with BOTH classes */
One space, entirely different rule. When a selector matches nothing you expect, check for a stray space first.
The universal selector
* matches everything:
* {
box-sizing: border-box;
}
You will meet this exact rule constantly — it is in almost every real
stylesheet, for reasons the box model lesson explains. Beyond that, use *
sparingly: it does a lot of work for something you rarely need.
Grouping
A comma applies one block to several selectors:
h1, h2, h3 {
font-family: Georgia, serif;
}
Each part before a comma is a complete selector in its own right. h1, h2 means
h1 elements and h2 elements — never "h2 inside h1".
Choosing well
A short guide that will serve you for a long time:
- Type selector for a site-wide baseline —
body,p,a - Class for everything else, which is most of the time
- ID for links and labels, not for styling
Name classes for what the thing is, not what it looks like:
.price { } /* good — still makes sense if you change the colour */
.red-bold-text { } /* bad — meaningless the day it turns green */
The second name is a promise you will eventually break, and then you have a
class called red-bold-text that is green.
Together
<section id="todays-menu">
<h2>Today's menu</h2>
<p class="price">Biryani — 350 rupees</p>
<p class="price discounted">Pulao — 280 rupees</p>
<p class="note">Cash only.</p>
</section>
#todays-menu {
border-top: 2px solid darkgreen;
}
h2 {
color: darkgreen;
}
.price {
font-weight: bold;
}
.discounted {
color: darkorange;
}
.note {
font-style: italic;
color: dimgray;
}
One ID for the section, a type selector for the heading, classes for everything that repeats or varies. No dots or hashes anywhere in the HTML.
Next: combinators — selecting by relationship, such as links inside the navigation only. If a class rule is refusing to apply, re-read the dot rule above; it is nearly always that.
Prefer learning with a teacher?
WasiLearn Academy runs small-group classes covering this material, online and in Karachi.
See the classes