Lesson 1 of 25

Introduction to CSS

HTML Describes, CSS Decides How It Looks

When you write HTML you are describing what each piece of content is: this is a heading, this is a paragraph, this is a list, this is an image. You never say how any of it should look. Yet open a plain HTML file in a browser and the heading is already large and bold, links are already blue and underlined, and the list already has bullets. Those decisions came from somewhere. Every browser ships with a built-in stylesheet — the user-agent stylesheet — and applies it to every page it opens. CSS is how you replace those defaults with choices of your own.

The name spells out what it is. Style, because it controls colour, spacing, size, layout and motion. Sheet, because the rules normally live in a separate file. Cascading, because more than one rule is allowed to target the same element and the browser follows a fixed procedure to decide which one wins. That third word is the part that quietly confuses people for months, and a full lesson later in this course is spent on it.

Keeping style out of your HTML is not about tidiness. A project with twenty pages that share one style.css can change its entire colour scheme by editing one line. The same project with colours typed into every page needs twenty edits, and you will miss one. There is a speed benefit too: the browser downloads a shared stylesheet once and reuses the cached copy on every page after that.

  • HTML is structure and meaning, CSS is presentation, JavaScript is behaviour
  • A page with no CSS still works — it simply looks like a plain document
  • One stylesheet can style any number of pages
  • CSS controls colour, fonts, spacing, layout, responsiveness and animation
  • The browser applies its own default styles first; yours override them

Three Ways to Attach CSS, and Which One to Use

There are exactly three places CSS can live. Inline means a style attribute written directly on one HTML element. Internal means a <style> block inside the <head> of one page. External means a separate .css file pulled in with a <link> tag.

External is the right answer for almost every real page, and it should be your default. The rules live in one file that every page shares, the browser caches that file, and your HTML stays readable because it contains content rather than paint. Internal <style> blocks are fine for a one-page experiment or for a handful of rules that genuinely belong to a single page and nowhere else.

Inline styles are the ones to avoid, and not just on grounds of neatness. They cannot be reused, so the same rule gets copied onto element after element. They also beat nearly every rule in your stylesheet when the browser decides which style wins, which means the only way to override one later is !important — a habit that spirals fast. And there is a limit people rarely expect: a style attribute can hold declarations only, never whole rules, so you cannot write a :hover state or a media query inside one at all. The moment you want a hover colour, an inline style cannot help you.

Example
<!-- 1. Inline — avoid except for values a script sets at runtime -->
<h1 style="color: #d1039e;">Hello</h1>

<!-- 2. Internal — fine for a single experimental page -->
<head>
  <style>
    h1 { color: #d1039e; }
  </style>
</head>

<!-- 3. External — the one to use for real projects -->
<head>
  <link rel="stylesheet" href="css/style.css">
</head>

/* css/style.css */
h1 {
  color: #d1039e;
}
Notes
  • The <link> tag belongs inside <head>. Put it at the bottom of the body and the browser paints the page unstyled first, then restyles it — a visible flash that users notice.

Reading a Rule Out Loud

A CSS rule has two halves. The selector says which elements to affect. The declaration block — everything inside the curly braces — says what to do to them. Each declaration is a property and a value separated by a colon and finished with a semicolon. Read the rule below as a sentence: "for every paragraph, set the text colour to dark grey and the line height to 1.6".

The browser does not care about your line breaks, spaces or indentation; you could write an entire stylesheet on one line and it would work identically. Humans care a great deal, so put one declaration per line and indent the block. The semicolon after the last declaration is technically optional, but leave it in — the day you add another declaration underneath, you will forget to go back and add it.

Comments in CSS are written /* like this */ and may span several lines. There is no single-line comment. Writing // this is my heading in a .css file is a mistake students carry over from JavaScript, and it does not simply get ignored: the parser treats it as the start of a broken rule and usually swallows whatever comes next as well. If a rule stops working for no visible reason, look upwards for a stray //.

Example
/* selector */
p {
  /* property : value ;   <- one declaration */
  color: #333333;
  line-height: 1.6;
}

/* One rule can target several selectors at once */
h1, h2, h3 {
  font-family: Georgia, serif;
}

/* Comments look like this and can span
   more than one line. */

// WRONG — CSS has no // comment. This breaks the rule below it.
p { color: red; }

CSS Never Tells You That You Made a Mistake

This is the biggest shock for anyone arriving from a programming language. If you misspell a variable in JavaScript or Python, you get an error message pointing at the line. If you misspell a property in CSS, nothing happens at all. Write colour: red instead of color: red and the browser silently throws that declaration away and moves on. No warning, no red text in the console, just an element that stubbornly refuses to change.

That behaviour is deliberate. It is what lets an old browser meet a brand-new property, ignore the part it does not understand, and still render the rest of the page. But while you are learning it means a typo and a genuine misunderstanding look exactly the same from the outside, and you can lose an hour to a missing letter.

The fix is to stop guessing and look. Right-click the element, choose Inspect, and open the Styles panel in your browser's developer tools. Every rule that matched the element is listed there, and any declaration the browser rejected appears struck through with a warning marker. If your rule is not in that list at all, the selector never matched — that is a different bug from a bad value, and the panel tells you which one you have.

  • Misspelled property name — silently dropped (colour, font-weigth)
  • Missing unit — width: 300 is invalid; it must be 300px. The exception is 0, which needs no unit
  • Missing semicolon — the parser runs two declarations together and throws away both
  • Selector typo — .btn in the CSS, class="button" in the HTML, so nothing matches
  • Editing the wrong file, or a stale cached stylesheet the browser has not re-downloaded
Notes
  • Keep the developer tools open while you write CSS. Not as a debugging step at the end — from the first rule. You can also edit values live in the Styles panel to try an idea before committing it to the file.

Linking a Stylesheet Without the Usual Frustration

The href in your <link> tag is resolved relative to the location of the HTML file, not the CSS file. If index.html sits in your project root and the stylesheet is at css/style.css, the correct value is css/style.css. From a page inside a subfolder, the same stylesheet is ../css/style.css. Getting this wrong produces a page that looks completely unstyled, which is a useful signal in itself: partial styling means your CSS loaded and a rule is wrong, while zero styling usually means the file never loaded.

When nothing changes after an edit, work through the same four checks every time before rewriting anything. Did the file actually save? Is the path right — open the Network tab and look for a 404 on the stylesheet? Is the browser showing a cached copy, which a hard refresh (Ctrl+F5, or Cmd+Shift+R on a Mac) will clear? And is the rule you just wrote even reaching the element, which the Styles panel will tell you in a second.

The demo below is a small card — the kind of thing you will build dozens of times. Open it, change background on .card, change the padding, change border-radius to 0. Watching a value move something is worth more than reading three paragraphs about it.

Example
<!-- index.html, sitting in the project root -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>My First Styled Page</title>
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <h1>My First Styled Page</h1>
</body>
</html>

/* css/style.css */
body {
  font-family: system-ui, Arial, sans-serif;
  background: #f4f4f7;
}

h1 {
  color: #d1039e;
}
Style your first card
HTML
<div class="card">
  <h2>Weekend Study Group</h2>
  <p class="meta">Every Saturday, 10 am</p>
  <p>Bring a laptop. We build one small page together each week.</p>
  <a class="btn" href="#">Join the group</a>
</div>
CSS
body {
  font-family: system-ui, Arial, sans-serif;
  background: #f4f4f7;
  padding: 24px;
}

.card {
  max-width: 360px;
  background: #ffffff;
  padding: 24px;
  border: 1px solid #e3e3ea;
  border-radius: 12px;
}

.card h2 {
  margin: 0 0 4px;
  color: #d1039e;
}

.meta {
  margin: 0 0 12px;
  color: #777777;
  font-size: 14px;
}

.btn {
  display: inline-block;
  margin-top: 12px;
  padding: 10px 18px;
  background: #d1039e;
  color: #ffffff;
  text-decoration: none;
  border-radius: 6px;
}
Notes
  • You will meet <meta name="viewport" content="width=device-width, initial-scale=1"> in every example in this course. Without it a phone pretends to be a wide desktop screen and shrinks your whole page, and none of your responsive CSS behaves as intended.
Ask AI