CSS Tutorial
CSS Specificity
When two rules match, the more specific selector wins. Inline and !important sit above that.
Two rules, one winner
CSS does not error when two declarations set the same property on the same element. It picks a winner. Source order matters only when the selectors are equally specific: the rule that appears later in the stylesheet wins. When one selector is more specific, it wins even if it comes first.
Think of a ladder, not a mystery score. Inline styles sit at the top of everyday work. Then ids. Then classes, attributes, and most pseudo-classes. Then element names and pseudo-elements. Universal* adds nothing.
| Kind | Example | Beats |
|---|---|---|
| Inline style | style="color: teal;" | id, class, and element rules |
| Id | #hours | classes and elements |
| Class, attribute, pseudo-class | .card, [open], :hover | elements |
| Element, pseudo-element | p, ::before | only a less specific element chain, or a tie broken by order |
Click Try it in CSS under an example. That opens /css/try. Change which rule comes last and watch which color survives.
Class beats element
Harbor studio sets every paragraph to slate, then a class paints the notice teal. The class wins even though the element rule is written second.
Example
<style>
body {
font-family: Georgia, serif;
margin: 1.25rem;
background: #f0f9ff;
}
.notice {
color: #0d9488;
}
p {
color: #64748b;
}
</style>
<h1>Harbor studio</h1>
<p class="notice">Open 8–16 — the class wins, even though p comes later.</p>
<p>This line uses the element rule.</p>Count the parts: p is one element. .notice is one class. A class outranks an element. Swapping the two rules would not change the notice color.
Id beats class
An id is meant to be unique on the page. CSS treats it as heavier than any number of classes you are likely to stack while learning. Use ids for skip links and form labels. Prefer a class when you only need a style hook.
Example
<style>
body {
font-family: Georgia, serif;
margin: 1.25rem;
background: #f0f9ff;
}
#desk {
color: #0c4a6e;
font-weight: 700;
}
.notice {
color: #0d9488;
font-weight: 400;
}
</style>
<h1>Harbor studio</h1>
<p id="desk" class="notice">Ask at the desk — the id wins over the class.</p>Inline beats id
A style attribute is more specific than a stylesheet id. That is why a quick inline test “always works” — and why a forgotten inline color is so hard to override later from a class.
Example
<style>
body {
font-family: Georgia, serif;
margin: 1.25rem;
background: #f0f9ff;
}
#desk {
color: #0c4a6e;
}
</style>
<h1>Harbor studio</h1>
<p id="desk" style="color: #0d9488;">
Inline teal wins over the id in the stylesheet.
</p>Equal specificity falls back to order. Two classes on two rules: whichever declaration comes last wins. That is the cascade you already used in the introduction, now with a name.
!important, mentioned once
!important after a value jumps the fight. It beats inline styles. Two !importantdeclarations then fall back to specificity and order again. It is a last resort, not a habit. There is a whole chapter on it after variables. Skip it for Harbor studio until a third-party sheet leaves you no other door.
If a class is not winning, do not reach for !important first. You probably have an id, an inline style, or a more specific selector later in the file. Fix that. Keep the ladder short: elements for defaults, classes for meaning, ids rarely.
What to do next
You can now predict a color fight. The next chapters are visual: rounded corners, gradients, shadows, and transforms. Specificity still applies — a class on a card will beat a bare div rule that setsborder-radius.
| Habit | Why |
|---|---|
| Style with classes | Reusable, medium weight, easy to override |
| Avoid inline styles in production | They beat almost everything in your sheet |
| One id per page, rarely for CSS | Ids are heavy and not reusable |
Worked examples
The short listings above show one property. These sheets paint documents you would actually ship: a lab dashboard, a clinic form, a marks table, a nav bar.
CSS does not invent meaning. HTML already said what the pieces are. Cascade, specificity, and the box model decide how they look. The numbers are classroom values — current, pH, pulse, 3-4-5 — so the style has something real to sit on.
Preview them in the CSS editor at /css/try. Change one property and watch the page paint. The tags stay the same.
Engineering
Class beats tag on a status line
A type selector is (0,0,1). A class is (0,1,0). An id is (1,0,0). Inline style sits above that. !important is a last resort above almost everything.
When two rules tie, source order wins — the one that appears last. .lead here beats p because the class is more specific, even if p comes later.
Example
<style>
p { color: navy; }
.lead { color: teal; }
</style>
<p class="lead">logger v1: ok — class wins</p>Chemistry
Why the warning stays red
If a later p { color: black } tries to mute .acid, it fails. Raise specificity on purpose with a class, not with !important on every bottle.
Example
<style>
p { color: #444; }
.acid { color: #b91c1c; }
</style>
<p class="acid">HCl — still red</p>