018: What CSS Is
Learning outcomes
By the end of this lesson, you can:
- explain how HTML supplies meaning and CSS supplies presentation;
- link one external stylesheet to an HTML document;
- identify a rule, selector, declaration block, property, and value;
- write simple type and class rules and verify that they apply; and
- use browser DevTools to distinguish a loading problem from an invalid declaration.
Prerequisites and retrieval
You need the 013 portfolio, a code editor, and a browser. Before starting, review the <head>, <body>, heading hierarchy, links, and sections in your HTML. Consider what meaning would remain if every visual style disappeared. That question is the boundary between HTML and CSS.
Terminology
- CSS: “CSS (Cascading Style Sheets) is the language used to describe the presentation of a document written in HTML.” — Source: MDN: What is CSS?
- Stylesheet: A collection of CSS rules, usually delivered as an external .css file via link. — Source: CSSWG: CSS Syntax Level 3
- Rule: A selector followed by its declaration block. — Source: CSSWG: Style rules
- Selector: A pattern that matches elements to which declarations apply. — Source: CSSWG: Selectors Level 4
- Declaration: A property/value pair such as color: navy, ending with a semicolon inside a block. — Source: CSSWG: Declarations
- Property: The stylistic feature being set (color, margin, font-size). — Source: CSSWG: Declarations
- Value: The setting assigned to a property; may be a keyword, number, function result, or list. — Source: CSSWG: Declarations
- User agent stylesheet: The browser’s built-in stylesheet supplying readable defaults before author CSS loads. — Source: CSSWG: Cascading and Inheritance Level 5
- DOM: The browser’s live tree representation of the document that selectors match against. — Source: MDN: Document Object Model
- Declaration block (official): "A declaration block is a (possibly empty) sequence of declarations and at-rules." — Source: CSS Syntax Module Level 3: Declaration blocks
- At-rule: "An at-rule starts with @, such as @media or @import." — Source: CSS Syntax Module Level 3: At-rules
Mental model: content, instructions, rendering
HTML is a labeled document. A heading remains a heading whether it is large, small, blue, or unstyled. CSS is a separate set of presentation instructions: “find every element matching this pattern, then try these declarations.” The browser parses HTML into the DOM, downloads linked CSS, matches rules to elements, resolves conflicts, and paints the result.
CSS is fault tolerant. If one declaration is invalid, the browser normally ignores that declaration and continues. This is valuable on a changing web, but it means a typo may fail quietly. Observation and DevTools are part of writing CSS, not a last resort.
Consider:
.intro {
color: rgb(31 41 55);
background-color: rgb(239 246 255);
}
.intro is the selector. Everything inside { } is the declaration block. color and background-color are properties; the rgb(...) expressions are values. Each declaration ends with a semicolon. Modern rgb() separates channels with spaces; later you will use / for alpha.
An external stylesheet is the normal choice because one file can style many pages, HTML stays readable, and browsers can cache it. Inline style attributes mix concerns and become hard to maintain. A <style> block can be useful for a tiny demo, but today the portfolio will use an external file.
Beginner example: connect the portfolio
Create styles.css beside index.html. Use this reduced portfolio if your 013 file differs:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Asha Rao | Portfolio</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>Asha Rao</h1>
<p class="intro">Building clear, useful websites with semantic HTML.</p>
</header>
<main>
<section aria-labelledby="projects-title">
<h2 id="projects-title">Projects</h2>
<article class="project">
<h3>Local library page</h3>
<p>A semantic information page made with HTML.</p>
<a href="https://example.com">View project</a>
</article>
</section>
</main>
<footer><p>Contact: <a href="mailto:asha@example.com">asha@example.com</a></p></footer>
</body>
</html>
Put this in styles.css:
body {
color: rgb(31 41 55);
background-color: rgb(248 250 252);
font-family: system-ui, sans-serif;
}
h1,
h2,
h3 {
color: rgb(30 64 175);
}
.intro {
font-size: 1.125rem;
}
.project {
background-color: white;
border: 1px solid rgb(203 213 225);
padding: 1rem;
}
a {
color: rgb(29 78 216);
}
Save both files and reload. Observe one change at a time. body matches the body and its text color is inherited by much of the page. The heading list shares a declaration block. .intro matches the element whose class contains intro. .project creates a visible panel without attempting layout.
Change the heading color, save, and reload. Add a second .project article: the same class rule applies without another CSS rule. Finally, temporarily change href="styles.css" to href="missing.css"; the browser returns to defaults. Restore it. This proves that linking and styling are separate stages.
Intermediate example: separate broad defaults from component styles
A maintainable small stylesheet often moves from broad rules to reusable components:
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
margin: 0;
color: rgb(30 41 59);
background: rgb(248 250 252);
font-family: system-ui, sans-serif;
line-height: 1.6;
}
header,
main,
footer {
padding: 1rem;
}
.project {
margin-block: 1rem;
padding: 1rem;
border: 1px solid rgb(203 213 225);
border-radius: 0.5rem;
background: white;
}
.project a {
font-weight: 700;
text-underline-offset: 0.2em;
}
.project a:focus-visible {
outline: 3px solid rgb(245 158 11);
outline-offset: 3px;
}
The box-sizing setup makes later sizing easier: declared widths include padding and borders. margin-block uses the writing mode's block direction instead of hard-coding top and bottom. The descendant selector limits bold links to projects. :focus-visible gives keyboard users an obvious focus indicator. You do not need to memorize these declarations today; identify their selectors, properties, and values.
Optional advanced example: one stylesheet, two pages
Add about.html with the same <link> and a body class:
<body class="about-page">
<main><h1>About Asha</h1><p class="intro">I learn by building.</p></main>
</body>
Then add:
.about-page .intro {
border-inline-start: 0.25rem solid rgb(30 64 175);
padding-inline-start: 1rem;
}
The shared defaults apply on both pages, while this rule applies only to .intro inside .about-page. This demonstrates reuse without copying styles into each HTML file.
Mistakes, debugging, and DevTools
- Wrong path:
hrefis relative to the HTML file. Use the Network panel; a404means the stylesheet was not found. - Wrong element:
<link>belongs in<head>, usesrel="stylesheet", and has no closing tag. - HTML syntax in CSS: write
.intro, notclass="intro". - Missing punctuation: check braces, the colon between property and value, and semicolons between declarations.
- Unsupported or misspelled value: DevTools crosses out or warns about invalid declarations.
- Stale page: save files, reload, and check that DevTools Sources shows the current CSS.
- Editing the wrong rule: inspect the element, then use the Styles pane to see matched rules. Toggle a declaration's checkbox and watch the page.
In DevTools, select the <h1>. The Styles pane shows author rules and browser defaults; the Computed pane shows the final color. If your rule is absent, its selector did not match or the CSS did not load. If present but crossed out, another declaration won; 020 explains why.
Rendering diagnosis: layout, paint, and compositing
A style change can require different amounts of browser work. Changing geometry such as width, margin, or font size can invalidate layout for the element and possibly its neighbors; the browser then paints affected pixels. A color or shadow often needs paint without changing geometry. A transform or opacity animation can sometimes be handled by a compositor layer without repeated layout, but layer promotion is an optimization, not a promise. “Reflow” and “repaint” are useful interview shorthand, not a reason to label every CSS rule slow.
When diagnosing jank, reproduce the interaction, record a Performance trace, and inspect long tasks and layout/paint events. Check whether a script is forcing synchronous layout by reading geometry immediately after changing styles, whether a large area is repainting, and whether the real cost is image decoding or JavaScript. Prefer transform for an optional movement animation, but measure and honor prefers-reduced-motion; do not use transforms to hide an overflow or source-order defect.
Accessibility and performance
CSS must enhance semantic HTML, not replace it. Do not choose heading elements for their default size; preserve the logical HTML hierarchy and style it. Keep link underlines unless another persistent visual cue identifies links, and never remove focus outlines without a strong replacement. Ensure text and background colors have adequate contrast; WCAG 2.2 requires at least 4.5:1 for normal text and 3:1 for large text.
External CSS can be cached across pages. Keep the <link> in <head> so styling is discovered early. Avoid large background images for decoration when a color or gradient works, and do not split a tiny site into many blocking stylesheets. These choices matter more than micro-optimizing selectors.
Deep dive: CSS syntax, parsing, and the three ways to attach styles
A CSS rule is not just “selector plus styles.” It has a precise structure:
.card {
color: #1f2937;
background-color: white;
padding: 1rem;
}
Read it in layers:
.cardis the selector. It decides which elements are candidates.{ ... }is the declaration block.color: #1f2937is one declaration.coloris the property.#1f2937is the value.
A declaration normally ends with a semicolon. The final semicolon in a block is technically optional, but keeping it prevents accidental breakage when another declaration is appended later.
Browsers are designed to recover from CSS they do not understand. If one declaration is invalid, the browser usually ignores that declaration and continues parsing later declarations:
.card {
color: navy;
invented-property: 42magic; /* ignored */
padding: 1rem; /* still applied */
}
That error-tolerant behavior is useful, but it can hide mistakes. DevTools is therefore part of CSS authoring, not an optional debugging tool.
External CSS: the normal project choice
<head>
<link rel="stylesheet" href="styles.css">
</head>
/* styles.css */
body {
font-family: system-ui, sans-serif;
}
External stylesheets are reusable across pages, cacheable by the browser, and easier to maintain.
Internal CSS: useful for isolated documents and experiments
<head>
<style>
.notice {
border-inline-start: 4px solid royalblue;
padding: 1rem;
}
</style>
</head>
Internal CSS belongs in a <style> element, normally inside <head>. It applies only to that document.
Inline CSS: highest maintenance cost
<p style="color: crimson; font-weight: 700;">Important</p>
Inline styles can be useful for generated one-off values, email HTML, or highly constrained integrations, but they mix content and presentation and are difficult to override and reuse. They also participate in the cascade differently from ordinary selector rules, which becomes important in 020.
Comments
CSS comments use /* ... */:
/* Component: pricing card */
.price-card {
padding: 1.5rem;
}
Do not use // comments in plain CSS. Some preprocessors accept them, but browsers parsing regular CSS do not.
Worked example: diagnose a stylesheet that “does not work”
Suppose the HTML is:
<link rel="stylesheet" href="./styles/site.css">
<article class="profile-card">
<h2>Ravi Kumar</h2>
<p>Frontend engineer</p>
</article>
and styles/site.css contains:
.profile-card {
background: #ffffff;
padding 1.5rem;
border: 1px solid #d1d5db;
}
.profile-card h2 {
colour: #111827;
}
Two declarations are invalid:
padding 1.5remis missing:.colouris not the CSS property name; the standard property iscolor.
Correct version:
.profile-card {
background: #ffffff;
padding: 1.5rem;
border: 1px solid #d1d5db;
}
.profile-card h2 {
color: #111827;
}
A professional debugging sequence is:
- Confirm the stylesheet request succeeds in the Network panel.
- Inspect the element.
- Check whether the rule appears in the Styles panel.
- Look for crossed-out declarations, warning icons, or invalid values.
- Check the Computed panel to find the final value.
- Only then change code.
If the entire rule is missing from DevTools, investigate file path, selector matching, or whether the CSS file loaded. If the rule exists but a declaration is crossed out, investigate cascade and specificity. If the declaration is present but has no visible effect, investigate layout, inherited values, or whether you are styling the right box.
Worked example: same HTML, three styling approaches
Start with:
<button class="save-button">Save profile</button>
External:
.save-button {
padding: 0.75rem 1rem;
border: 0;
border-radius: 0.5rem;
background: #2563eb;
color: white;
}
Internal:
<style>
.save-button {
padding: 0.75rem 1rem;
background: #2563eb;
color: white;
}
</style>
Inline:
<button
class="save-button"
style="padding: .75rem 1rem; background: #2563eb; color: white"
>
Save profile
</button>
All three can render similarly. The difference is architecture. External CSS gives the class a reusable meaning, while inline CSS duplicates presentation every time the button appears.
Deeper mental model: specified, computed, used, and actual values
When you write:
.card {
width: 60%;
color: inherit;
}
the browser does not immediately turn those tokens into pixels and RGB values. Conceptually it resolves values through stages:
- specified value: what the cascade selected;
- computed value: after inheritance and relative-value processing that can happen at that stage;
- used value: after layout knows dimensions and context;
- actual value: what the device can finally render.
This explains why DevTools can show a declaration such as width: 60% while the Layout panel reports a pixel width. CSS is a constraint language whose final result depends on the surrounding document and viewport.
Tiered exercises
Before the exercise, perform one final retrieval check: close DevTools, choose a rule, and state its selector and every declaration. Then reopen DevTools and confirm your prediction. The habit of predicting before inspecting turns browser tools into evidence rather than a place to make random edits.
Foundation: Link portfolio.css to the 013 portfolio. Set a readable system font, text color, page background, and distinct heading color.
Core: Add .project to at least two articles and style both with one rule. Style links and provide a visible :focus-visible outline.
Stretch: Add a second HTML page that reuses the stylesheet. Give its <body> a page class and add one page-specific rule without inline styles.
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Portfolio</title>
<link rel="stylesheet" href="portfolio.css">
</head>
html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }
body {
margin: 0;
color: rgb(30 41 59);
background-color: rgb(248 250 252);
font-family: system-ui, sans-serif;
line-height: 1.6;
}
header, main, footer { padding: 1rem; }
h1, h2, h3 { color: rgb(30 64 175); }
.project {
margin-block: 1rem;
padding: 1rem;
border: 1px solid rgb(203 213 225);
background-color: white;
}
a { color: rgb(29 78 216); text-underline-offset: 0.2em; }
a:focus-visible { outline: 3px solid rgb(245 158 11); outline-offset: 3px; }
.about-page .intro { border-inline-start: 4px solid rgb(30 64 175); padding-inline-start: 1rem; }
Recap and exit questions
CSS matches rules to HTML and changes presentation while HTML retains meaning. External stylesheets provide separation and reuse. A rule is a selector plus declarations; each declaration is a property/value pair.
- What is the difference between a selector and a property?
- Why can an unstyled HTML page still be readable?
- What three things would you check if no CSS appears?
- Why is an external stylesheet preferable for a multi-page portfolio?
- Can you explain every part of
.project { padding: 1rem; }? - Which changes are likely to affect geometry, and how would you prove the cause of a slow interaction?
