The basics
What is a CSS file?
HTML says what's on a page: this is a heading, this is a list, this is a button. CSS says how it looks: the heading is dark blue and 2rem tall, the list sits in two columns on wide screens, the button turns darker when you hover over it. A CSS file, also called a stylesheet, holds those instructions as plain text.
Keeping styles in a separate file means a whole site can share one look: change a colour in style.css and every page that links to it updates. The browser downloads the file once and reuses it from its cache on the next page.
CSS doesn't have to live in a .css file. There are three places it can go:
- A separate
.cssfile, linked from each page with<link rel="stylesheet">. Best for anything shared between pages. - A
<style>element inside the HTML page. Common in single-file pages and HTML emails. - A
styleattribute on one element, such as<p style="color: red">. It beats rules from stylesheets, which makes it hard to override later.
Anatomy
What's inside a CSS file
A stylesheet is a list of rules. Each rule has a selector, which picks elements on the page, and a block of declarations in curly braces, each a property and a value. Here is a short stylesheet, part by part.
/* Site styles */
@import url("reset.css");
:root {
--brand: #046eff;
}
body {
font-family: system-ui, sans-serif;
margin: 0;
}
.button,
.link:hover {
background: var(--brand);
padding: 0.5rem 1rem;
}
#main > p:first-child {
font-size: 1.25rem;
}
@media (max-width: 600px) {
.button { display: block; }
}- 1
/* Site styles */A comment
The only comment syntax CSS has. A
//comment isn't valid CSS: the parser reads it as part of whatever comes next, which breaks that rule or declaration, so it gets dropped. - 2
@import url("reset.css");An at-rule
Rules starting with
@are instructions rather than styles.@importpulls in another stylesheet. It must come before all other rules except@charset,@layerstatements and other imports, and the browser can only discover the imported file once this one has loaded, which slows the page down. - 3
:root { --brand: #046eff; }A custom property
A variable: any property name starting with
--. Set on:root, the top of the page, it's available to every element. - 4
body {A selector
This one matches the
<body>element by its tag name. Everything between the braces applies to it. - 5
font-family: system-ui, sans-serif;A declaration
A property, a colon, a value and a semicolon. Fonts are a fallback list: the browser uses the first one available. Text properties like this are inherited, so every element inside the body gets the same font.
- 6
.button, .link:hover {A selector list
A comma applies the same rule to several selectors: here anything with
class="button", and anything withclass="link"while the pointer is over it.:hoveris a pseudo-class, a state rather than something in the HTML. - 7
background: var(--brand);Using the variable
var()reads the custom property. Change--brandonce and every rule that uses it changes. - 8
padding: 0.5rem 1rem;A shorthand with units
Two values mean top and bottom first, then left and right.
remis relative to the root font size, so spacing grows if the reader enlarges text. - 9
#main > p:first-child {A more specific selector
An
id(#main), the child combinator>and a pseudo-class. Because it includes an id, this rule beats rules that use only classes and tag names, wherever they are in the file. - 10
@media (max-width: 600px) {A media query
The rules inside apply only when the condition is true: here on screens up to 600 pixels wide. This is how one stylesheet adapts to phones.
Under the hood
The cascade: how a browser decides which rule wins
Several rules often set the same property on the same element. The "cascading" in the name is the set of rules that settles it. The browser compares the competing declarations in this order and stops at the first difference:
- 1Origin and importance. The page's own CSS beats the browser's defaults. A declaration marked
!importantjumps ahead of normal ones. - 2Inline styles. A
styleattribute beats rules from stylesheets. - 3Cascade layers. With
@layer, rules in a later layer beat rules in an earlier one; rules outside any layer beat all layers. - 4Specificity. The more specific selector wins, as the table below shows.
- 5Order. If everything else is equal, the rule that comes last wins, including rules in files linked later in the page.
| Selector | Specificity | Beats |
|---|---|---|
p | (0,0,1) | Only the browser defaults |
.intro | (0,1,0) | Any number of element selectors |
.card .intro | (0,2,0) | .intro, wherever it comes in the file |
#main p | (1,0,1) | Any number of classes |
Separate from the cascade is inheritance: some properties, mostly text ones such as color and font-family, pass from an element to everything inside it unless something overrides them. Layout properties like margin and border don't.
Connecting it
How a page loads a CSS file
<head>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/print.css" media="print">
<style>
/* page-specific rules can still go here */
</style>
</head>- The browser waits for stylesheets in the
<head>before it shows the page, so it doesn't flash unstyled content. A large or slow stylesheet delays the whole page. mediamakes a stylesheet conditional. Hereprint.cssonly applies when printing, and doesn't hold up the screen version.- Paths inside CSS are relative to the CSS file, not the page. In
css/style.css,url("img/logo.png")meanscss/img/logo.png. Useurl("../img/logo.png")to go up a level. - The
Content-Typemust betext/css. Browsers ignore a stylesheet served as anything else, such astext/htmlortext/plain, on any page in standards mode (one that starts with<!DOCTYPE html>).
History
CSS1, CSS2, CSS3 and why there is no CSS4
CSS level 1 became a W3C Recommendation in December 1996, CSS level 2 in May 1998, and the corrected CSS 2.1 in June 2011. After that, the specification was split into separate modules (Selectors, Color, Flexbox, Grid and many more), each with its own level number. "CSS3" became a name for everything after 2.1, and there is no single "CSS4". Instead, the Working Group publishes a yearly CSS Snapshot listing which modules make up current CSS.
For a stylesheet, the version doesn't matter: there's no version line in a CSS file. What matters is which features the browsers you care about support. Some milestones:
| Feature | What it does | In all major browsers since |
|---|---|---|
| Grid layout | Two-dimensional page layout | 2017 |
Custom properties (--x, var()) | Variables in CSS | 2017 |
Cascade layers (@layer) | Ordering groups of rules, as in the sample file | 2022 |
Container queries (@container) | Styling by the size of a container, not the window | 2023 |
Nesting (&) | Rules inside rules, as in Sass | 2023 |
:has() | Selecting an element by what it contains | 2023 |
Troubleshooting
Why isn't my CSS working?
Open the browser's developer tools (F12, or Option+Command+I on a Mac) and inspect the element. The Styles panel shows every rule that matches, with overridden declarations crossed out. Most problems are one of these:
| Symptom | Usual cause | Fix |
|---|---|---|
| No styles at all | Wrong path in the <link>, so the file returns 404 | Check the Network panel; remember paths are case-sensitive on most servers |
| "Refused to apply style… MIME type ('text/html')" | The server sent an error page, or the wrong Content-Type | Fix the path, or serve .css files as text/css |
| One rule is ignored | Another rule wins on specificity, layer or order | Look for it crossed out in the Styles panel, then make your selector more specific or move it |
| Everything after a certain line is ignored | A syntax error such as a missing } or a // comment swallows the rules that follow | Run the file through the W3C CSS Validator |
| Changes don't show up | The old file is cached | Hard-reload, or add a version to the link: style.css?v=2 |
| Background images missing | url() paths are resolved from the CSS file's folder, not the page's | Fix the path relative to the stylesheet |
é instead of é in content: | The file is UTF-8 but was read as another encoding | Save as UTF-8 and add @charset "UTF-8"; as the very first line |
CSS fails quietly
A browser that doesn't understand a declaration skips just that declaration and carries on, and an unknown selector drops only its rule. That's what lets new features roll out gradually, but it also means a typo produces no error message, only a style that's silently missing.
How to
How to open, edit, check and minify a CSS file
- Open or edit it: any plain-text editor works; a code editor such as VS Code adds colour previews and autocompletion. Opened in a browser on its own, a CSS file shows as text.
- Experiment live: in the browser's developer tools you can change any declaration and see the result immediately. Changes are lost on reload, so copy them back into the file.
- Check it: paste it into the W3C CSS Validation Service, or try it on a page with our HTML tester.
- Minify it: build tools such as esbuild, Lightning CSS or cssnano remove comments and whitespace.
sample-minified.cssbelow is the commented sample after esbuild. - See any site's CSS: open the developer tools' Sources panel (Style Editor in Firefox), or follow the
<link>addresses in the page's source.
Security
Can a CSS file be dangerous?
CSS can't run programs in current browsers, so a stylesheet on its own can't install anything or read your files. The risks come from CSS that an attacker controls on someone else's page:
- Data leaks through selectors. An attribute selector can match a hidden value one character at a time, for example
input[value^="a"], and load a background image from the attacker's server when it matches. Repeated, that can leak tokens or other values written into the page. - Tracking. Every
url()is a request, so a stylesheet can tell a third-party server when and from where a page was viewed. - Fake content. Injected CSS can hide real text, overlay fake buttons or rewrite labels with
content:, which is enough for convincing phishing on a trusted domain.
Never insert user input into a <style> element or style attribute without strict validation, and treat third-party stylesheets as code you trust. A Content-Security-Policy with a style-src directive limits where stylesheets may come from.
Free downloads
Sample CSS files to download
Free sample CSS files for testing parsers, minifiers, upload filters, encodings and size limits. Each CSS file parses without errors in esbuild and the CSSTree validator.
Loading…What's inside sample-stylesheet.css
The stylesheet is commented: open it in a text editor and each numbered comment marks one of these parts. To see it applied, open sample-demo.html from the same folder.
Comment 1: cascade layers
@layer reset, base, components, utilities;sets the order of four layers in one line, so the utilities always win over components regardless of selector specificity.Comments 2 and 3: variables and dark mode
Colours, radius and spacing as custom properties on
:root, then aprefers-color-scheme: darkmedia query that redefines only the colour values.Comments 4 and 5: reset and base styles
box-sizing: border-boxfor everything, then fonts and colours onbodythat every element inherits.Comments 6 and 7: grid and nesting
A card grid that reflows with
repeat(auto-fit, minmax(14rem, 1fr)), and a card rule with nested& h2and&:hoverrules.Comment 8: specificity
Two rules for
.price. The first,.card .price, wins even though the second comes later, because (0,2,0) beats (0,1,0).Comment 9: pseudo-elements and :has()
::beforeadds a#to tags,:has()gives a card a coloured border when it contains a "new" tag, and an::afterrule writes the "Stylesheet: loaded" line on the demo page.Comments 10 and 11: animation and container queries
A pulsing dot that stops for people who prefer reduced motion, and a header that switches to two columns when its container is at least 40rem wide, inside an
@supportscheck.Comments 12 and 13: utilities and print
Helper classes in the last layer, and print rules that hide the animation and print each link's address after it.
All sample CSS files
Commented sample stylesheet
sample-stylesheet.css · 4.7 KB (4,784 bytes)
A realistic stylesheet using current CSS: cascade layers, custom properties, dark mode, grid, nesting,
:has(), container queries, animation and print styles, with numbered comments explaining each part.- Checking parsers and minifiers handle modern syntax
- Teaching how a stylesheet is organised
Demo page for the stylesheet
sample-demo.html · 1.8 KB (1,832 bytes)
An HTML page with no styles of its own that links to
sample-stylesheet.css. Keep both files in the same folder. If the stylesheet loads, the page says "Stylesheet: loaded".- Checking a host serves CSS with the right type and path
- Seeing the sample stylesheet in action
Minimal CSS file
sample-minimal.css · 65 bytes
One rule with two declarations: the smallest useful stylesheet.
- Parser tests
- A starting point for a new stylesheet
Minified CSS
sample-minified.css · 2.2 KB (2,223 bytes)
The sample stylesheet minified with esbuild: same rules on one line, comments removed except a
/*!licence-style comment, which minifiers keep by convention.- Comparing minified and readable CSS
- Testing formatters and source viewers
UTF-8 encoding test
sample-utf8.css · 1.0 KB (1,058 bytes)
Non-ASCII text in
content:strings (accents, Greek, Cyrillic, Chinese, Japanese, Korean, Arabic, Hebrew, symbols, emoji), the same characters as CSS escapes like\e9, and class names such as.caféand an escaped.\31 23.- Spotting encoding bugs in editors, servers and build tools
- Testing CSS escape handling
100 KB CSS file
sample-100kb.css · 100 KB (102,400 bytes)
About 3,300 generated utility classes, padded with a comment to exactly 102,400 bytes.
- Upload and size-limit tests
- Minifier and compression benchmarks
Ways to test with them
- Is CSS served correctly? Put
sample-demo.htmlandsample-stylesheet.cssonline together and open the page. If it doesn't say "Stylesheet: loaded", check the path and theContent-Type. - Modern syntax: run
sample-stylesheet.cssthrough your minifier, linter or CMS sanitiser. Older tools may reject nesting,@layeror@container, or quietly drop them. - Minification round trip: compare your minifier's output with
sample-minified.css; both should contain the same rules. - Encoding: pass
sample-utf8.cssthrough your pipeline and compare. AnyÃorâ€means a step didn't treat the file as UTF-8. - Upload limits:
sample-100kb.cssis exactly 102,400 bytes, for testing a limit at the boundary.
Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.
Put it online
Have a CSS file? Give it a link.
Drop a CSS file on 99helpers and it gets its own address in seconds. Opened in a browser, the link shows the stylesheet as text, and pages can load it from there with a <link> tag.
Questions
CSS files, frequently asked
What does CSS stand for?
Cascading Style Sheets. "Cascading" refers to the rules that decide which style wins when several apply to the same element.
How do I open a CSS file?
With any text editor, such as VS Code, Notepad or TextEdit in plain-text mode. A browser shows it as plain text; to see its effect, open the HTML page that links to it.
How do I link a CSS file to HTML?
Add <link rel="stylesheet" href="style.css"> inside the page's <head>, with the path from the HTML file to the CSS file.
Is CSS a programming language?
Not in the usual sense. It's a style sheet language: it describes how things look, and has no loops or general logic, though features like variables, calc() and media queries make it more capable than it first appears.
What's the difference between CSS and SCSS?
SCSS is the main syntax of Sass, a language that adds features such as mixins and functions and is compiled into plain CSS. Browsers read only CSS.
Why is my CSS not applying?
Usually the file isn't loading (wrong path, or served with the wrong Content-Type), the browser is using a cached copy, or another rule is more specific. The browser's developer tools show which.
Is there a CSS4?
No. Since CSS 2.1, CSS has been split into modules with their own levels. The W3C publishes a yearly CSS Snapshot of what current CSS includes.
Can a CSS file contain a virus?
No: CSS can't run programs. Attacker-controlled CSS on a web page can still leak some page data or show fake content, so sites shouldn't let users inject styles.
Related formats
Other file types explained
Keep going
Related
Sources
- W3C: CSS specifications and CSS Snapshot
- RFC 2318: The text/css Media Type
- W3C: A brief history of CSS
- MDN: @charset
- W3C CSS Validation Service
Last reviewed 27 October 2026.