To design the stats feature of Backbone, our Ruby on Rails CMS, we needed to show a stacked bar graph of page views vs unique visitors. I looked around for a sample of how others did stacked bar graphs and came up empty handed. There are plenty of CSS bar graph interpretations, but none of them did stacked bar graphs. So I’ve done it here. Based off Alen Grakalic’s Pure CSS Data Chart.

The Markup

The first thing I do anytime I start HTML/CSS work is code the HTML. It’s a personal preference to make sure it’s all going to look good for screen readers and be as semantic as possible, and since it’s my article we’re going to do the HTML first.

[code lang="html"]<br />
&lt;dl id=&quot;csschart&quot;&gt;<br />
&lt;dt&gt;Mon&lt;/dt&gt;<br />
&lt;dd&gt;36&lt;/dd&gt;<br />
&lt;dd&gt;30&lt;/dd&gt;<br />
&lt;/dl&gt;<br />
[/code]

Like Alen Grakalic’s implementation, I used a definition list. I found it to be the most semantic way of presenting data like this. To explain, each day of the week is in a <dt> tag and the data for that day is in a <dd> tag. There are two <dd> tags for each day, one for our page views and one for our unique visitors.

[code lang="html"]<br />
&lt;dt&gt;Mon&lt;/dt&gt;<br />
&lt;dd class=&quot;p36&quot;&gt;&lt;span&gt;&lt;b&gt;36&lt;/b&gt;&lt;/span&gt;&lt;/dd&gt;<br />
&lt;dd class=&quot;sub p30&quot; &gt;&lt;span&gt;&lt;b&gt;30&lt;/b&gt;&lt;/span&gt;&lt;/dd&gt;<br />
&lt;/dl&gt;<br />
[/code]

Each <dd> is given a class that corresponds to the percentage of that bar. p100 is 100% the height of the graph and p0 is 0% the height of the graph. Making 100 classes is a pain and a lot of CSS but it makes it so easy when you’re turning these graphs out dynamically.

The other class to which we’ve added some of the <dd> tags is “sub”. This denotes the stacked bars in the graph that will be put on top of the other <dd>.

Finally, we wrap our data in <b> and <span> tags so we have enough to work with when we’re styling it.

Styling the Graph.

[code lang="css"]<br />
dl#csschart, dl#csschart dt, dl#csschart dd{<br />
margin:0;<br />
padding:0;<br />
}<br />
dl#csschart{<br />
background:url(../images/bg_chart.gif) no-repeat 0 0;<br />
width:454px;<br />
height:360px;<br />
padding-left:11px;<br />
}<br />
dl#csschart dt{<br />
display:none;<br />
}<br />
dl#csschart dd{<br />
position:relative;<br />
float:left;<br />
display:inline;<br />
width:33px;<br />
height:330px;<br />
margin-top:22px;<br />
}<br />
dl#csschart span{<br />
position:absolute;<br />
display:block;<br />
width:33px;<br />
bottom:0;<br />
left:0;<br />
z-index:1;<br />
color:#555;<br />
text-decoration:none;<br />
}<br />
dl#csschart span b{<br />
display:block;<br />
font-weight:bold;<br />
font-style:normal;<br />
float:left;<br />
line-height:200%;<br />
color:#fff;<br />
position:absolute;<br />
top:5px;<br />
left:3px;<br />
text-align:center;<br />
width:23px;<br />
}</p>
<p>/* Styling the Bars. */</p>
<p>dl#csschart span{<br />
height:50%;<br />
background:url(../images/bar.png) repeat-y;<br />
}<br />
dl#csschart .sub{<br />
margin-left:-33px;</p>
<p>}<br />
dl#csschart .sub span{<br />
background:url(../images/subBar.png) repeat-y;<br />
}</p>
<p>dl#csschart .p0 span{height:0%}<br />
dl#csschart .p1 span{height:1%}<br />
dl#csschart .p2 span{height:2%}<br />
dl#csschart .p3 span{height:3%}<br />
dl#csschart .p4 span{height:4%}<br />
dl#csschart .p5 span{height:5%}</p>
<p>/*This continues until 100%*/</p>
<p>[/code]
The first thing we do is reset all the margins and padding to make it look the same on all browsers. Then we define the width and height of our chart in dl#csschart. We’re using a background image to help with the tick marks on the axes and for some background gridlines. One important thing to note is the padding-left. This moves the first bar over past the tick marks on the left of the background image.

Next, we hide the dt tags. There is really no good way to make them do what we want. Position the dd tags to float left and use margins to push them to the correct place in our background image. Now, just to be clear, the dd tags are not our bars, they are simply containers for our bars. They are all 100% of the height of our graph. We use the span tags inside the dd tags to fill in our bars. Since they’re positioned absolute inside our positioned dd tags we can use bottom:0; to place them on the x-axis and have them grow in height from there. We use the b tag to display the actual data value inside the bar.

At the bottom we define the background image for the bars in dl#csschart span (you can easily just make it a background color instead), then we position our .sub bars overtop by giving them a margin-left of -33px (the exact width of the bars).

Finally, we make our 101 classes for each percentage point from 0% to 100% to give our bars their height.

I’ve made a diagram to explain what each tag is doing.

Add the Axes.

Ok now you’ll notice we don’t have labels on our axes. So we use some simple unordered lists. One before the cssChart:
[code lang="html"]<br />
&lt;ul class=&quot;yAxis&quot;&gt;<br />
&lt;li&gt;100&lt;/li&gt;<br />
&lt;li&gt;90&lt;/li&gt;<br />
&lt;li&gt;80&lt;/li&gt;<br />
&lt;li&gt;70&lt;/li&gt;<br />
&lt;li&gt;60&lt;/li&gt;<br />
&lt;li&gt;50&lt;/li&gt;<br />
&lt;li&gt;40&lt;/li&gt;<br />
&lt;li&gt;30&lt;/li&gt;<br />
&lt;li&gt;20&lt;/li&gt;<br />
&lt;li&gt;10&lt;/li&gt;<br />
&lt;/ul&gt;</p>
<p>[/code]
and one after the cssChart:
[code lang="html"]<br />
&lt;ul class=&quot;xAxis&quot;&gt;<br />
&lt;li&gt;Mon&lt;/li&gt;<br />
&lt;li&gt;Tue&lt;/li&gt;<br />
&lt;li&gt;Wed&lt;/li&gt;<br />
&lt;li&gt;Thu&lt;/li&gt;<br />
&lt;li&gt;Fri&lt;/li&gt;<br />
&lt;li&gt;Sat&lt;/li&gt;<br />
&lt;li&gt;Sun&lt;/li&gt;<br />
&lt;/ul&gt;</p>
<p>[/code]

Styling the Axes.

[code lang="css"]<br />
ul.xAxis{<br />
margin:0 0 0 27px;<br />
padding:0;<br />
float:left;<br />
clear:left;<br />
display:inline;<br />
width:454px;<br />
}<br />
ul.yAxis{<br />
margin:14px 0 0 0;<br />
padding:0;<br />
display:inline;<br />
float:left;<br />
}<br />
ul.xAxis li{<br />
float:left;<br />
list-style:none;<br />
width:33px;<br />
text-align:center;<br />
}<br />
ul.yAxis li{<br />
list-style:none;<br />
height:33px;<br />
text-align:right;<br />
float:left;<br />
clear:left;<br />
}</p>
<p>[/code]

Styling the axes is really just floating the the y-axis left and using some margins to push it in place. Then you can use some margins to push the li tags to line up with the tick marks of your background image.