The <pre> element is essential for displaying code examples, ASCII art, and any content where whitespace preservation matters. However, styling it presents unique challenges that trip up many developers. This guide covers the key considerations for creating polished, accessible, and performant code blocks that enhance your web development projects.
Understanding the Pre Tag
What Pre Does Differently
The <pre> element represents preformatted text that should be presented exactly as written in the HTML file. Unlike regular HTML content where whitespace collapses into single spaces, <pre> preserves spaces, tabs, and line breaks exactly as they appear in the source.
<pre>
function example() {
console.log("Indentation preserved");
}
</pre>
This preservation behavior makes `<pre>` ideal for code examples, configuration files, ASCII art, and poetry where visual formatting carries meaning.
### First Newline Stripping Behavior
One subtlety that catches many developers: if one or more newline characters appear immediately after the opening `<pre>` tag, the first newline is stripped. This explains why code examples sometimes render with unexpected top margin or misaligned first line.
### Block-Level Nature
By default, `<pre>` is a block-level element, meaning it creates a line break before and after its content. This differs from the inline `<code>` element, which is why nesting `<code>` inside `<pre>` provides the best of both worlds: block-level presentation with inline code semantics.
[MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/pre)
Semantic HTML Structure
Pairing Code with Pre
The <code> element should wrap code content inside <pre> for semantic correctness. This pairing communicates to assistive technologies that the content represents computer code rather than literal preformatted text.
<pre><code>
const greeting = "Hello, World!";
console.log(greeting);
</code></pre>
The `<code>` element semantically identifies text as code, while `<pre>` handles the presentation of preserved whitespace and monospace typography.
[CSS-Tricks](https://css-tricks.com/considerations-styling-pre-tag/)
### Related Elements: Samp and Kbd
For complete semantic coverage, the `<samp>` element represents sample output from computer programs, and `<kbd>` represents user input. These elements work together for comprehensive documentation:
```html
<pre><code><kbd>npm install</kbd> creates a new package.
The terminal displays <samp>Package added successfully</samp>.</code></pre>
Typography and Font Selection
Monospace Font Stacks
Code content requires monospace fonts where each character occupies equal horizontal space. Modern font stacks ensure consistent rendering across operating systems:
pre, code {
font-family: Consolas, "Andale Mono WT", "Andale Mono",
"Lucida Console", "Lucida Sans Typewriter",
"DejaVu Sans Mono", "Bitstream Vera Sans Mono",
"Liberation Mono", "Nimbus Mono L", Monaco,
"Courier New", Courier, monospace;
}
For simplicity, the generic monospace keyword provides acceptable rendering across all systems, though dedicated font stacks offer improved character rendering and aesthetic consistency.
Proper typography choices, including font selection for code blocks, are part of the broader CSS best practices that make professional websites stand out.
Font Sizing Considerations
Code examples often need slightly smaller font sizing than body text to fit within layouts. However, minimum font-size settings in user agents can override declarations below certain thresholds, particularly on Windows where Courier is a bitmap font available only in specific sizes.
Line Wrapping Decisions
The Wrap vs Scroll Debate
Developers face a fundamental choice: wrap long lines of code or enable horizontal scrolling. Each approach has trade-offs.
Wrapping keeps all content visible without horizontal scrolling but can make code harder to read when indentation becomes disconnected from its block. The white-space: pre-wrap value enables wrapping while preserving other whitespace behavior:
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
Scrolling maintains exact code formatting but requires users to scroll horizontally for long lines. This approach suits code where exact character positioning matters:
pre {
overflow-x: auto;
overflow-y: hidden;
}
Choosing the right approach for code display is one of many CSS techniques that impact user experience and site usability.
Cross-Browser Considerations
Different browsers handle line wrapping differently, particularly with long unbroken strings like URLs. Modern browsers support white-space: pre-wrap universally, but legacy browser support may require vendor prefixes.
Tab Width and Indentation Control
The Tab Character Challenge
Tab characters render as 8 spaces wide by default in most browsers, which is wider than the 4-space indentation standard in most code style guides. The tab-size property provides control:
pre {
tab-size: 4;
}
Note that tab-size affects display only--the underlying code remains unchanged. This allows developers to standardize indentation appearance without modifying source files.
Character Escaping and HTML Parsing
Why Escaping Matters
The <pre> element parses its text content as HTML. This means characters like <, >, and & are interpreted as HTML markup rather than displayed literally. Displaying code examples requires escaping these characters:
<pre><code>
<div class="example">
Content here
</div>
</code></pre>
Unescaped characters cause display issues or, worse, break page rendering entirely. Syntax highlighting tools typically handle escaping automatically during the transformation process.
[MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/pre)
### Common Character References
When escaping manually, these character references ensure proper display:
- `<` becomes `<`
- `>` becomes `>`
- `&` becomes `&`
Syntax Highlighting Integration
Why Syntax Highlighting Matters
Syntax highlighting improves code readability by applying colors to different language constructs. Popular libraries like Prism.js or Highlight.js parse code and wrap syntax elements in spans with appropriate classes.
<pre><code class="language-javascript">
function greet(name) {
return `Hello, ${name}!`;
}
</code></pre>
For teams building AI-powered web applications, syntax highlighting becomes even more important when documenting complex API integrations and code examples.
Library Selection Considerations
Prism.js is recommended for its small footprint, zero dependencies, and extensibility. The library offers theming support and can be customized to include only necessary language definitions.
Accessibility Implementation
Providing Alternative Descriptions
Preformatted text, especially ASCII art, requires alternative descriptions for screen reader users. The <figure> and <figcaption> elements, combined with ARIA attributes, make this content accessible:
<figure>
<pre role="img" aria-label="ASCII diagram showing server architecture">
+------------------+
| Load Balancer |
+--------+---------+
|
+--------+---------+
| Web Servers |
+--------+---------+
|
+--------+---------+
| Database |
+------------------+
</pre>
<figcaption>
Server architecture diagram showing load balancer
distributing requests to web servers connected to a database.
</figcaption>
</figure>
Without alternative text, screen readers announce preformatted content character-by-character, which fails to convey the intended meaning.
Accessibility-focused development is a core principle of our web development services, ensuring all users can engage with your content.
Preventing Translation Mangle
Adding class="notranslate" to pre elements prevents automated translation services from converting code examples, which would destroy their functionality:
<pre class="notranslate"><code>...</code></pre>
Performance Considerations
Minimizing Layout Impact
Large code blocks can impact page performance through:
- Complex syntax highlighting processing
- Excessive DOM elements from colorized code
- Layout thrashing from overflow calculations
Mitigation strategies include:
- Lazy loading syntax highlighting for below-the-fold code
- Using
content-visibility: autofor long code blocks - Limiting line numbers displayed
Performance optimization is essential for SEO success, as page speed directly impacts search rankings and user experience.
Scrollbar Performance
Horizontal scrollbars on pre elements trigger layout calculations. The overflow-x: auto property defers scrollbar creation until content overflows, improving initial render performance compared to overflow: scroll.
Cross-Browser Compatibility
Historical IE Challenges
Older versions of Internet Explorer rendered horizontal scrollbars on the inside of pre elements, interfering with content display. Modern browsers have resolved these inconsistencies, but maintaining awareness helps when supporting legacy environments.
Modern Best Practices
Current browser support allows straightforward implementation using standard CSS properties. Testing across Chrome, Firefox, Safari, and Edge ensures consistent code block rendering for all users.
Complete CSS Foundation
A robust CSS foundation for preformatted content combines all discussed considerations:
pre {
font-family: Consolas, Monaco, "Courier New", monospace;
font-size: 0.875em;
line-height: 1.5;
tab-size: 4;
/* Overflow handling */
overflow-x: auto;
overflow-y: hidden;
/* Spacing and visual treatment */
padding: 1em;
margin: 1.5em 0;
background-color: #f5f5f5;
border-radius: 4px;
}
/* Prevent translation of code examples */
pre[class="notranslate"] {
translate: no-op;
}
/* Code element inside pre */
pre code {
font-family: inherit;
font-size: inherit;
background: none;
}
Summary
Styling the <pre> element requires attention to semantic structure, typography, accessibility, and cross-browser behavior. By pairing <code> inside <pre>, selecting appropriate monospace fonts, choosing between wrapping and scrolling, controlling tab width, escaping special characters, and implementing accessibility features, developers create code blocks that are both beautiful and functional. These considerations ensure code examples enhance rather than detract from the user experience.