This page covers what is true before any styling decision is made: the page already has a style sheet, the content already flows, and the browser reads CSS in a forgiving way. It ends with a first style sheet written the way every page in this section writes CSS.
1. Structure first, presentation second
The idea behind style sheets is a separation of concerns. HTML says what the content is: a heading, a list, a quotation, a navigation region. CSS says how that content should look in a particular context: on a phone, on paper, in a dark room, for a reader who needs larger text.
The separation is never complete. CSS binds to the document through selectors, so a style sheet depends on the markup it styles. It is a loose coupling, not a clean break, and the quality of the HTML sets the ceiling on the quality of the CSS.
| Why separate them | What it costs |
|---|---|
| One document can be presented many ways: screen, print, large text, high contrast. | Two languages to learn, each with its own rules. |
| One style sheet can style a whole site, so a design change happens in one place. | Bad markup forces bad CSS: deep selectors, extra wrappers, workarounds. |
| Designers and developers can work on separate files. | The connection between the two lives in selectors, which break when the markup changes carelessly. |
| A cached style sheet is downloaded once for every page that uses it. | An extra request on the very first visit. |
So the order of work matters. Write the HTML first, choosing elements for their meaning. Then style that structure. A page built from header, nav, main, article and footer gives a style sheet clear, stable things to select. A page built from anonymous div elements gives it nothing to hold on to except class names invented for the purpose.
2. User-agent styles, and what a base layer is for
Open a page with no CSS at all and it is not unstyled. Headings are large and bold, lists have bullets, links are blue and underlined, quotations are indented. Those looks come from the user-agent style sheet: real CSS, built into the browser, that gives every HTML element a default presentation.
The HTML standard's rendering section describes what those defaults should be, so Chrome, Firefox and Safari ship nearly identical sheets. A rule such as this one, close to what browsers actually use, is why every h1 looks like a heading before you write anything:
That means you never author on a blank page. A rule like h1 { color: crimson; } does not define how a heading looks. It adds one declaration to a style computation the browser was already going to do.
Defaults are a feature
The user-agent sheet is the reason an HTML page still works when its CSS fails to load: the structure stays visible, readable and usable. That is the baseline progressive enhancement builds on. The cost is that people learn what an element looks like before they learn what it means, and then reach for <h3> because they want smaller bold text. Choose elements for meaning, and change their look with CSS.
Resets, and the base layer that replaced them
Because the defaults once differed between browsers, authors began with a CSS reset: a sheet that erased the defaults so that every browser started from the same place. The bluntest version is still common in old tutorials:
Erasing everything has costs. Lists lose the indentation that shows they are lists, focus and form styles can vanish, and the author must then rebuild every default by hand. Today the defaults are consistent, so the modern approach keeps them and adjusts only what the design needs: a small reset layer for the handful of defaults nearly every design changes, and a base layer that styles the elements themselves.
Putting the reset in a @layer also keeps it weak: any later layer beats it, however specific its selectors, so it never fights the rest of the style sheet. The first style sheet below shows the layers together.
3. Going with the flow: block, inline and inline-block
Before any layout is written, content already has one: normal flow. Elements appear in source order, each after the one before. Two kinds of box share that flow.
- Block boxes (
p,h1,ul,section) stack one after another and fill the available space in the inline direction. - Inline boxes (
a,em,code, plain text) sit side by side within a line and wrap onto the next line when the line is full. - Inline-block is a hybrid: the box sits in a line like inline content, but takes a width, a height and vertical padding like a block.
Whitespace mostly collapses in normal flow: several spaces or line breaks between words become one space. Elements such as pre and textarea keep their whitespace because their user-agent styles say so, through the white-space property.
Inline and block, not left and top
Notice the words in the diagram: inline and block, not horizontal and vertical. In English, lines run left to right and blocks stack top to bottom. In Arabic and Hebrew, lines run right to left. In vertical Japanese, lines run top to bottom and blocks stack right to left. CSS describes flow by those logical directions, and the writing-mode and direction of the content decide which physical way they point.
This is why the examples in this section write margin-inline-start rather than margin-left. Space between an icon and its label set with margin-left ends up on the wrong side the moment the page is translated into Arabic. Space set with margin-inline-start follows the text. The web is a world wide web, not a left-to-right English one, and logical properties cost nothing to adopt from the start.
Flow is the default layout, and it is a good one: it reflows for any screen width, any zoom level and any text size. Layout, which comes later in this section, is mostly the work of changing flow deliberately where the design needs it, and leaving it alone everywhere else.
4. Anatomy of a rule
A style sheet is a list of rules and at-rules. A rule pairs a selector, which says which elements to style, with a declaration block, which says how. Each declaration is a property and a value, separated by a colon and ended by a semicolon.
Written as a grammar, the whole surface syntax of the language is short:
A few details follow from it:
- CSS ignores whitespace between tokens, so a rule can sit on one line or many.
- The semicolon after the last declaration is optional, but always writing it means adding a line later never breaks the one before.
- A comma-separated selector list applies one block to several selectors:
h1, h2 { line-height: 1.2; }. - There are only block comments,
/* … */. Aline comment is not a comment in CSS; it quietly breaks the rule that follows it. - An at-rule begins with
@and is an instruction to the style sheet itself, such as@import,@media,@layeror@supports. Some end with a semicolon, others carry a block.
Nesting
A declaration block can also contain other rules. Native CSS nesting lets a style sheet follow the shape of the HTML it styles:
The nested ul rule means nav ul, and the & selector can refer to the parent explicitly where needed, as in &:hover. Nest to show structure, and stay shallow: a selector three levels deep is as specific and as fragile as one written out longhand. The cascade page, third in this section, treats nesting in full.
5. Where styles come from
An author can attach CSS to a document in four ways. They differ in reach, in caching and in how tightly they bind style to markup.
| Way | Syntax | Reach | Use it for |
|---|---|---|---|
| Linked (external) | <link rel="stylesheet" href="site.css"> | Every page that links it; cached across them | The default for any real site |
| Document-wide | <style> … </style> in the head | One page; no extra request | Single-page demos, and small critical styles |
| Inline | style="color: crimson" | One element | Values set by a script at run time, such as a custom property |
| Imported | @import url("tokens.css"); | Pulls one sheet into another | Splitting a sheet into files, with care |
Linked style sheets
A linked style sheet is a plain .css file containing rules and nothing else, attached with a link element in the document's head:
The media attribute limits a sheet to a context. A sheet marked media="print" is still downloaded, but the browser does not wait for it before showing the page on screen. The type="text/css" attribute seen in older pages is no longer needed: CSS is the only style sheet language browsers support.
Document-wide styles
A style element holds rules for its own page. It belongs in the head. Browsers will honor one in the body, but the HTML standard does not allow it there, and a style that arrives late can make the page visibly change after it first renders.
Inline styles
The style attribute has no selector: the element is the selector. Inline declarations are tied to one element, cannot be reused, cannot respond to media queries, and beat every normal author rule in a style sheet. That makes them the assembly language of CSS: occasionally exactly right, never the default. The best modern use is to pass a value rather than a look:
The style sheet decides what --i means, for example a delay of calc(var(--i) * 0.1s), so the markup carries data and the CSS keeps the presentation.
Imported styles
@import pulls one style sheet into another, and must come before every other rule except @charset and @layer statements. It can place the imported rules straight into a layer, or apply them only when a condition holds:
The catch is performance. The browser cannot discover an imported file until it has downloaded and read the file that imports it, so chains of imports turn into chains of requests. Use @import for organization in development and let a build step combine the files, or list the sheets with link elements so they download in parallel.
6. Media, alternate and user style sheets
A document can carry different presentations for different contexts, and it is not only the author who supplies them.
Style sheets for a medium
The media attribute and the @media at-rule both name a medium. Three media types matter today: screen, print and all. The others in the specifications (tv, handheld, braille and more) were never implemented in any useful way and are deprecated. Print is the case that endures: hiding navigation, removing backgrounds, and widening the text column for paper.
Media queries extend the same idea from which medium to which conditions: viewport size, orientation, and, most usefully, the reader's own preferences such as prefers-color-scheme and prefers-reduced-motion. The responsive design page in this section covers them in depth.
Alternate style sheets
A page can offer named alternatives: <link rel="alternate stylesheet" title="Large text" href="large.css">. Firefox lists them under View › Page Style. Other browsers do not offer a switcher, so in practice a site that offers themes provides its own control and, better still, follows the reader's operating-system preferences automatically.
User style sheets, and the mediated medium
The reader can style the page too. Browser settings for minimum font size and default colors, accessibility extensions, forced-colors modes such as Windows High Contrast, and custom user style sheets all contribute CSS. The cascade recognizes three origins: the user-agent, the user, and the author.
| Priority (lowest first) | Origin | Importance |
|---|---|---|
| 1 | User-agent | normal |
| 2 | User | normal |
| 3 | Author | normal |
| 4 | Author | !important |
| 5 | User | !important |
| 6 | User-agent | !important |
Normally the author wins over the user, and the user over the browser. Marking a declaration !important flips that order, so a reader who truly needs larger text or higher contrast can always override the author. (Animations and transitions also take part in the full ordering; the cascade page shows where.)
That is the deepest difference between styling for the web and drawing an interface in a native app. The author does not have the last word. Designs that assume they control the canvas break under zoom, reflow, dark mode, reduced motion and assistive technology. Designs that treat their CSS as a contribution to a negotiation adapt gracefully. Relative units, logical properties and preference queries are how a style sheet holds up its end.
7. Forgiving parsing
CSS is lenient by design. A browser that meets something it does not understand skips it and carries on. That is not sloppiness; it is what lets a style sheet written today work in a browser from years ago and in one from years ahead.
| The browser meets | It drops | Example |
|---|---|---|
| An unknown property | That one declaration | colr: red; |
| A value it cannot parse | That one declaration | width: 12 rem; (the space breaks the unit) |
| An invalid selector in a list | The whole rule | h1, h2:unknown { … } styles no h1 either |
| An unknown at-rule | The at-rule and its block | @future { … } |
The third row surprises people: one bad selector in a comma-separated list throws away the entire rule. The selectors :is() and :where() take a forgiving list instead, dropping only the selector they cannot read, which is one reason they appear so often in modern CSS.
Fallbacks, the progressive way
Forgiveness gives CSS its simplest progressive-enhancement pattern. Write the widely supported declaration first and the newer one after it. A browser that understands the second uses it; one that does not drops it and keeps the first.
When an enhancement needs several declarations to make sense together, wrap them in @supports instead, so a browser applies all of them or none:
8. A first style sheet
Here is a small base style sheet for the demo page from section 2. It uses no classes at all. It styles the HTML's structure, orders the cascade with layers, keeps its design values in custom properties, measures in relative units, and adds enhancements on top of a baseline.
Each habit in it has a reason:
- Element selectors, no classes. The HTML already says what each part is, so the CSS can say how each kind of part looks. Classes earn their place later, for variations the markup cannot express.
@layerfirst. The opening statement fixes the order of the layers before any rules arrive. A rule inlayoutbeats a rule inbaseregardless of selector specificity, so nobody has to win arguments with ever more specific selectors or!important.- Custom properties as tokens.
--space,--measureand the colors are named once and used everywhere. Change one and the whole page follows; there are no unexplained magic numbers. - Relative units.
remfollows the reader's default font size,emfollows the element's own, andchsets the line length in characters. The page scales with zoom and with the reader's settings. The one fixed number left in the demo is a hairline1pxtable border. - Logical properties.
margin-inline,padding-inline-startandmax-inline-sizefollow the writing direction, so the page is ready for right-to-left languages. - Enhancement on top. The baseline works everywhere. The transition is added only for readers who have not asked their system to reduce motion, and the demo page adds dark-mode colors only in browsers that support
light-dark().
9. A brief history, and Baseline today
CSS is older than most of the people learning it, and its history explains some of the advice that still circulates.
| When | What happened |
|---|---|
| 1996 | CSS level 1 becomes a W3C Recommendation: fonts, colors, text, the box model. |
| 1998 | CSS level 2 adds positioning, media types and more selectors. Browser support is uneven for a decade. |
| 2000s | The browser wars. Authors rely on hacks, the Acid tests expose the gaps, and resets and vendor prefixes (-webkit-, -moz-) become routine. |
| 2011 | CSS 2.1 is finally finished. Work has already split into separate modules, each with its own levels, which is what people loosely call "CSS3". |
| 2017 | Grid ships in every major browser within months, a sign of how closely the engines now coordinate. |
| 2022 to 2023 | Cascade layers, container queries, :has() and nesting arrive in every major browser. "Baseline" starts labelling what is safe to use everywhere. |
There is no CSS4. The language is now a set of modules that advance independently, so the useful question is not which version a browser supports but whether a particular feature is supported. Baseline answers it: a feature is newly available once it works in the current versions of Chrome, Edge, Firefox and Safari, and widely available thirty months after that. MDN and caniuse.com show the status of each feature.
Two habits from the bad old days are worth unlearning. Vendor prefixes are no longer how new features ship, so hand-written -webkit- copies of standard properties are clutter; a build tool can add the few still needed. And comment "masks" around the contents of a style element, written to hide CSS from browsers that predate it, protect against browsers no one has used in decades.
10. Summary
| Concept | Key points |
|---|---|
| Structure first | HTML says what content is; CSS says how it looks. CSS binds through selectors, so good markup comes first. |
| User-agent styles | Every page starts with the browser's own style sheet. Keep its useful defaults; adjust them in a small reset layer and a base layer instead of erasing them. |
| Normal flow | Block boxes stack in the block direction; inline boxes line up and wrap in the inline direction. Use logical properties so flow works in every writing mode. |
| Rules | A selector plus a declaration block of property and value pairs. At-rules begin with @. Only /* */ comments exist. Nest to mirror the markup, and stay shallow. |
| Where styles live | Linked by default; style elements for single pages; inline styles for run-time values; @import for organization, combined for production. |
| Media and origins | Screen and print are the media that matter. The user-agent, the user and the author all contribute CSS, and !important lets the reader have the final say. |
| Forgiving parsing | Unknown declarations are dropped one by one; a bad selector drops its whole rule. Put the baseline first and the enhancement after it, or group enhancements in @supports. |
| A first style sheet | Element selectors, @layer order, custom properties, relative units, logical properties, and preference queries on top of a baseline. |
| History and Baseline | CSS is a set of modules, not versions. Check Baseline status per feature, and drop vendor-prefix and comment-mask habits. |