Stylesheet
the file that holds a page's CSS
What it is
A stylesheet, spelled style sheet in the specifications and often just called the CSS file, is one collection of CSS rules that a browser fetches, parses and applies to a document as a single unit.
A page can receive stylesheets in four ways. A link element with
rel="stylesheet" points at a separate file. A style element carries rules
inside the HTML itself. An @import rule at the top of one stylesheet pulls in
another. And a script can build one with new CSSStyleSheet() and attach it to
a document or a shadow root through adoptedStyleSheets. The first two look
like this in the head of a page:
<link rel="stylesheet" href="/css/site.css" />
<link rel="stylesheet" href="/css/print.css" media="print" />
<style>
.banner {
border-block-end: 2px solid;
}
</style>
The author’s sheets are not the only ones in play. Every browser ships a default
stylesheet, which is why an unstyled heading still comes out large and bold, and
a reader can add a user stylesheet of their own; the cascade weighs the three
origins against each other. The style attribute on one element is a different
thing: declarations with no selector, belonging to that element and to no sheet.
Once loaded, a stylesheet becomes a CSSStyleSheet object in the CSS Object
Model, the specification this term’s definition comes from. The object records
the element that owns the sheet, the media it applies to, its title, whether it
is disabled, and its list of rules, and document.styleSheets lists a page’s
sheets in order. One flag exists for privacy: a sheet fetched from another
origin without CORS is not origin-clean, and a script that asks for its rules
gets a security error instead.
The media attribute limits a sheet to an environment. A sheet marked
media="print" is still downloaded, but the browser waits only for sheets whose
media matches, so a print sheet does not hold up the screen.
Why it matters
A stylesheet decides what a browser has to fetch before it shows anything. The HTML standard treats a stylesheet link the parser finds as render-blocking whenever its media matches, so the first paint waits until that file has arrived and been parsed, instead of drawing the page unstyled and redrawing it in front of the reader. Its size, its host and the round trips needed to discover it all sit between a click and the first thing a reader sees.
The number of files is the first decision. One bundle shared by every page is
fetched once and then served from the cache; a stylesheet per page sends less up
front and more as a reader moves around. Rules inlined in a style element cost
no extra request, but they travel again with every page, because they cannot be
cached apart from the document that carries them. Each @import adds a full
round trip, because the browser learns the imported address only after the
importing file has arrived.
Caching is the second. A stylesheet cached for a year makes every later page faster, but a change then has to reach readers holding the old copy. The usual answer is a fingerprinted file name, with a hash of the content inside the name, so a changed file is a new address and an old one can stay cached for as long as anyone likes, while the HTML pointing at it is kept short-lived.
Trust is the third. A stylesheet decides what is visible and where; it can hide a warning, restyle a button, or request images from any address its rules name. Loading one from a third party hands that power to the third party, along with a host the page cannot render without. Subresource Integrity lets the page state a cryptographic hash for the file, and the browser refuses any file whose bytes differ.
What it looks like in practice
The site’s own stylesheet bundle shows how far one inlined asset can tip the balance. At 87 KB it was, for a document site with no framework, most of a page’s weight spent before any content arrived, and two thirds of the largest stylesheet turned out to be one base64-encoded font: about 56 KB of text encoding about 42 KB of font. It had been inlined for a first-paint benefit that a preloaded external file gets anyway, and every page paid for it whether the weight was needed or not. Taking it out took that file from 84 KB to 28 and the whole bundle from 87 KB to 31 KB, with the font weights preloaded instead. Base64 writes every three bytes as four characters, so a binary file inlined into a stylesheet always weighs about a third more than the file served on its own.
Paper is a medium a stylesheet has to serve too. The site’s case studies are what someone prints and takes into a meeting, so one 637-line stylesheet with a single page rule and one print block makes them print on unknown paper in both colour themes. The page rule sets a margin and deliberately no paper size, and a measure of about seventy-two characters keeps a landscape sheet from running a line to about a hundred and ten. Four engine behaviours are written down as traps, each having caused a real defect: viewport units measured against the page box by one engine but against the window by another, which cropped a third of every line; fixed-position elements that paint on every sheet; a palette defaulting to white text for the dark theme, which printed four section labels white on white; and a flex or grid box that paged media cannot split, which produced a blank first sheet. A six-part check covers six paper and orientation combinations, both colour-scheme preferences and the real page count, and it was that check which noticed when a stray comment terminator made the CSS linter swallow a whole rule and pass clean twice.
The site’s security page lists Subresource Integrity on the stylesheet: the bundle is fingerprinted and hashed at build time, so a reader’s browser can verify that it arrived unmodified. The same page asks the reader to count the hosts in the browser’s network panel and gives the answer as one, the site’s own.
Where it goes wrong
A stylesheet the browser learns about late arrives late. A link at the end of
the body, a sheet injected by a script, or a chain of @import rules each lets
the page paint before the styles land, so raw text jumps into a layout, or a
finished layout shifts. An import chain looks harmless in the source:
/* site.css: the browser finds base.css only after this file arrives */
@import url("base.css");
@import url("theme.css");
Put stylesheet links in the head and flatten imports into the bundle at build time.
A deploy can pair new markup with old rules. Readers whose cache holds the previous stylesheet get HTML expecting classes the old file has never heard of, and their layout breaks until the cache expires, while anyone testing with a fresh cache sees a working site. The cause is a stylesheet name that never changes combined with a long cache lifetime, and a fingerprinted name removes it.
A stylesheet served with the wrong content type is ignored. The HTML standard
applies a linked stylesheet only when it arrives as text/css, with one
exception for a same-origin file on a page in quirks mode. A server that labels
.css files as text/plain, or answers a missing file with an HTML page and a
success status, leaves the page unstyled while the network panel shows a request
that apparently worked. Check the header on the deployed file.
An integrity hash goes stale when the file changes after hashing: a hand edit on
the server, a CDN that minifies on the way through, or a build that hashes
before its last rewrite. The browser treats the mismatch as a network error and
renders without the sheet. On another origin, integrity also needs CORS: a
crossorigin attribute on the link and a matching header from the server.
Compute the hash in the step that writes the final file.
A framework stylesheet on a public CDN used to be justified by readers already having it cached from other sites. The Fetch standard partitions the HTTP cache by top-level site, so each site’s copy is fetched and stored separately, and what remains is a second host on the critical path under someone else’s control. Serving the file from the site’s own host costs the same bytes without the extra connection.
Further reading
- CSS Object Model (CSSOM) — what a style sheet is inside the browser, and the interface scripts use to read and change it.
- HTML Standard: Links —
the
stylesheetlink type, the content-type rule and when a stylesheet blocks rendering. - Subresource Integrity — the
integrityattribute and what the browser does with a file that fails the check. - Fetch Standard: HTTP cache partitions — how the cache is keyed by top-level site.
- CSS Paged Media Module Level 3 — the
@pagerule and page margins a print stylesheet works with. - Media Queries Level 5 — print,
screen, colour-scheme preferences and the other conditions a
mediaattribute can test.