CSS Formatter

Use this CSS formatter to format CSS you received from anywhere: a minified bundle, a chat message, or a half-finished stylesheet. It splits single-line rules onto separate lines, normalizes spacing around colons and semicolons, and can strip comments or lowercase hex colors as it works. Everything runs in your browser, so nothing you paste ever leaves the tab.

Preset examples
Renders as you type. Nothing is uploaded.
—

How the Formatter Works

The formatter makes a single walk over the input with a small set of special states. A single-quoted or double-quoted string is copied through to its closing quote with backslash escapes honored, so a content value holding a brace or a semicolon never splits a block. A block comment is either dropped or printed on its own line. The url() function is consumed up to its matching parenthesis, which keeps asset paths and data links out of the declaration splitter. When a declaration starts with a custom property name, the whole value is read up to the next top-level semicolon, and any braces or parentheses nested inside that value pass through untouched.

Commas carry different jobs in different places. In a selector list, each top-level comma records a split point, and when the opening brace arrives the list is printed one selector per line with the brace attached to the last row. In an at-rule prelude such as a media query, the commas stay on the single line, because breaking a condition list makes the query harder to scan. The tokenizer remembers whether the current line began with an at-keyword to tell the two cases apart.

Indentation is plain brace depth. Every opening brace raises the level, every closing brace lowers it, and each emitted line is prefixed with the indent string repeated once per level. Nested rules, at-rules, and keyframe stops line up under their parents with no selector-aware logic.

A post-pass then touches the emitted lines. Inside any block, a colon with no space after it gets one, and a last declaration missing its semicolon gets one appended; comment rows and lines ending in a comma are skipped. The pass never reorders declarations or rewrites values, so feeding the output back into the input yields the same text again. That stability is worth one quick check: paste the result back and confirm the stats line does not move.

What the tokenizer treats as opaque

Four kinds of input are copied as raw runs rather than split into tokens. Quoted strings swallow everything up to their closing quote, including escaped quotes and any brace characters a content value happens to contain. Block comments are lifted out whole so an unterminated one produces an error instead of eating the rest of the file. url() is consumed through its final parenthesis, which protects paths that contain parentheses or query separators. Custom properties keep their entire value, even one holding a nested block for a fallback, because splitting a custom property would change what the variable holds.

Reading the stats line and the error banner

The stats line under the options reports three numbers after every render: bytes in, bytes out, and the line count of the output. Bytes are measured with a UTF-8 encoder, so multi-byte characters in font stacks or content values are counted the way a server would count them. The red banner appears only when the formatter refuses to emit output, which happens for unbalanced braces, an unterminated string, and an unterminated comment. While the banner is visible, the output box still shows the previous good render, which makes it easy to compare the broken edit against what the page last produced.

Examples

The four preset buttons load the samples below. Each row pairs the exact input string with the output the formatter returns under the default options: two-space indent, comments kept, hex case untouched.

Preset Before After
Minified Rules Tight rules on single lines that get opened up into separate blocks. a{color:#333;text-decoration:none}h1,h2{margin:0;padding:8px}
a {
  color: #333;
  text-decoration: none;
}
h1,
h2 {
  margin: 0;
  padding: 8px;
}
Media Query A width condition held on one line while the selector list below it splits into separate rows. @media (min-width:640px) and (max-width:1024px){.card h1,.card h2,.card h3{font-size:clamp(1.5rem,4vw,2.5rem)}}
@media (min-width:640px) and (max-width:1024px) {
  .card h1,
  .card h2,
  .card h3 {
    font-size: clamp(1.5rem,4vw,2.5rem);
  }
}
Theme Variables Named values that carry a raw image link and color codes, each one kept to a single line. :root{--brand:#FF6600;--paper:url(/img/paper.png);--surface:#FFFFFF;--ink:#101820}
:root {
  --brand: #FF6600;
  --paper: url(/img/paper.png);
  --surface: #FFFFFF;
  --ink: #101820;
}
Keyframes Timing marks that drive a spinning icon, led by a comment that can be kept or removed.
/*! spinner timing for the header mark */
@keyframes spin{from{transform:rotate(0deg)}50%{opacity:.6}to{transform:rotate(360deg)}}
/*! spinner timing for the header mark */
@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  50% {
    opacity: .6;
  }
  to {
    transform: rotate(360deg);
  }
}

When to Use This Tool

Formatting is a reading task rather than a build step, so the moments that call for it are the moments when a stylesheet stops making sense on screen. The list below covers the situations where pasting into this page is faster than squinting at a minified line or retyping a snippet by hand.

  • A vendor ships a minified stylesheet and you need to read one rule before patching it by hand.
  • Snippets from documentation, a ticket, or a design handoff need to land in one file with matching indentation.
  • A teammate pasted a rule into chat as a single line and you want it expanded before committing.
  • Two versions of a stylesheet differ by thousands of whitespace-only lines, so you format both first and the diff shows real changes.
  • You just finished a manual edit and want the brace balance checked before the file goes into review.
  • A bug report includes a style dump that collapsed in transit, and formatting restores the nesting so the reader can follow it.
  • You are writing a pull request comment and want a short block of CSS readable without horizontal scrolling.

Best Practices

These habits keep the formatted copy and the file in your repository in agreement, and they keep the toggles from removing text you still need.

  1. Run the formatter once the edit is finished. Formatting mid-edit, then editing the output in another window, leaves two copies that drift apart.
  2. Match the indent width to the rest of the project and keep that choice for the whole file.
  3. Leave strip-comments off when the stylesheet carries license or attribution text inside block comments.
  4. Paste the formatted result back into the input once. If the stats line is identical, the output is stable and safe to commit.
  5. Diff against the original with whitespace-sensitive settings on the first pass, so moved declarations are visible rather than hidden in a noisy diff.
  6. Send the beautified copy through a CSS minifier for the production build; the pretty version is for reading and review.

Common Mistakes

Each of these has shipped in a real project at some point. They all come from treating the browser page like an editor with a save button, or from running the formatter at the wrong point in the workflow.

  1. Formatting in the browser, then hand-editing the formatted copy and closing the tab without copying. The page holds no history and nothing is saved.
  2. Leaving strip-comments on and overwriting a source file whose block-comment banner held the license text.
  3. Treating the hex case toggle as a functional change. #FF6600 and #ff6600 match the same color; the toggle only unifies how the file looks.
  4. Formatting a generated file such as a bundler dump or a framework utility export, because the next build replaces the formatted copy anyway.
  5. Editing the output box and expecting the stats line to follow. The numbers describe the last render of the input, so copy the result instead of retyping into it.
  6. Ignoring an unbalanced-brace banner and pasting the previous output somewhere as if it matched the input. Fix the braces first and let the page render again.

Frequently Asked Questions

Does this tool change the meaning of my CSS?

No. Whitespace between tokens is not significant in CSS, so re-wrapping lines and adjusting indentation keeps the cascade identical. The only value-level change offered is lowercasing hex colors, and a hex triplet is case-insensitive, so #FF6600 and #ff6600 select the same color. Selector lists, at-rule preludes, and declaration values are copied character for character apart from the spacing rules described on this page.

What happens when braces do not match?

The formatter counts opening and closing braces as it walks the input, and it reports an error when the totals disagree or a closing brace appears with nothing open. The red banner under the options shows the message, the input is left untouched, and the output box keeps whatever it held before the broken edit. Fix the stray or missing brace and the next keystroke renders again.

Can it remove comments?

Yes. The strip-comments checkbox removes block comments, including the special banner form that build tools keep for license text, so read the result before you overwrite a source file. With the box unchecked, each comment is placed on its own line at the current indentation level and nothing else about the block changes.

Why does a custom property stay on one line?

A custom property such as --brand:#FF6600 can hold any token sequence, including nested braces inside a fallback, so the formatter reads the whole value up to the terminating semicolon and keeps it together. Newlines inside the value are collapsed to single spaces rather than split apart, which is what most preprocessors do when they print variables.

Does it minify or shrink file size?

No. This page only beautifies. Minified input usually comes back larger because each declaration moves onto its own line, and the stats line shows both byte counts so the difference is visible. When you need the opposite direction, run the result through a CSS minifier afterwards.

Will it fix my syntax errors?

It repairs a missing trailing semicolon on the last declaration of a block and normalizes spacing around colons, which covers the two most common hand-editing slips. It does not guess at misspelled properties, unmatched parentheses inside a value, or selectors with the wrong combinator, because guessing there would change what the rules match.

Is there a size limit or does it send my CSS anywhere?

There is no hard limit beyond what the browser can hold in a textarea, and formatting runs entirely in the page. No network request carries your stylesheet, so the tool keeps working after the page has loaded even if the connection drops, and closing the tab discards everything.

How to Format CSS Online

  1. Paste your CSS or load a preset

    Drop any stylesheet into the input box, or press one of the four preset buttons to load a sample covering minified rules, a media query, theme variables, and keyframes.

  2. Pick indent width and toggles

    Choose two spaces, four spaces, or a tab for indentation, then decide if comments should be stripped and if hex colors should be lowercased. The output refreshes on every keystroke.

  3. Copy the formatted result

    Read the stats line for byte counts and line totals, watch the red banner if unbalanced braces or an unterminated string are found, then press Copy to take the output.