Skip to content

Formatting HTML without breaking your layout

By · HTML, CSS & JavaScript · 4 min read · Updated

Most code formatters can rearrange whitespace freely because the language ignores it. HTML is different: some whitespace is visible on the page. That is why formatting HTML sometimes makes a gap appear between two buttons, a link pick up a trailing underline, or an inline element shift by a few pixels. This guide explains how browsers treat whitespace, why formatters are cautious about it, and how to keep markup readable without changing the layout.

How browsers handle whitespace

When a browser renders text, it applies the CSS white-space rules. Under the default value, normal:

  • Sequences of spaces, tabs and line breaks collapse into a single space.
  • Whitespace at the start and end of a line box is removed.
  • Whitespace between block elements, such as div, p and section, does not render, because each block starts its own line.
  • Whitespace between inline elements, such as a, span, strong, img, button and input, renders as one space character.

The last rule causes all the trouble. Compare these two snippets:

<a href="/a">One</a><a href="/b">Two</a>

<a href="/a">One</a>
<a href="/b">Two</a>

The first renders as "OneTwo". The second renders as "One Two", because the line break between the links collapses into a visible space. A formatter that puts each link on its own line changes what users see.

Where it bites in practice

  • Inline-block layouts. Navigation bars and grids built with display: inline-block get unexpected gaps of about 4 pixels between items.
  • Links and punctuation. <a>docs</a>. written as the link and the full stop on separate lines produces "docs ." with a space before the dot.
  • Underlines and backgrounds. Whitespace inside an inline element, such as a line break before </a>, becomes an underlined or highlighted trailing space.
  • Pre-formatted content. Inside pre and textarea, and anywhere CSS sets white-space: pre, every space and newline is significant. Re-indenting them changes the content itself.

How Prettier deals with it

Prettier, used by the HTML Formatter, has an option called htmlWhitespaceSensitivity with three values:

  • css (the default) follows each element's default CSS display value. Whitespace around inline elements is treated as significant; around block elements it is not.
  • strict treats all whitespace around every element as significant, because CSS could make any element inline.
  • ignore treats all whitespace as insignificant, producing the tidiest output at the risk of changing the rendering.

To keep significant whitespace unchanged while still wrapping long lines, Prettier sometimes produces output that looks odd at first:

<a href="/docs">Read the documentation</a
><a href="/api">API reference</a>

The closing > moved to the next line so that no whitespace exists between the two links. It is unusual, but correct: the page renders exactly as before. If it bothers you, the fix is in the markup or CSS, not the formatter, as described below.

Making markup formatter-friendly

The best way to get clean formatting is to make whitespace stop mattering:

  1. Use flexbox or grid for layout. Whitespace between flex and grid items does not render, so inline-block gaps disappear and the formatter can lay out children freely.
  2. Use gap for spacing. Space between items should come from CSS, not from text spaces in the markup.
  3. Keep inline content on one line where it is short. A sentence with a link inside it reads fine on one line and has no ambiguity.
  4. Prefer block-level wrappers for groups. A list of buttons inside a flex container formats cleanly; the same buttons floating in a paragraph do not.

For a row of links or buttons, that is three lines of CSS. The markup can then be formatted any way at all, one element per line included, and it renders identically:

.toolbar {
  display: flex;
  gap: 8px;            /* spacing from CSS, not from spaces in the HTML */
  flex-wrap: wrap;
}

Once whitespace is not significant, you can safely switch the formatter to ignore it for that project, or keep the default and enjoy cleaner output anyway.

Other formatting choices

Attributes

Elements with many attributes, common in frameworks and with accessibility attributes, become hard to read on one line. Putting one attribute per line makes them scannable and produces clean diffs when a single attribute changes. Most teams use one attribute per line only when the element does not fit within the line width.

Line width

A width of 100 to 120 characters suits HTML better than the 80 common for other languages, because markup nests deeply and attribute values like class lists are long.

Embedded CSS and JavaScript

Prettier formats the contents of <style> and <script> tags with its CSS and JavaScript formatters. That keeps a single file consistent, but for anything substantial, separate files are easier to lint, cache and test.

Void elements

Elements like <br>, <img> and <input> have no closing tag. Writing <br /> is harmless in HTML5 and required in XHTML and JSX, so teams that mix HTML and JSX often keep the slash for consistency.

Formatting is not minifying

Formatting is for source code people read. Minification for production is a separate build step that also collapses whitespace, often more aggressively. Never format a minified production page to edit and re-deploy it; fix the source and rebuild. Formatting minified pages is still very useful for reading them, for example when you are debugging a third-party widget or checking which meta tags a page really serves.

Summary

Whitespace between inline elements is visible; whitespace between blocks is not. Default formatter settings respect that difference, which sometimes produces unusual line breaks. Use flexbox, grid and CSS gap for layout so whitespace no longer matters, and your HTML can be formatted as freely as any other code.