A client for whom I provide web services asked me if I could help her print barcode labels from their data.
Now, I’ve created Avery labels using Office, Illustrator, even Photoshop — but never using web technologies. You just don’t have a lot of control printing from your browser using CSS.
Or do you…? After all, we’ve always been able to specify real-world measurements such as “in” and “cm” using CSS.
I bought Avery 5160 labels because they seemed big enough to allow me to be a little sloppy while still providing many stickers per page.
A quick test proved that I could specify the page margins, label sizes, and gutter widths in inches. And both Firefox and IE allowed me to set the print margins to 0, leaving control of the layout to my CSS. Here’s what the print preview looks like from Firefox:

It’s not perfect, but it’s good enough.
Printing multiple pages turned out to be trickier. First, to prevent pages from breaking halfway across my labels, I inserted an empty div with the style rule “page-break-after” set to “always”.
Also, I had used the HTML body to set the margins. But the top of “page 2″ doesn’t know anything about the HTML body’s top margin. There is some documentation on “paged media” but it felt like uncharted territory. Rather than fight it, I decided to let the browser — rather than the CSS — set the top margin. I had to convey that in some friendly instructions on my client’s launch page:
Before printing labels, use your browser’s print preview options to set the top print margin to 1/2 inch and all other print margins to 0 (zero).
Try printing a test page on plain paper first. Hold it up to the light behind a sheet of labels to make sure the bar codes line up with the stickers.
It worked great in Firefox and Internet Explorer — good enough for my client.
Once the concept was proven, I built a controller page that lets my client print a test sheet, blocks of real data, individual data points, and even “blank” labels to push the data past previously peeled stickers so that nothing is wasted.
Here’s a one-page example of the HTML and CSS used to create Avery 5160 labels. (HTML corrected thanks to Halty.)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>HTML & CSS Avery Labels (5160) by MM at Boulder Information Services</title>
<link href="labels.css" rel="stylesheet" type="text/css" >
<style>
body {
width: 8.5in;
margin: 0in .1875in;
}
.label{
/* Avery 5160 labels -- CSS and HTML by MM at Boulder Information Services */
width: 2.025in; /* plus .6 inches from padding */
height: .875in; /* plus .125 inches from padding */
padding: .125in .3in 0;
margin-right: .125in; /* the gutter */
float: left;
text-align: center;
overflow: hidden;
outline: 1px dotted; /* outline doesn't occupy space like border does */
}
.page-break {
clear: left;
display:block;
page-break-after:always;
}
</style>
</head>
<body>
<div class="label"><img src="http://boulderinformationservices.files.wordpress.com/2011/08/barcode_sample.png" /><br>Human readable</div>
<div class="label"><img src="http://boulderinformationservices.files.wordpress.com/2011/08/barcode_sample.png" /><br>Human readable</div>
<div class="label"><img src="http://boulderinformationservices.files.wordpress.com/2011/08/barcode_sample.png" /><br>Human readable</div>
<div class="label"><img src="http://boulderinformationservices.files.wordpress.com/2011/08/barcode_sample.png" /><br>Human readable</div>
<div class="label">(Repeat 30 times)</div>
<div class="page-break"></div>
</body>
</html>