Skip to content

Instantly share code, notes, and snippets.

@shawnbot
Last active September 23, 2018 11:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawnbot/8ea469aa6ccd94770fcef04e75cb0886 to your computer and use it in GitHub Desktop.
Save shawnbot/8ea469aa6ccd94770fcef04e75cb0886 to your computer and use it in GitHub Desktop.
CSS bar charts in 2018

This is an example of what you should be able to do once the major browsers implement some seriously cool features in the CSS3 draft spec as of April, 2016:

  1. CSS variables, using the --name: value assignment and var(--name) accessor syntax. (Already implemented by Chrome, Firefox, and Webkit!)
  2. CSS3 calc(), which gives us calculated values between different units, e.g. subtracting a value in px or em from a percentage. (Partially implemented in Chrome, Firefox, and Safari.)
  3. CSS3 attr(), which grants the function the ability to parse values in specific units in the form attr(attr-name units). (Not yet implemented in any major browser.)

Together, these features would enable us to use HTML element attribute values as the basis for calculated values in CSS on a per-element basis, and define (then change) which property the values are applied to. This would open up possibilities for more data-driven design entirely in CSS, without the need for JavaScript.

Note: I've used the x- prefix to denote HTML custom elements, which are a great way to simplify your markup, encapsulate your CSS, and extend the DOM element API via JavaScript. You could just as easily HTML5 elements or classes, though.

/* The bar chart container establishes a common min and max */
x-bar-chart {
--min: 0;
--max: 100;
display: block;
}
x-bar {
/* Each bar has its own value */
--value: 0;
/* And its size is a variable so that we can use it any property,
or even set directly. This should be a number between 0 and 1. */
--size: calc((var(--value) - var(--min)) / (var(--max) - var(--min))));
display: block;
margin-bottom: .5em;
}
/* If you render the bar itself as generated content,
then the content (e.g. text labels) can flow independently
of the element's own bounding box, precluding the need for
overflow: visible */
x-bar::after {
background: slateblue;
content: "";
display: block;
/* by default, a bar has a percentage width based on its size */
height: 1em;
width: calc(100% * var(--size));
}
/* bars can get their value from the value attribute */
x-bar[value] {
/* this syntax parses the value attribute as a number,
rather than using a unit length */
--value: attr(value number);
}
/* charts *and* bars could establish their own min and max */
x-bar-chart[min],
x-bar[min] {
--min: attr(min number);
}
x-bar-chart[max],
x-bar[max] {
--max: attr(max number);
}
@media screen and (min-width: 640px) {
/* then, if we want to get *really* fancy, we can
make the chart go vertical on wider screens */
x-bar-chart {
display: flex;
}
x-bar {
align-self: bottom;
flex: 1;
position: relative;
margin-bottom: 0;
}
/* spacing between bars */
x-bar + x-bar {
margin-left: .5em;
}
x-bar::after {
position: absolute;
bottom: 0;
height: calc(100% * var(--size));
width: 100%;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="bar-chart.css">
</head>
<body>
<x-bar-chart min="0" max="200">
<x-bar value="200">A: $100</x-bar>
<x-bar value="150">B: $150</x-bar>
<x-bar value="25">C: $25</x-bar>
</x-bar-chart>
</body>
</html>
@shawnbot
Copy link
Author

Note: this is a simplification that doesn't cover cases in which --min is less than zero.

@shawnbot
Copy link
Author

One other awesome thing about this approach, though, is that you could cover negative cases with CSS selectors:

x-bar-chart[min^="-"] x-bar {
  /* left offset bars with a positive value */
}

x-bar[min^="-"] {
  /* recalculate width and right offset */
  background: orange;
}

@yairEO
Copy link

yairEO commented Sep 23, 2018

would be nice to also have a Yaxis with ticks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment