{"id":273668,"date":"2018-08-13T06:57:13","date_gmt":"2018-08-13T13:57:13","guid":{"rendered":"http:\/\/css-tricks.com\/?p=273668"},"modified":"2018-09-26T07:36:15","modified_gmt":"2018-09-26T14:36:15","slug":"simple-interactive-pie-chart-with-css-variables-and-houdini-magic","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/simple-interactive-pie-chart-with-css-variables-and-houdini-magic\/","title":{"rendered":"Simple Interactive Pie Chart with CSS Variables and Houdini Magic"},"content":{"rendered":"

I got the idea for doing something of the kind when I stumbled across this interactive SVG pie chart<\/a>. While the SVG code is as compact as it gets (a single <circle><\/code> element!), using strokes for creating pie chart slices is problematic as we run into rendering issues<\/a> on Windows for Firefox and Edge. Plus, in 2018, we can accomplish a lot more with a lot less JavaScript!<\/p>\n

I managed to get the following result using a single HTML element for the chart and very little JavaScript. The future should completely eliminate the need for any JavaScript, but more on that later.<\/p>\n

<\/p>\n

\"Animated
The final pie chart result.<\/figcaption><\/figure>\n

Some of you may remember Lea Verou’s Missing Slice<\/a> talk—my solution is based on her technique. This article dissects how it all works, showing what we can do in terms of graceful degradation and other ways this technique can be put to use.<\/p>\n

The HTML<\/h3>\n

We use Pug to generate the HTML from a data<\/code> object that contains unitless percentage values for the past three years:<\/p>\n

- var data = { 2016: 20, 2017: 26, 2018: 29 }<\/code><\/pre>\n

We make all our elements reside in a .wrap<\/code> element. Then, we loop through our data<\/code> object and, for each of its properties, we create a radio input<\/code> with a corresponding label<\/code>. After these, we add a .pie<\/code> element to the mix.<\/p>\n

- var darr = [], val;\r\n\r\n.wrap\r\n  - for(var p in data) {\r\n    - if(!val) val = data[p];\r\n    input(id=`o${p}` name='o' type='radio' checked=val == data[p])\r\n    label(for=`o${p}`) #{p}\r\n    - darr.push(`${data[p]}% for year ${p}`)\r\n  - }\r\n  .pie(aria-label=`Value as pie chart. ${darr.join(', ')}.` \r\n       role='graphics-document group')<\/code><\/pre>\n

The above Pug code compiles to the following HTML:<\/p>\n

<style><div class=\"wrap\">\r\n  <input id=\"o2016\" name=\"o\" type=\"radio\" checked=\"checked\"\/>\r\n  <label for=\"o2016\">2016<\/label>\r\n  <input id=\"o2017\" name=\"o\" type=\"radio\"\/>\r\n  <label for=\"o2017\">2017<\/label>\r\n  <input id=\"o2018\" name=\"o\" type=\"radio\"\/>\r\n  <label for=\"o2018\">2018<\/label>\r\n  <div class=\"pie\" aria-label=\"Value as pie chart. 20% for year 2016, 26% for year 2017, 29% for year 2018.\" role=\"graphics-document group\"><\/div>\r\n<\/div><\/code><\/pre>\n

Note that we also made sure only the first radio input<\/code> is checked.<\/p>\n

Passing custom properties to the CSS<\/h3>\n

I normally don’t like putting styles in HTML but, in this particular case, it’s a very useful way to pass custom property values to the CSS and ensure that we only need to update things in one place if we need to change any of our data points—the Pug code. The CSS remains the same.<\/p>\n

The trick is to set a unitless percentage --p<\/code> on the .pie<\/code> element for every radio input<\/code> that might be checked:<\/p>\n

style\r\n  - for(var p in data) {\r\n    | #o#{p}:checked ~ .pie { --p: #{data[p]} }\r\n  - }<\/code><\/pre>\n

We use this percentage for a conic-gradient()<\/code> on the .pie<\/code> element after making sure neither of its dimensions (including border<\/code> and padding<\/code>) are 0<\/code>:<\/p>\n

$d: 20rem;\r\n\r\n.wrap { width: $d; }\r\n\r\n.pie {\r\n  padding: 50%;\r\n  background: conic-gradient(#ab3e5b calc(var(--p)*1%), #ef746f 0%);\r\n}<\/code><\/pre>\n

Note that this requires native conic-gradient()<\/code> support since the polyfill<\/a> doesn’t work with CSS variables. At the moment, this limits support to Blink browsers with the Experimental Web Platform features<\/strong> flag enabled, though things are bound to get better.<\/p>\n

\"Screenshot
The Experimental Web Platform features<\/strong> flag enabled in Chrome.<\/figcaption><\/figure>\n

Update<\/strong>: Chrome 69+ now supports conic-gradient()<\/code> natively without the flag as well.<\/p>\n

We now have a working skeleton of our demo—picking a different year via the radio buttons results in a different conic-gradient()<\/code>!<\/p>\n

\"Animated
The basic functionality we’ve been after (live demo<\/a>, Blink browsers only).<\/figcaption><\/figure>\n

Displaying the value<\/h3>\n

The next step is to actually display the current value and we do this via a pseudo-element. Unfortunately, number-valued CSS variables cannot be used for the value of the content<\/code> property, so we get around this by using the counter()<\/code> hack.<\/p>\n

.pie:after {\r\n  counter-reset: p var(--p);\r\n  content: counter(p) '%';\r\n}<\/code><\/pre>\n

We’ve also tweaked the color<\/code> and font-size<\/code> properties so that our pseudo-element is a bit more visible:<\/p>\n

\"Screenshot.
Displaying the value on the chart (live demo<\/a>, Blink browsers only).<\/figcaption><\/figure>\n

Smoothing things out<\/h3>\n

We don’t want abrupt changes between values, so we smooth things out with the help of a CSS transition<\/code>. Before we can transition or animate the --p<\/code> variable, we need to register it in JavaScript:<\/p>\n

CSS.registerProperty({\r\n  name: '--p', \r\n  syntax: '<integer>',\r\n  initialValue: 0, \r\n  inherits: true\r\n});<\/code><\/pre>\n

Note that using <number><\/code> instead of <integer><\/code> causes the displayed value to go to 0<\/code> during the transition<\/code> as our counter needs an integer. Thanks to Lea Verou for helping me figure this out!<\/p>\n

Also note that explicitly setting inherits<\/code> is mandatory. This wasn’t the case until recently.<\/p>\n

This is all the JavaScript we need for this demo and, in the future, we shouldn’t even need this much as we’ll be able to register custom properties from the CSS<\/a>.<\/p>\n

With that out of the way, we can add a transition<\/code> on our .pie<\/code> element.<\/p>\n

.pie {\r\n  \/* same styles as before *\/\r\n  transition: --p .5s;\r\n}<\/code><\/pre>\n

And that’s it for the functionality! All done with one element, one custom variable, and a sprinkle of Houdini magic!<\/p>\n

\"Animated
Interactive pie chart (live demo<\/a>, Blink browsers with flag only).<\/figcaption><\/figure>\n

Prettifying touches<\/h3>\n

While our demo is functional, it looks anything but pretty at this point. So, let’s take care of that while we’re at it!<\/p>\n

Making the pie… a pie!<\/h4>\n

Since the presence of :after<\/code> has increased the height<\/code> of its .pie<\/code> parent, we absolutely position it. And since we want our .pie<\/code> element to look more like an actual pie, we make it round with border-radius: 50%<\/code>.<\/p>\n

\"Screenshot.
Rounding up our pie (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

We also want to display the percentage value in the middle of the dark pie slice.<\/p>\n

In order to do this, we first position it dead in the middle of the .pie<\/code> element. By default, the :after<\/code> pseudo-element is displayed after its parent’s content. Since .pie<\/code> has no content in this case, the top-left corner of the :after<\/code> pseudo-element is in the top-left corner of the parent’s content-box<\/code>. Here, the content-box<\/code> is a 0x0<\/code> box in the center of the padding-box<\/code>. Remember that we’ve set the padding<\/code> of .pie<\/code> to 50%<\/code>—a value that’s relative to the wrapper width<\/code> for both the horizontal and the vertical direction!<\/p>\n

This means the top-left corner of :after<\/code> is in the middle of its parent, so a translate(-50%, -50%)<\/code> on it shifts it to the left by half its own width<\/code> and up by half its own height<\/code>, making its own mid-point coincide with that of .pie<\/code>.<\/p>\n

Remember that %<\/code>-valued translations are relative<\/a> to the dimensions of the element they’re applied on<\/em> along the corresponding axis. In other words, a %<\/code>-valued translation along the x<\/var>-axis is relative to the element’s width<\/code>, a %<\/code>-valued translation along the y<\/var>-axis is relative to its height<\/code> and a %<\/code>-valued translation along the z<\/var>-axis is relative to its depth, which is always 0<\/code> because all elements are flat two-dimensional boxes with 0<\/code> depth along the third axis.<\/p>\n

\"Screenshot.
Positioning the value label in the middle of the pie (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

Next, we rotate<\/code> the value such that the positive half of its x<\/var>-axis splits the dark slice into two equal halves and then translate<\/code> it by half a pie radius along this now-rotated x<\/var>-axis.<\/p>\n

See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

What we need to figure out is how much to rotate the :after<\/code> pseudo-element so that its x<\/var>-axis splits the dark slice into two equal halves. Let’s break that down!<\/p>\n

Initially, the x<\/var>-axis is horizontal, pointing towards the right, so in order to have it in the desired direction, we first need to rotate it so that it points up and going along the starting edge of the slice. Then it needs to rotate clockwise by half a slice.<\/p>\n

In order to get the axis to point up, we need to rotate it by -90deg<\/code>. The minus sign is due to the fact that positive values follow a clockwise direction and we’re going the other way.<\/p>\n

See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

Next, we need to rotate it by half a slice.<\/p>\n

See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

But how much is half a slice?<\/p>\n

Well, we already know what percentage of the pie this slice represents: it’s our custom property, --p<\/code>. If we divide that value by 100<\/code> and then multiply it by 360deg<\/code> (or 1turn<\/code>, it doesn’t matter what unit is used), we get the central angle of our dark slice.<\/p>\n

After the -90deg<\/code> rotation, we need to rotate :after<\/code> by half this central angle in the clockwise (positive) direction.<\/p>\n

This means we apply the following transform<\/code> chain:<\/p>\n

translate(-50%, -50%) rotate(calc(.5*var(--p)\/100*1turn - 90deg)) translate(.25*$d);<\/code><\/pre>\n

The last translation is by a quarter of $d<\/code>, which is the wrapper width<\/code> and gives us the .pie<\/code> diameter as well. (Since the content-box<\/code> of .pie<\/code> is a 0x0<\/code> box, it has no border<\/code> and both its left and right padding<\/code> are 50%<\/code> of its wrapper parent width<\/code>.) The .pie<\/code> radius is half its diameter, meaning that half the radius is a quarter of the diameter ($d<\/code>).<\/p>\n

Now the value label is positioned where we want it to be:<\/p>\n

\"Screenshot.
Positioning the value label in the middle of the slice (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

However, there’s still one problem: we don’t want it to be rotated, as that can look really awkward and neck-bending at certain angles. In order to fix this, we revert the rotation at the end. To make things easier for ourselves, we store the rotation angle in a CSS variable that we call --a<\/code>:<\/p>\n

--a: calc(.5*var(--p)\/100*1turn - 90deg);\r\ntransform: \r\n  translate(-50%, -50%) \r\n  rotate(var(--a)) \r\n  translate(.25*$d) \r\n  rotate(calc(-1*var(--a)));<\/code><\/pre>\n

Much better!<\/p>\n

\"Screenshot.
Positioning the value label in the middle of the slice, now horizontal (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

Layout<\/h4>\n

We want to have the whole assembly in the middle of the screen, so we solve this with a neat little grid trick<\/a>:<\/p>\n

body {\r\n  display: grid;\r\n  place-items: center center;\r\n  margin: 0;\r\n  min-height: 100vh\r\n}<\/code><\/pre>\n

Alright, this puts the entire .wrap<\/code> element in the middle:<\/p>\n

\"Screenshot.
Positioning the whole assembly in the middle (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

The next step is to place the pie chart above the radio buttons. We do this with a flexbox layout on the .wrap<\/code> element:<\/p>\n

.wrap {\r\n  display: flex;\r\n  flex-wrap: wrap-reverse;\r\n  justify-content: center;\r\n  width: $d;\r\n}<\/code><\/pre>\n
\"Screenshot.
Placing the pie chart above the radio buttons (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

Styling the radio buttons<\/h4>\n

…or more accurately, we’re styling the radio button labels<\/em> because the first thing that we do is hide the radio inputs:<\/p>\n

[type='radio'] {\r\n  position: absolute;\r\n  left: -100vw;\r\n}<\/code><\/pre>\n
After hiding the radio buttons (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

Since this leaves us with some very ugly labels that are very hard to distinguish from one another, let’s give each one some margin<\/code> and padding<\/code> so they don’t look so crammed together, plus backgrounds so that their clickable areas are clearly highlighted. We can even add box and text shadows for some 3D effects. And, of course, we can create a separate case for when their corresponding inputs are :checked<\/code>.<\/p>\n

$c: #ecf081 #b3cc57;\r\n\r\n[type='radio'] {\r\n   \/* same as before *\/\r\n\r\n  + label {\r\n    margin: 3em .5em .5em;\r\n    padding: .25em .5em;\r\n    border-radius: 5px;\r\n    box-shadow: 1px 1px nth($c, 2);\r\n    background: nth($c, 1);\r\n    font-size: 1.25em;\r\n    text-shadow: 1px 1px #fff;\r\n    cursor: pointer;\r\n  }\r\n\t\r\n  &:checked {\r\n    + label {\r\n      box-shadow: inset -1px -1px nth($c, 1);\r\n      background: nth($c, 2);\r\n      color: #fff;\r\n      text-shadow: 1px 1px #000;\r\n    }\r\n  }\r\n}<\/code><\/pre>\n

We’ve also blown up the font-size<\/code> a bit and set a border-radius<\/code> to smooth out the corners:<\/p>\n

\"Screenshot.
After styling the radio button labels (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

Final prettifying touches<\/h4>\n

Let’s set a background<\/code> on the body<\/code>, tweak the font<\/code> of the whole thing and add a transition<\/code> for the radio labels:<\/p>\n

\"Screenshot.
The final pie chart result (live demo<\/a>, Blink browsers only, transition needs flag).<\/figcaption><\/figure>\n

Graceful degradation<\/h3>\n

While our demo now looks good in Blink browsers, it looks awful in all other browsers… and that’s most browsers!<\/p>\n

First off, let’s put our work inside a @supports<\/code> block that checks for native conic-gradient()<\/code> support so the browsers that support it will render the pie chart. This includes our conic-gradient()<\/code>, the padding<\/code> that gives the pie equal horizontal and vertical dimensions, the border-radius<\/code> that makes the pie circular, and the transform<\/code> chain that positions the value label in the middle of the pie slice.<\/p>\n

.pie {\t\r\n  @supports (background: conic-gradient(tan, red)) {\r\n    padding: 50%;\r\n    border-radius: 50%;\r\n    background: conic-gradient(var(--stop-list));\r\n    --a: calc(.5*var(--p)\/100*1turn - 90deg);\r\n    --pos: rotate(var(--a)) \r\n           translate(#{.25*$d}) \r\n           rotate(calc(-1*var(--a)));\r\n    }\r\n  }\r\n}<\/code><\/pre>\n

Now, let’s construct a bar chart as a fallback for all other browsers using linear-gradient()<\/code>. We want our bar to stretch across the .wrap<\/code> element so that the horizontal padding<\/code> is still 50%<\/code>, but vertically as a narrow bar. We still want the chart to be tall enough to fit the value label. This means we go for a smaller vertical padding<\/code>. We also decrease the border-radius<\/code>, since 50%<\/code> would give us an ellipse and what we need is a rectangle with slightly rounded corners.<\/p>\n

The fallback also replaces conic-gradient()<\/code> with a left-to-right linear-gradient()<\/code>. Since both the linear-gradient()<\/code> creating the fallback bar chart and the conic-gradient()<\/code> creating the pie chart use the same stop list, we can store it in a CSS variable (--stop-list<\/code>) so that we don’t even have it repeated in the compiled CSS.<\/p>\n

Finally, we want the value label in the middle of the bar for the fallback since we don’t have pie slices anymore. This means we store all the post-centering positioning into a CSS variable (--pos<\/code>) whose value is nothing in the no conic-gradient()<\/code> support case and the previous transform<\/code> chain otherwise:<\/p>\n

.pie {\r\n  padding: 1.5em 50%;\r\n  border-radius: 5px;\r\n  --stop-list: #ab3e5b calc(var(--p)*1%), #ef746f 0%;\r\n  background: linear-gradient(90deg, var(--stop-list));\r\n  \/* same as before *\/\r\n\t\r\n  &:after {\r\n    transform: translate(-50%, -50%) var(--pos, #{unquote(' ')});\r\n    \/* same as before *\/\r\n  }\r\n\t\r\n  @supports (background: conic-gradient(tan, red)) {\r\n    padding: 50%;\r\n    border-radius: 50%;\r\n    background: conic-gradient(var(--stop-list));\r\n    --a: calc(.5*var(--p)\/100*1turn - 90deg);\r\n    --pos: rotate(var(--a)) \r\n           translate(#{.25*$d}) \r\n           rotate(calc(-1*var(--a)));\r\n    }\r\n  }\r\n}<\/code><\/pre>\n

We also switch to using a flexbox layout on the body<\/code> (since, as clever as it may be, the grid<\/code> one is messed up in Edge).<\/p>\n

body {\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  \/* same as before *\/\r\n}<\/code><\/pre>\n

This all gives us a bar chart fallback for the browsers not supporting conic-gradient()<\/code>.<\/p>\n

\"Screenshot.
The fallback for the final pie chart result (live demo<\/a>).<\/figcaption><\/figure>\n

Responsifying it all<\/h3>\n

The one problem we still have is that, if the viewport is narrower than the pie diameter, things don’t look so good anymore.<\/p>\n

CSS variables and media queries to the rescue!<\/p>\n

We set the diameter to a CSS variable (--d<\/code>) that gets used to set the pie dimensions and the position of the value label in the middle of our slice.<\/p>\n

.wrap {\r\n  --d: #{$d};\r\n  width: var(--d);\r\n  \/* same as before *\/\r\n\r\n  @media (max-width: $d) { --d: 95vw }\r\n}<\/code><\/pre>\n

Below certain viewport widths, we also decrease the font-size<\/code>, the margin<\/code> for our <label><\/code> elements, and we don’t position the value label in the middle of the dark pie slice anymore, but rather in the middle of the pie itself:<\/p>\n

.wrap {\r\n \/* same as before *\/\r\n\r\n@media (max-width: 265px) { font-size: .75em; }\r\n}\r\n\r\n[type='radio'] {\r\n   \/* same as before *\/\r\n\r\n  + label {\r\n    \/* same as before *\/\r\n    \r\n    @media (max-width: 195px) { margin-top: .25em; }\r\n  }\r\n}\r\n\r\n.pie{\r\n   \/* same as before *\/\r\n\r\n  @media (max-width: 160px) { --pos: #{unquote(' ')} } \r\n}<\/code><\/pre>\n

This gives us our final result: a responsive pie chart in browsers supporting conic-gradient()<\/code> natively. And, even though that’s sadly just Blink browsers for now, we have a solid fallback that renders a responsive bar chart for all other browsers. We also animate between values—this is even more limited at this point, to just Blink browsers with the Experimental Web Platform features flag enabled.<\/p>\n

See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n

Bonus: radial progress!<\/h3>\n

We can also apply this concept to build a radial progress indicator like the one below (inspired by this Pen<\/a>):<\/p>\n

\"Animated
The radial progress and its fallback.<\/figcaption><\/figure>\n

The technique is pretty much the same, except we leave the value label dead in the middle and set the conic-gradient()<\/code> on the :before<\/code> pseudo-element. This is because we use a mask<\/code> to get rid of everything, except for a thin outer ring and, if we were to set the conic-gradient()<\/code> and the mask<\/code> on the element itself, then the mask<\/code> would also hide the value label inside and we want that visible.<\/p>\n

On clicking the <button><\/code>, a new value for our unitless percentage (--p<\/code>) is randomly generated and we transition smoothly between values. Setting a fixed transition-duration<\/code> would create a really slow transition<\/code> between two close values (e.g. 47%<\/code> to 49%<\/code>) and a really fast transition<\/code> when moving between values with a larger gap in between (e.g. 3%<\/code> to 98%<\/code>). We get around this by making the transition-duration<\/code> depend on the absolute value of the difference between the previous value of --p<\/code> and its newly generated value.<\/p>\n

[id='out'] { \/* radial progress element *\/\r\n  transition: --p calc(var(--dp, 1)*1s) ease-out;\r\n}<\/code><\/pre>\n
const _GEN = document.getElementById('gen'), \r\n             _OUT = document.getElementById('out');\r\n\r\n_GEN.addEventListener('click', e => {\r\n  let old_perc = ~~_OUT.style.getPropertyValue('--p'), \r\n      new_perc = Math.round(100*Math.random());\r\n\t\r\n  _OUT.style.setProperty('--p', new_perc);\r\n  _OUT.style.setProperty('--dp', .01*Math.abs(old_perc - new_perc));\r\n  _OUT.setAttribute('aria-label', `Graphical representation of generated percentage: ${new_perc}% of 100%.`)\r\n}, false);<\/code><\/pre>\n

This gives us a nice animated radial progress indicator for browsers supporting all the new and shiny features. We have a linear fallback for browsers not supporting conic-gradient()<\/code> natively and no transition<\/code> in the case of no Houdini support:<\/p>\n

See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"

I got the idea for doing something of the kind when I stumbled across this interactive SVG pie chart. While […]<\/p>\n","protected":false},"author":225572,"featured_media":274939,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Ana Tudor shows us how to make an animated pie chart with one element, one variable, and a little Houdini...then makes it more awesome.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_share_on_mastodon":"0","_share_on_mastodon_status":"%title% %permalink%"},"categories":[4],"tags":[881,1370,839,1036,652],"class_list":["post-273668","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-articles","tag-charts","tag-conic-gradients","tag-css-variables","tag-custom-properties","tag-houdini"],"acf":{"show_toc":"No"},"share_on_mastodon":{"url":"","error":""},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/08\/animated-pie-chart-values.gif?fit=800%2C400&ssl=1","jetpack-related-posts":[{"id":208855,"url":"https:\/\/css-tricks.com\/how-to-make-charts-with-svg\/","url_meta":{"origin":273668,"position":0},"title":"How to Make Charts with SVG","author":"Robin Rendle","date":"October 5, 2015","format":false,"excerpt":"In my first post about making charts, I looked at methods that solely relied on CSS. I argued that this wasn\u2019t the best option in most cases; there are just too many tricky design and development hurdles to overcome. Generally speaking, it\u2019s best to make charts with a combination of\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/css-audit-specificity-graph.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/css-audit-specificity-graph.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/css-audit-specificity-graph.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/css-audit-specificity-graph.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/css-audit-specificity-graph.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":284853,"url":"https:\/\/css-tricks.com\/css-houdini-could-change-the-way-we-write-and-manage-css\/","url_meta":{"origin":273668,"position":1},"title":"CSS Houdini Could Change the Way We Write and Manage CSS","author":"Yangguang LI","date":"March 28, 2019","format":false,"excerpt":"CSS Houdini may be the most exciting development in CSS. Houdini is comprised of a number of separate APIs, each shipping to browsers separately, and some that have already shipped (here's the browser support). The Paint API is one of them. I\u2019m very excited about it and recently started to\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/06\/magic-stage.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/06\/magic-stage.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/06\/magic-stage.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/06\/magic-stage.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/06\/magic-stage.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":206670,"url":"https:\/\/css-tricks.com\/making-charts-with-css\/","url_meta":{"origin":273668,"position":2},"title":"Making Charts with CSS","author":"Robin Rendle","date":"August 18, 2015","format":false,"excerpt":"There are many ways to make visual representations of data: bar charts, line graphs, scatter diagrams, sparklines... not to mention the many ways in which you can implement them on the web. In this post I'll be looking at plain CSS methods for styling data. But before we take a\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/07\/bar-chart.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/07\/bar-chart.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/07\/bar-chart.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/07\/bar-chart.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2022\/07\/bar-chart.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":262731,"url":"https:\/\/css-tricks.com\/simple-patterns-for-separation\/","url_meta":{"origin":273668,"position":3},"title":"Simple Patterns for Separation (Better Than Color Alone)","author":"Chris Coyier","date":"November 18, 2017","format":false,"excerpt":"Color is pretty good for separating things. That's what your basic pie chart is, isn't it? You tell the slices apart by color. With enough color contrast, you might be OK, but you might be even better off (particularly where accessibility is concerned) using patterns, or a combination. Patrick Dillon\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":276023,"url":"https:\/\/css-tricks.com\/interactive-introduction-to-css-houdini\/","url_meta":{"origin":273668,"position":4},"title":"Interactive Introduction to CSS Houdini","author":"Chris Coyier","date":"September 10, 2018","format":false,"excerpt":"This is a great explanatory microsite by Sam Richard. CSS Houdini will let authors tap in to the actual CSS engine, finally allowing us to extend CSS, and do so at CSS speeds. Much like Service Workers are a low-level JavaScript API for the browser's cache, Houdini introduces low-level JavaScript\u2026","rel":"","context":"In "Links"","block_context":{"text":"Links","link":"https:\/\/css-tricks.com\/category\/links\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/09\/houdini.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/09\/houdini.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/09\/houdini.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/09\/houdini.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/09\/houdini.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":196752,"url":"https:\/\/css-tricks.com\/using-angularjs-for-data-visualisations\/","url_meta":{"origin":273668,"position":5},"title":"Using AngularJS for Data Visualisations","author":"Nick Moreton","date":"February 25, 2015","format":false,"excerpt":"The following is a guest post by Nick Moreton. I gotta say I find this idea rather intriguing. I know that I love working in HTML, SVG, and CSS, so when Nick shares that we can use that for structure and use the data directly to style a chart, that\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/273668","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/225572"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=273668"}],"version-history":[{"count":69,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/273668\/revisions"}],"predecessor-version":[{"id":276994,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/273668\/revisions\/276994"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/274939"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=273668"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=273668"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=273668"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}