Thursday, February 5, 2026

CSS Bar Charts Utilizing Fashionable Features


New CSS options can typically make it simpler and extra environment friendly to code designs we already knew find out how to create. This effectivity may stem from diminished code or hacks, or improved readability because of the new options.

In that spirit, let’s revamp what’s underneath the hood of a bar chart.

We start by laying out a grid.

.chart {
  show: grid;
  grid-template-rows: repeat(100, 1fr);
  /* and many others. */
}

The chart metric relies on share, as in “some quantity out of 100.” Let’s say we’re working with a grid containing 100 rows. That should stress check it, proper?

Subsequent, we add the bars to the grid with the grid-column and grid-row properties:

.chart-bar {
  grid-column:  sibling-index();
  grid-row: span attr(data-value quantity);
  /* and many others. */
}

Proper off the bat, I need to be aware a few issues. First is that sibling-index() perform. It’s model new and has incomplete browser assist as of this writing (come on, Firefox!), although it’s presently supported within the newest Chrome and Safari (however not on iOS apparently). Second is that attr() perform. We’ve had it for some time, nevertheless it was just lately upgraded and now accepts data-attributes. So when we've got a kind of in our markup — like data-value="32" — that’s one thing the perform can learn.

With these in place, that’s actually all we have to create a fairly darn good bar chart in vanilla CSS! The next demo has fallbacks in place so to nonetheless see the ultimate end in case your browser hasn’t adopted these new options:

Sure, that was simple to do, nevertheless it’s finest to know precisely why it really works. So, let’s break that down.

Mechanically Establishing Grid Columns

Declaring the sibling-index() perform on the grid-column property explicitly locations the record objects in consecutive columns. I say “specific” as a result of we’re telling the grid precisely the place to position every merchandise by its data-value attribute within the markup. It goes first

  • in first column, second
  • in second column, and so forth.

    That’s the facility of sibling-index() — the grid intelligently generates the order for us with out having to do it manually by way of CSS variables.

    /* First bar: sibling-index() = 1 */
    grid-column: sibling-index();
    
    /* ...leads to: */
    grid-column: 1;
    grid-column-start: 1; grid-column-end: auto;
    
    /* Second bar: sibling-index() = 2 */
    grid-column: sibling-index();
    
    /* ...leads to: */
    grid-column: 2;
    grid-column-start: 2; grid-column-end: auto;
    
    /* and many others. */

    Mechanically Establishing Grid Rows

    It’s just about the identical factor! However on this case, every bar occupies a sure variety of rows based mostly on the proportion it represents. The grid will get these values from the data-value attribute within the markup, successfully telling the grid how tall every bar within the chart ought to be.

    /* First bar: data-value="32" */
    grid-row: span attr(data-value quantity);
    
    /* ...leads to: */
    grid-row: span 32
    
    /* Second bar: data-value="46" */
    grid-row: span attr(data-value quantity);
    
    /* ...leads to: */
    grid-row: span 46

    The attr() perform, when supplied with a information sort parameter (the parameter worth quantity in our case), casts the worth retrieved by attr() into that particular sort. In our instance, the attr() perform returns the worth of data-value as a sort, which is then used to find out the variety of rows to span for every bar.

    Let’s Make Completely different Charts!

    Since we've got the nuts and bolts down on this method, I figured I’d push issues a bit and exhibit how we are able to apply the identical strategies for every kind of CSS-only charts.

    For instance, we are able to use grid-row values to regulate the vertical route of the bars:

    Or we are able to skip bars altogether and use markers as a substitute:

    We will additionally swap the columns and rows for horizontal bar charts:

    Wrapping up

    Fairly thrilling, proper? Simply have a look at all of the methods we used to tug these items off earlier than the times of sibling-index() and an upgraded attr():

  • Related Articles

    Latest Articles