File types · Explainer

The CSS file (.css)

A CSS file is a plain-text stylesheet that tells a browser how to display a web page: colours, fonts, spacing and layout. This guide explains what's inside one, how browsers decide which rule wins, the quirks worth knowing, and has free sample CSS files to download for testing.

At a glance

Full name
Cascading Style Sheets
Extensions
.css
MIME type
text/css
Kind
Plain text (style rules)
Encoding
UTF-8 by default; a byte order mark, the HTTP header or @charset can declare another
Standard
W3C CSS Working Group: a family of modules, summarised in a yearly CSS Snapshot
First released
Proposed in 1994 by Håkon Wium Lie; CSS level 1 became a W3C Recommendation in 1996
Opens with
Any text editor to edit; browsers apply it to HTML pages
Comments
Only /* … */; there is no // line comment
Magic number
None

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 .css file, 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 style attribute 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.

style.css
/* 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. 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. 2@import url("reset.css");

    An at-rule

    Rules starting with @ are instructions rather than styles. @import pulls in another stylesheet. It must come before all other rules except @charset, @layer statements and other imports, and the browser can only discover the imported file once this one has loaded, which slows the page down.

  3. 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. 4body {

    A selector

    This one matches the <body> element by its tag name. Everything between the braces applies to it.

  5. 5font-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. 6.button, .link:hover {

    A selector list

    A comma applies the same rule to several selectors: here anything with class="button", and anything with class="link" while the pointer is over it. :hover is a pseudo-class, a state rather than something in the HTML.

  7. 7background: var(--brand);

    Using the variable

    var() reads the custom property. Change --brand once and every rule that uses it changes.

  8. 8padding: 0.5rem 1rem;

    A shorthand with units

    Two values mean top and bottom first, then left and right. rem is relative to the root font size, so spacing grows if the reader enlarges text.

  9. 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. 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:

  1. 1Origin and importance. The page's own CSS beats the browser's defaults. A declaration marked !important jumps ahead of normal ones.
  2. 2Inline styles. A style attribute beats rules from stylesheets.
  3. 3Cascade layers. With @layer, rules in a later layer beat rules in an earlier one; rules outside any layer beat all layers.
  4. 4Specificity. The more specific selector wins, as the table below shows.
  5. 5Order. If everything else is equal, the rule that comes last wins, including rules in files linked later in the page.
Specificity, counted as (ids, classes, elements)
SelectorSpecificityBeats
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

index.html
<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.
  • media makes a stylesheet conditional. Here print.css only 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") means css/img/logo.png. Use url("../img/logo.png") to go up a level.
  • The Content-Type must be text/css. Browsers ignore a stylesheet served as anything else, such as text/html or text/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:

FeatureWhat it doesIn all major browsers since
Grid layoutTwo-dimensional page layout2017
Custom properties (--x, var())Variables in CSS2017
Cascade layers (@layer)Ordering groups of rules, as in the sample file2022
Container queries (@container)Styling by the size of a container, not the window2023
Nesting (&)Rules inside rules, as in Sass2023
:has()Selecting an element by what it contains2023

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:

SymptomUsual causeFix
No styles at allWrong path in the <link>, so the file returns 404Check 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-TypeFix the path, or serve .css files as text/css
One rule is ignoredAnother rule wins on specificity, layer or orderLook for it crossed out in the Styles panel, then make your selector more specific or move it
Everything after a certain line is ignoredA syntax error such as a missing } or a // comment swallows the rules that followRun the file through the W3C CSS Validator
Changes don't show upThe old file is cachedHard-reload, or add a version to the link: style.css?v=2
Background images missingurl() paths are resolved from the CSS file's folder, not the page'sFix the path relative to the stylesheet
é instead of é in content:The file is UTF-8 but was read as another encodingSave 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.css below 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.

sample-stylesheet.css · 4.7 KBDownloadOpen
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.

  1. 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.

  2. Comments 2 and 3: variables and dark mode

    Colours, radius and spacing as custom properties on :root, then a prefers-color-scheme: dark media query that redefines only the colour values.

  3. Comments 4 and 5: reset and base styles

    box-sizing: border-box for everything, then fonts and colours on body that every element inherits.

  4. 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 & h2 and &:hover rules.

  5. 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).

  6. Comment 9: pseudo-elements and :has()

    ::before adds a # to tags, :has() gives a card a coloured border when it contains a "new" tag, and an ::after rule writes the "Stylesheet: loaded" line on the demo page.

  7. 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 @supports check.

  8. 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.html and sample-stylesheet.css online together and open the page. If it doesn't say "Stylesheet: loaded", check the path and the Content-Type.
  • Modern syntax: run sample-stylesheet.css through your minifier, linter or CMS sanitiser. Older tools may reject nesting, @layer or @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.css through your pipeline and compare. Any à or †means a step didn't treat the file as UTF-8.
  • Upload limits: sample-100kb.css is 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

Last reviewed 27 October 2026.