CSS Basics

Table of Contents

  1. Three Ways to Add CSS
  2. Anatomy of a Rule
  3. Selectors
  4. Combining Selectors
  5. Pseudo-classes
  6. The Cascade: Who Wins?
  7. Inheritance
  8. Style the Profile Page
  9. Try It Yourself

1. Three Ways to Add CSS

In chapter 1 you added CSS inside a <style> element. There are three places CSS can live:

WayLooks likeWhen to use
Inline<p style="color: red">Almost never — it can't be reused and is hard to override
Internal<style> in the <head>Quick experiments, single-file demos
External<link rel="stylesheet" href="style.css">Almost always

External stylesheets win because one file styles every page, the browser caches it (as in Caching, CDNs, and Speed), and your HTML stays about structure only. Set it up now: create style.css in the project folder, move your <style> rules into it, and link it in the <head> of every page:

<link rel="stylesheet" href="style.css">

2. Anatomy of a Rule

p {
  color: #333333;
  line-height: 1.6;
}
  • Selector (p) — which elements the rule applies to.
  • Declaration block ({ … }) — one or more declarations.
  • Declaration (color: #333333;) — a property and its value, separated by a colon, ended with a semicolon.

Whitespace doesn't matter, but one declaration per line is the convention. A missing semicolon or colon makes the browser throw away that declaration — and sometimes the next one too. If a style isn't applying, check the punctuation, then check DevTools: invalid declarations appear struck through.

Comments in CSS use /* … */:

/* Page-wide defaults */

3. Selectors

A selector says what to style. The basic ones:

SelectorMatchesExample
TypeEvery element of that nameh2 { … }
ClassElements with that class.card { … }
IDThe one element with that id#contact { … }
UniversalEverything* { … }
AttributeElements with an attributea[target="_blank"] { … }

Classes are the workhorse. In HTML you add class="…" — an element can have several, separated by spaces — and in CSS you target it with a dot:

<article class="card featured">…</article>
.card {
  border: 1px solid #d6d3d1;
  padding: 16px;
}

.featured {
  border-color: #b45309;
}

Prefer classes over IDs for styling. IDs are unique, so they can't be reused, and as section 6 shows they're harder to override. Save IDs for fragment links and form labels. Choose class names that describe what the thing is (.card, .nav-link) and not how it looks (.red-box), since looks change.

You can group selectors with a comma to share one rule:

h1, h2, h3 {
  font-family: Georgia, serif;
}

4. Combining Selectors

Combinators target elements by their relationship in the tree:

SelectorNameMatches
nav aDescendantAny <a> anywhere inside a <nav>
ul > liChild<li>s that are direct children of <ul>
h2 + pAdjacent siblingThe <p> immediately after an <h2>
h2 ~ pGeneral siblingEvery <p> after an <h2>, same parent
a.buttonCompoundAn <a> that also has class button
nav a {
  text-decoration: none;
}

.card > h3 {
  margin-top: 0;
}

Keep selectors short. main section article div p span works but is fragile — it breaks the moment you rearrange the HTML. One class on the element is usually better.

5. Pseudo-classes

A pseudo-class matches an element in a particular state. It's written with a single colon:

Pseudo-classWhen
:hoverThe pointer is over the element
:focusThe element has keyboard focus
:focus-visibleFocus that should be shown (mainly keyboard)
:activeWhile it's being pressed
:first-child, :last-childPosition among siblings
:nth-child(2n)Every even child
:not(.x)Elements that don't match .x
a:hover {
  color: #b45309;
}

a:focus-visible {
  outline: 3px solid #1d4ed8;
  outline-offset: 2px;
}

li:not(:last-child) {
  margin-bottom: 8px;
}

Anything you do with :hover you should do with :focus-visible as well, so keyboard users get the same feedback. There are also pseudo-elements (double colon) like ::before and ::after, which add generated content, and ::first-line.

6. The Cascade: Who Wins?

What if two rules set the same property on the same element?

p { color: black; }
.intro { color: green; }

The cascade decides. That's the "C" in CSS. The browser considers, in order:

  1. Origin and importance. Your styles beat the browser defaults. (A declaration marked !important beats nearly everything — avoid it.)
  2. Specificity. A more specific selector beats a less specific one.
  3. Source order. If everything else is equal, the last rule wins.

Specificity is a score from the parts of a selector, compared left to right:

Selector partWeight
Inline style=""Highest
IDs (#contact)Heavy
Classes, attributes, pseudo-classes (.card, :hover)Medium
Types, pseudo-elements (p, ::before)Light

So .intro (one class) beats p (one type) regardless of the order you wrote them, and #contact p beats .intro.

The practical advice:

  • Write flat, class-based selectors. Then specificity is rarely a problem and source order does the work.
  • When a rule isn't applying, open DevTools. The Styles pane shows losing declarations crossed out, and which rule beat them.
  • Resist !important. It only works until you need to override it, then you need another one.

7. Inheritance

Some properties pass down from parent to child automatically. Set color on <body> and every paragraph inside it gets that color unless something overrides it:

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

Text properties — color, font-family, font-size, line-height, text-align — are inherited. Box properties — margin, padding, border, background — are not, which makes sense: a border on a container shouldn't draw a border around every child.

Setting the base typography on body once is a core habit. It means you'll write far less CSS.

You can control inheritance explicitly with these values:

  • inherit — take the parent's value.
  • initial — reset to the property's default.
  • unset — inherit if it's an inherited property, otherwise reset.

8. Style the Profile Page

Apply what you've learned. Add this to style.css:

body {
  font-family: system-ui, sans-serif;
  line-height: 1.6;
  color: #292524;
  background-color: #fafaf9;
}

a {
  color: #b45309;
}

a:hover {
  color: #7c2d12;
}

a:focus-visible {
  outline: 3px solid #1d4ed8;
  outline-offset: 2px;
}

nav ul {
  list-style: none;
}

nav a {
  text-decoration: none;
  font-weight: 600;
}

.card {
  border: 1px solid #d6d3d1;
  background-color: #ffffff;
}

table {
  border-collapse: collapse;
}

th, td {
  border: 1px solid #d6d3d1;
}

Then add class="card" to each project <article>. Spacing is missing on purpose: the next chapter explains it.

9. Try It Yourself

  1. Link the stylesheet. Check that both pages use style.css. Edit a color and watch both pages change.
  2. Specificity battle. Add .card h3 { color: green; } and h3 { color: red; }. Which wins? Swap the order — does it change? Check DevTools to see the struck-through rule.
  3. Selector practice. Write one rule for each of: every <a> inside <footer>, every <li> that is a direct child of nav ul, and every external link (a[href^="https"]).
  4. Hover and focus. Style button:hover and button:focus-visible on the form. Test with the mouse and with the Tab key.
  5. Play with inheritance. Move color from body to main — what stops being colored? Why?

Next, the most important idea in CSS: every element is a box, and understanding that box lets you control spacing and size.

Buy Me a Coffee

Found this tutorial helpful? Consider buying me a coffee to support more free content!