Web DevelopmentHTML and CSS Barcodes

Sure, barcodes may seem a little retro these days, but they're still ubiquitous. One of the places you may wish to create barcodes is on the web. There are various ways to approach this - special barcode fonts, spans for each line, server generated images, etc. Although many solutions are available, I thought I'd add mine into the mix.

This approach focuses on keeping the HTML simple, we end up with an element for each number in the barcode and just a few extra elements for structure - simple enough to write by hand, if you so desire. The bars are displayed using CSS linear gradients, we can add support for older browsers using background images if required. The end result looks something like this

This is a UPC-A barcode, consisting of 12 digits separated into two groups of 6. The HTML we use to represent this is

<span class="barcode upc-a">
    <i class="bcs"></i><!--
    --><span class="bcl"><!--
    --><b class="bc0"></b><!--
    --><b class="bc3"></b><!--
    --><b class="bc6"></b><!--
    --><b class="bc0"></b><!--
    --><b class="bc0"></b><!--
    --><b class="bc0"></b><!--
    --></span><!--
    --><i class="bcm"></i><!--
    --><span class="bcr"><!--
    --><b class="bc2"></b><!--
    --><b class="bc9"></b><!--
    --><b class="bc1"></b><!--
    --><b class="bc4"></b><!--
    --><b class="bc5"></b><!--
    --><b class="bc2"></b><!--
    --></span><!--
    --><i class="bce"></i>
</span>

First note the comments, these are just there to ensure there is no white space between the elements without having to write everything on one line. So let's forget about these and concentrate on the rest of the HTML.

At the outer level whe have a span with class name barcode, this element wraps up the entire barcode. As we will see below we have styled the barcode with relative sizes so that changing the font-size on this outer level element changes the entire barcode size to match.

The first child of the barcode element is for the barcode's start pattern, hence the class name bcs. Note I've used an i element because it's short and it's distinct from the b elements used for the number bars, but you could just use a span if you prefer. Similarly, there are also elements with class names bcm and bce for the middle and end patterns of the barcode respectively.

Next are the elements for the first 6 digits, grouped in a span with class bcl. this wrapping element allows us to distinguish our styles for the left digits from the right digits (grouped in a span with class bcr), this is important because in UPC barcodes the same number is represented differently when it appears on the right hand side to when it is on the left - that's how your barcode scanner knows if the barcode is upside down!

Each digit in the barcode is represented by a b element, again because it's short and the "b" makes you think of bar - the bold styling doesn't worry me, but you can use a span if you prefer. The class name for each b determines the digit: bc0 for 0, bc1 for 1 etc. "Where are the actual digits?" I hear you cry. Well, they're actually in the stylesheet, injected using the rather useful :after pseudo class

.bc0:after { content: "0"; }
.bc1:after { content: "1"; }
.bc2:after { content: "2"; }
/*etc.*/

Because you can't style elements based on their text content this technique allows to avoid writing duplicate information in the HTML.

Now, how do we get the bars? Well we just use CSS linear gradients. You may normally use linear gradients for smooth transitions from one colour to another, but they can equally be used for sharp colour transitions, a technique that allows you to do clever things like create the Facebook loading animation in pure CSS. For instance, to vertically divide your element one third black, then one third white, and the final third black again you can use the following CSS

background-image: linear-gradient(90deg, black 33%, white 33%, white 67%, black 67%);

Interestingly, we don't need to repeat the percentages, we can set the colour stop to 0 and it will just follow on with this colour from the same position as the previous colour stop. Thus we get the same effect using the much simpler rule

background-image: linear-gradient(90deg, black 33%, white 0, white 67%, black 0);

So, let's look at an example of one of the digits, and where better to start than zero, and let's start on the left group of the barcode. The zero digit, like all the others, has a width of 7 in units of the thinnest bar in the barcode. It turns out to be convenient to take this thinnest bar width as 0.1em, which gives us 0.7em per digit, which is just about right for spacing between the numbers, and also means are barcode will scale nicely with font size.

.bc0 {
    width: 0.7em;
}

This 7 wide digit is divided into bars in the pattern 0001101 where here 0 is white and 1 is black, i.e. it's a white bar 3 units wide, followed by a black bar 2 units wide, then a white bar 1 unit wide, and finally a black bar 1 unit wide. Unfortunately sevenths don't make for nice percentages, but even so, we can create this pattern using CSS linear gradients as follows

.bcl > .bc0 {
    background-image: linear-gradient(90deg, transparent 42.86%, black 0, 
                                             black 71.43%, transparent 0, 
                                             transparent 85.71%, black 0);
}

All the other digits can be created similarly, and likewise for the digits in the right hand group of the barcode where the patterns are inverted. We also use a similar styling for the start, middle and end patterns of the barcode, which have widths 0.3em, 0.5em and 0.3em respectively.

So that's pretty much it, there's obviously more styling required to make everything hang together in the right place, but I won't bore you with all that. So here it is, assuming your browser supports the relevant CSS, a live example

If you want to see the details all code is on github. There you'll also find a JavaScript helper function for easily creating the correct HTML structure for a given UPC-A barcode.