I recently published a new open source project, Flexbox Bar Graphs, and wanted to share a simple breakdown of how it was built. It isn’t anything mind-blowing, but I like the idea of placing bar graphs in a web page with zero Javascript.
So in the end, this is what our bar graphs will look like on desktop:
And this is how it will look on smaller devices:
Let’s get into the details!
The HTML
The main “secret” of this project is that our graphs are constructed out of HTML tables. Now before you freak out - this is perfectly fine and works in our favor quite well.
- If the user has JS disabled –> they will still see our graphs
- If the user has CSS disabled –> they will see a standard data table set
All bases are covered!
<!-- Using a basic table with our custom data-id --><tabledata-id="flexbox-bar-graph"><caption>Web Performance Results</caption><thead><tr><th>Test Performed</th><th>Before</th><th>After</th><th>Difference</th></tr></thead><tbody><tr><th>Initial Load Time</th><td><!--
WTF are these CSS variables?
See the CSS section below
--><spanstyle="--data-set:4.7/5;"></span><p>4.7</p></td><td><spanstyle="--data-set:2.7/5;"></span><p>2.7</p></td><td><spanstyle="--data-set:2/5;"></span><p>2</p></td></tr></tbody></table>
Nothing crazy is happening here - just your standard HTML table structure. The one main thing to notice is the --data-set
CSS variable placed inline on each data point. This will be important for our CSS to configure the individual bar graphs properly.
The CSS
This might look overwhelming if I just dumped the whole CSS file in one big code block, so instead I’m going to break them down into two parts:
- Baseline styling (mobile)
- Desktop styling
Baseline
Here we target just our table elements with the data-id
of flexbox-bar-graph
. This allows us to avoid worrying about adding classes or IDs and also avoids conflicts with other non-graph styled tables in our projects.
The base :root
element holds all of our bar graph colors. Change these as you see fit!
/* Bar Graph color variables */:root{--bar-color-1:#357EC7;--bar-color-2:#E42217;--bar-color-3:#4CC417;--bar-color-4:#7D0541;--bar-color-5:#FFD801;}[data-id="flexbox-bar-graph"]{border-collapse:collapse;margin:4rem06rem;width:100%;}[data-id="flexbox-bar-graph"]caption{text-align:left;}[data-id="flexbox-bar-graph"]theadth{text-align:right;}[data-id="flexbox-bar-graph"]theadth:nth-child(1),[data-id="flexbox-bar-graph"]tbodyth{text-align:left;}[data-id="flexbox-bar-graph"]tbodyth{font-weight:normal;font-style:italic;}[data-id="flexbox-bar-graph"]tbodytd{text-align:right;}[data-id="flexbox-bar-graph"]tbodytdp{margin:0;}
Desktop
Now we set your “visual” bar graphs to show at a set width (in this example it is 1000px and above). That way the “default” styling can target the mobile device screen sizes.
- The
thead tr th:nth-child(x):before
elements create the square “legends” beside each individual data point heading - The
tbody tr td:nth-of-type(x) span
elements are the bars themselves
@media(min-width:1000px){[data-id="flexbox-bar-graph"]{background:transparent;display:block;min-height:400px;padding:0;position:relative;width:100%;}[data-id="flexbox-bar-graph"]caption{display:block;font-size:2rem;text-align:center;width:100%;}[data-id="flexbox-bar-graph"]thead{display:block;margin:2rem03rem;width:100%;}[data-id="flexbox-bar-graph"]theadtr{border-bottom:1pxsolidlightgrey;display:flex;justify-content:center;padding-bottom:1rem;}[data-id="flexbox-bar-graph"]theadtrth{display:inline-block;margin:0;padding:0;position:relative;text-align:right;}[data-id="flexbox-bar-graph"]theadtrth:before{content:'';display:inline-block;height:10px;margin:00.5rem02rem;position:relative;width:10px;}[data-id="flexbox-bar-graph"]theadtrth:nth-child(1),[data-id="flexbox-bar-graph"]theadtrth:nth-child(1):before{display:none;}[data-id="flexbox-bar-graph"]theadtrth:nth-child(2):before{background:var(--bar-color-1);}[data-id="flexbox-bar-graph"]theadtrth:nth-child(3):before{background:var(--bar-color-2);}[data-id="flexbox-bar-graph"]theadtrth:nth-child(4):before{background:var(--bar-color-3);}[data-id="flexbox-bar-graph"]theadtrth:nth-child(5):before{background:var(--bar-color-4);}[data-id="flexbox-bar-graph"]theadtrth:nth-child(6):before{background:var(--bar-color-5);}[data-id="flexbox-bar-graph"]tbody{display:flex;justify-content:space-between;min-height:300px;width:100%;}[data-id="flexbox-bar-graph"]tbodytr{display:flex;flex-direction:column-reverse;flex-wrap:wrap;justify-content:flex-end;padding:050px;position:relative;width:100%;}[data-id="flexbox-bar-graph"]tbodytrth{font-size:90%;position:absolute;text-align:center;top:100%;width:calc(100%-100px);}[data-id="flexbox-bar-graph"]tbodytrtd{align-items:center;display:flex;flex-direction:column;height:95%;justify-content:flex-end;}[data-id="flexbox-bar-graph"]tbodytrtdspan{display:block;height:calc(var(--data-set)*100%);width:20px;}[data-id="flexbox-bar-graph"]tbodytrtd:nth-of-type(1)span{background:var(--bar-color-1);}[data-id="flexbox-bar-graph"]tbodytrtd:nth-of-type(2)span{background:var(--bar-color-2);}[data-id="flexbox-bar-graph"]tbodytrtd:nth-of-type(3)span{background:var(--bar-color-3);}[data-id="flexbox-bar-graph"]tbodytrtd:nth-of-type(4)span{background:var(--bar-color-4);}[data-id="flexbox-bar-graph"]tbodytrtd:nth-of-type(5)span{background:var(--bar-color-5);}[data-id="flexbox-bar-graph"]tbodytrtdp{font-size:90%;margin:0;text-align:center;}}
Bonus Styling
In the Flexbox Bar Graph repo, I’ve also included the ability to display these bar graphs horizontally, like so:
The change in CSS is actually quite simple to pull this off - you just need to include the data-layout
attribute on the table itself.
[data-layout="horizontal"]tbody{min-height:auto;}[data-layout="horizontal"]tbodytr{flex-direction:column;padding:040px;}[data-layout="horizontal"]tbodytrth{width:calc(100%-80px);}[data-layout="horizontal"]tbodytrth{text-align:left;top:calc(100%+20px);}[data-layout="horizontal"]tbodytrtd{flex-direction:row;height:auto;justify-content:start;margin:10px0;}[data-layout="horizontal"]tbodytrtdspan{height:20px;width:calc(var(--data-set)*100%);}[data-layout="horizontal"]tbodytrtdp{margin-left:10px;}
That’s All Folks!
That just about sums things up. Feel free to check out the Github repo itself, open any issues you find or fork it for your own!