Perfect Pre Tags

If you operate a website that features lots of code examples, you know how important it is to spend some quality time styling the <pre> element. When left unstyled, wild <pre> tags will mangle your preformatted content and destroy your site’s layout. Different browsers treat the <pre> tag quite differently, varying greatly in their default handling of font-sizing, scrollbar-rendering, and word-wrapping. Indeed, getting your preformatted code to look consistent, usable, and stylish across browsers is no easy task, but it certainly can be done. In this article, I’ll show you everything you need to create perfect <pre> tags.

First thangs first

Before getting into it, let’s take a moment to ensure we’re all on the same page. The (X)HTML <pre> element is used to display preformatted text, code, or just about anything else. pre tags are ideal for multiple lines of code or text that need to retain character spacing, display unformatted characters, keep inherent line breaks, and so on.

Let’s say we have the following code that we want to include in a web page:

<?php function shortLink($atts, $content = null) {
	extract(shortcode_atts(array(
		"href" => 'http://' // default URL
	), $atts));
	return '<a href="'.$href.'">'.$content.'</a>';
}
add_shortcode('link', 'shortLink'); ?>

After converting the “<” characters to their encoded equivalents, “&lt;”, we would wrap the code in <pre> tags and get this in the browser:

<?php function shortLink($atts, $content = null) {
	extract(shortcode_atts(array(
		"href" => 'http://' // default URL
	), $atts));
	return '<a href="'.$href.'">'.$content.'</a>';
}
add_shortcode('link', 'shortLink'); ?>

Looks pretty similar, eh? Notice that the line breaks, spacing, and unencoded characters (besides opening brackets) That’s the whole point: the <pre> tag enables you to easily display raw chunks of source code, text (think poetry), and any other content that we don’t want the browser to process. Now let’s look at that same code when displayed without <pre> tags:

extract(shortcode_atts(array(
"href" => ‘http://’ // default URL
), $atts));
return ‘‘.$content.’‘;
}
add_shortcode(‘link’, ‘shortLink’); ?>

As you can see, when not wrapped in <pre> tags, code examples such as this are inaccurate and essentially useless. <pre> elements ensure that the content retains its “natural” format, which is crucial for displaying code, poetry, equations, and other types of specialized content.

Also, note that the <code> element is frequently used in conjunction with the <pre> tag when using syntax highlighters and formatting plugins such as the excellent Code Auto Escape. For example, here at Perishable Press, all multi-line code examples are wrapped with <pre><code> and then auto-escaped using the Auto Escape plugin, which automatically escapes all characters within <pre> elements, eliminating the need to manually convert, say, opening brackets to their encoded equivalents. Many other syntax highlighters and code-formatting plugins also provide this functionality, greatly facilitating the post-writing process. Such tools help you streamline production and improve display of your preformatted content.

One last thing about the <pre> tag before we dive into the good stuff. You should keep in mind that <pre> tags are used for displaying blocks of preformatted characters. That is, regardless of how many lines of text or code you use, the <pre> tag is a block-level element and will display its content as such. Conversely, the <code> tag is an inline element that is perfect for displaying individual words, characters, and lines of preformatted text within a block-level element. For example, I use the <code> tag all the time — just check out the source code of the previous couple of sentences to see what I mean.

Displaying preformatted content & dealing with overflow

Default behavior: horizontal scrollbars

One of the biggest challenges to displaying preformatted content using the <pre> tag is dealing with continuous strings of characters such as URLs and long chunks of code. By default, the <pre> element handles this by stretching to fit its content. Assuming that no widths have been specified in the CSS, the <pre> element will expand in length to accomodate its longest line of content. Interesting, but not very practical in most design scenarios. As soon as a constraining width is applied, the <pre> element uses a horizontal scrollbar to accomodate any content that doesn’t “fit” within the display area. This default behavior is deployed in the stylesheet like this:

pre {
	overflow: auto;
	width: 500px;
	}

This is a commonly seen way of dealing with oversized <pre> content. It’s fast, easy, and effective. Even so, not everyone likes to scroll..

Word-wrapping

Instead of using a scrollbar to display long lines of preformatted text, some prefer to wrap the content within the display area of the <pre> element. When we wrap preformatted content, any lines that extend beyond the specified width will wrap to the next line. As simple as this sounds, some browsers have real problems when it comes to continuous strings of text such as long URLs. Many browsers are unable to break up continuous lines of text unless specifically instructed to do so. Fortunately this is possible using a crefully crafted set of CSS directives.

To enable word-wrapping for your <pre> content, use the following slice of CSS and edit the first directive to set the desired width:

pre {
	width: 500px;                          /* specify width  */
	white-space: pre-wrap;                 /* CSS3 browsers  */
	white-space: -moz-pre-wrap !important; /* 1999+ Mozilla  */
	white-space: -pre-wrap;                /* Opera 4 thru 6 */
	white-space: -o-pre-wrap;              /* Opera 7 and up */
	word-wrap: break-word;                 /* IE 5.5+ and up */
	/* overflow-x: auto; */                /* Firefox 2 only */
	/* width: 99%; */		       /* only if needed */
	}

Once in place, this code will force your <pre> areas to stay at 500 pixels wide. If any continuous lines extend beyond this width, they will be broken and wrapped accordingly.

Auto-expanding code box with CSS

If word-wrapping isn’t for you, you may want to implement some auto-expansion functionality. Using a small snippet of CSS, it is possible to style your <pre> tags such that they magically expand whenever the user hovers their mouse. So, for example, your <pre> areas would display normally at 500pixels in width, but as soon as the user hovers their cursor over the area, it would instantly expand to a larger width, say, 700 pixels.

Setting this up is easy. Just include the following CSS in your stylesheet and enjoy the results:

pre {
	overflow: auto;
	width: 500px;
	}
pre:hover {
	position: relative;
	width: 700px;
	z-index: 99;
	}

Of course, you will want edit the width values according to your needs and customize your <pre> and hover styles to look all sweet. You know.

There are some pros and cons to this method. Here are some of the pros:

  • It works great without requiring any JavaScript.
  • Scrollbars appear only when the box is not expanded.
  • The boxes expand instantly — no waiting required.
  • Works fine even without an inner <code> wrapper.

..and of course some of the cons:

  • All <pre> tags expand even if it’s not necessary (i.e., the code fits)
  • The sudden display change may disorient/confuse newer web users.
  • Expanding box may interfere with other page elements.
  • Even after expansion, the <pre> are may still require horizontal scrollbars to see all of the content.

Auto-expanding code box with jQuery et al

The CSS expanding-box method works nice, but it’s a bit choppy — upon hover, it’s like, BAM — suddenly you’re staring at a full-size code box. Using a little bit of jQuery, we can create a much smoother expanding code box, as originally shared by Chris Coyier at Digging into WordPress.

The jQuery method is an improvement over the CSS method, behaving more elegantly:

  • Expands only when hovered over
  • Expands only as wide as necessary
  • Expands with some nice animation

To implement, begin by styling the <pre> element with a little CSS:

pre {
	overflow: auto;
	width: 500px; 
	}

This will prepare the <pre> element for the following JavaScript:

$(function(){
	$("pre").hover(function() {
		var codeInnerWidth = $("code", this).width() + 10;
		if (codeInnerWidth > 500) {
			$(this).stop(true, false).css({zIndex:"99",position:"relative",overflow:"hidden"}).animate({width:codeInnerWidth+"px"});
		}
	}, function() {
		$(this).stop(true, false).animate({width:500});
	});
});

And that’s pretty much it. You’ll want to customize the CSS and jQuery to fit your needs, but the main thing is getting all of the widths to match up (both in the CSS and JavaScript). When JavaScript is unavailable on the user’s browser, this method degrades gracefully to default <pre> elements with auto-scrollbars.

As discussed at Digging into WordPress, this method requires that your preformatted content is wrapped in both <pre> and <code> tags. For complete information, check out the the original article.

Whipping scrollbars into shape

Vertical scrollbars, height, and Internet Explorer

If you do decide to use scrollbars to display overflow content, you will discover many inconsistencies across browsers, especially (surprise surprise) Internet Exploder. The first thing to understand is that, on standards-compliant browsers (i.e., anything other than IE) vertical scrollbars will only appear if an explicit height is specified for the <pre> element. If it is, vertical scrollbars will appear whenever the preformatted content contains more lines than is viewable within the specified height.

Why is this important? Because it makes eliminating vertical scrollbars rather easy. As a general rule of thumb, I never specify heights for preformatted content, but there are situations where you might want to do so.

As for our ‘ol friend IE, you are pretty much going to get vertical scrollbars regardless of whether or not you declare a height. They just appear on their own. Like friends of that squatter you mistakenly let stay with you for awhile.

Fortunately, there are effective ways to exterminate those stinky vertical scrollbars in IE. Here is the method I use on many of my sites:

/* no vertical scrollbars for standards-compliant browsers */
pre {
	overflow: auto; 
	width: 500px;
	}
/* no vertical scrollbars for IE 7 */
*:first-child+html pre {
	padding-bottom: 20px;
	overflow-y: hidden;
	overflow: visible;
	overflow-x: auto; 
	}
/* no vertical scrollbars for IE 6 */
* html pre { 
	padding-bottom: 20px;
	overflow: visible;
	overflow-x: auto;
	}

That code is pretty much plug-n-play with only the essentials, but you will want to customize the width in the first declaration block and add other styles as desired. What’s happening with this code? Glad you axed. Lemme break it down:

  1. first block — sets default scrolling for standards-compliant browsers; no vertical scrollbars unless explicit height is set.
  2. second block — hack for IE 7 that removes the vertical scrollbar and adds a bit of padding to make room for any horizontal scrollbar that might be present.
  3. third block — hack for IE 6 that removes the vertical scrollbar and also adds some padding.

Of course, rather than using unsightly CSS hacks for IE, it’s best practice to summon them via conditional comments. Once in place, this code will neutralize and eliminate those nasty vertical scrollbars in IE and provide some extra bottom-padding to make room for horizontal scrollbars when they appear. This code is effective, but the additional padding is not needed when the content fits within the <pre> area and the horizontal scrollbar does not appear, resulting in an awkward blank line. Fortunately we can turn to JavaScript to account for this dynamic display property.

Fixing IE’s funky inside scrollbars with JavaScript

IE is so bad..” — how bad is it? It renders horizontal <pre> scrollbars on the inside of the element. This sucks because it interferes with content, pushes everything up about 20 pixels, and invokes display of the unnecessary vertical scrollbar.

We saw how to remedy this display deficiency using CSS in the previous section, but it wasn’t quite ideal because of the extra bottom padding that is used to ensure content display when horizontal scrollbars appear. A better way to handle it is to use a little JavaScript to do the following:

  1. Check if the browser is Internet Explorer
  2. Find all <pre> elements with overflowing horizontal content
  3. Add 20 pixels of bottom padding to account for the horizontal scrollbar
  4. Remove the vertical scrollbar

Thankfully, Remy Sharp delivers this functionality with the following slice of JavaScript:

window.onload = function () {  
	// only apply to IE  
	if (!/*@cc_on!@*/0) return;  
	// find every element to test  
	var all = document.getElementsByTagName('*'), i = all.length;  
	// fast reverse loop  
	while (i--) {    
		// if the scrollWidth (the real width) is greater than 
		// the visible width, then apply style changes    
		if (all[i].scrollWidth > all[i].offsetWidth) {
			all[i].style['paddingBottom'] = '20px';
			all[i].style['overflowY'] = 'hidden';
		}
	}
};

..and as if that weren’t cool enough, here’s the same functionality via jQuery:

(function ($) {
	$.fn.fixOverflow = function () {
		if ($.browser.msie) {
			return this.each(function () {
				if (this.scrollWidth > this.offsetWidth) {
					$(this).css({ 'padding-bottom' : '20px', 'overflow-y' : 'hidden' });
				}
			});
		} else {
			return this;
		}
	};
})(jQuery);
// usage
$('pre').fixOverflow().doOtherPlugin();

Either of these methods will do the job nicely, making IE appear to display any horizontal scrollbars on the outside of the <pre> element.

Interestingly enough, we can also execute this dynamic functionality from within the stylesheet and eliminate the need for any JavaScript. By using one of IE’s proprietary expression properties, we can include the following directly in our IE-only stylesheet:

pre {
	width: 500px;
	overflow-x: auto;
	overflow-y: hidden;
	padding-bottom: expression(this.scrollWidth > this.offsetWidth ? 20 : 0);
	}

Just specify the width and you’re off to the races. For either of these dynamic methods (i.e., JavaScript, jQuery, or CSS expression), keep in mind that we are treating horizontal overflow issues when an explicit vertical height has not been specified.

Bonus tip: displaying a name for each class of <pre> text

If you have different types of preformatted content, you can output the name of each one within the content itself. To illustrate, let’s say you provide different types of code snippets at your site, such as CSS, HTML, and PHP. By adding a class to an inner <code> element, you can combine CSS-2.1’s attribute selector and :after pseudo-element selector to display the class name within the preformatted content area.

pre code[class]:after {
  content: 'highlight: ' attr(class);
  display: block; text-align: right;
  font-size: smaller;
  padding-top: 5px;
}

Then, you set up your preformatted code like so:

<pre><code class="CSS">

The class name you specify for each type of code block will then be displayed to the bottom-right of the preformatted content area. Shouts out to Chris Coyier for this awesome trick.

Styling preformatted content

Now that we know how to improve the physical properties of the <pre> element, let’s wrap things up with a few ideas for styling the actual preformatted content.

Fonts

When styling your preformatted content, employ fonts suitable to its purpose. For example, if your site is mostly sporting code snippets, throw down with some tough monospace typography:

  • monospace
  • "Courier new", Courier, "Andale Mono", monospace
  • Consolas, "Lucida Console", Monaco, monospace
  • 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

To create the perfect monospace font stack, you really should be testing on as many different browsers as possible. Check different operating systems, browsers, zoom settings, and types of preformatted content. A couple of notes: Courier is an incredibly tight-looking font that, unfortunately, does not scale well on all browsers/systems. Particularly, there seems to be a lower-limit to the display size of the Courier font. Also, to get things looking right on both PC and Mac without all the fuss, simply declare “monospace” for your <pre> font and you’ll get a great-looking font on both systems.

Borders

While maybe not beneficial to every block of preformatted text, a nice set of borders can really help accent and emphasize your content. Especially for code snippets, adding a border around the area can help users discern easily between it and the post content.

The are many cool things that can be done with <pre> borders:

  • Place a border on only one or two sides of the <pre> text
  • Use varying widths and/or styles (e.g., dotted or custom image)
  • Get all “Web-2.0” and round your corners

Colors

Colors are another inspiring thing to play with when it comes to styling the presentation of your <pre> elements. You can color the text itself, the background, and the borders. Anything is possible here, I just wanted to point out that a good combination of colors for these different properties can really help your <pre> areas “pop.” Also fun to play with when choosing the perfect color combination is transparency, which might be used to let the background show through just a bit. Background images also present unlimited possibilities, such as adding a personal logo/icon or even a nice drop shadow for the upper/left border.

How I roll..

Last but not least, here is the template snippet that I use as a base for styling <pre> tags. After splicing this little snippet into my stylesheet, I proceed to tweak and fuss ‘til everything’s just right..

code, samp, kbd {
	font-family: "Courier New", Courier, monospace, sans-serif;
	text-align: left;
	color: #555;
	}
pre code {
	line-height: 1.6em;
	font-size: 11px;
	}
pre {
	padding: 0.1em 0.5em 0.3em 0.7em;
	border-left: 11px solid #ccc;
	margin: 1.7em 0 1.7em 0.3em;
	overflow: auto;
	width: 93%;
	}
/* target IE7 and IE6 */
*:first-child+html pre {
	padding-bottom: 2em;
	overflow-y: hidden;
	overflow: visible;
	overflow-x: auto; 
	}
* html pre { 
	padding-bottom: 2em;
	overflow: visible;
	overflow-x: auto;
	}

Rather than another long-winded diatribe exploring the manifold intricacies and subtleties of this particular stylistic strategy, I defer to your currently established comprehension of CSS and invite subsequent analysis of its constituent declarations. Or, in the parlance of the day: “it’s plug-n-play, dude – I’m outta here!!!

Hungry for more

As mentioned, I post a lot of code here at Perishable Press. So much so, that I have become rather obsessed with the fine art of formatting and styling preformatted content. As tweeted the other day, I could spend all day just fussing over <pre> code. To me, it really is that important. In this article, I have shared many different techniques for creating perfect <pre> tags, but these methods are far from exhaustive. I am always on the lookout for new and useful ways to improve the appearance and functionality of my preformatted code examples, so if you happen to know any sweet tricks that I missed, share them and I will update the article with the method and link to your site.