{"id":257419,"date":"2017-08-11T10:54:45","date_gmt":"2017-08-11T17:54:45","guid":{"rendered":"http:\/\/css-tricks.com\/?p=257419"},"modified":"2017-08-11T11:14:07","modified_gmt":"2017-08-11T18:14:07","slug":"css-charts-grid-custom-properties","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/css-charts-grid-custom-properties\/","title":{"rendered":"More CSS Charts, with Grid & Custom Properties"},"content":{"rendered":"

I loved Robin’s recent post, experimenting with CSS Grid for bar-charts<\/a>. I’ve actually been using a similar approach on a client project, building a day-planner with CSS Grid. It’s a different use-case, but the same basic technique: using grid layouts to visualize data.<\/p>\n

(I recommend reading Robin’s article first, since I’m building on top of his chart.)<\/p>\n

Robin’s approach relies on a large Sass loop to generate 100 potential class-names, even though less than 12 are used in the final chart. In production we’ll want something more direct and performant, with better semantics, so I turned to definition lists and CSS Variables<\/a> (aka Custom Properties) to build my charts. <\/p>\n

<\/p>\n

Here’s the final result:<\/p>\n

See the Pen Bar chart in CSS grid + variables<\/a> by Miriam Suzanne (@mirisuzanne<\/a>) on CodePen<\/a>.<\/p>\n

Let’s dig into it!<\/p>\n

Markup First<\/h3>\n

Robin was proposing a conceptual experiment, so he left out many real-life data and accessibility concerns. Since I’m aiming for (fictional) production code, I want to make sure it will be semantic and accessible. I borrowed the year-axis idea from a comment on Robin’s charts, and moved everything into a definition list. Each year is associated with a corresponding percentage in the list:<\/p>\n

<dl class=\"chart\">\r\n  <dt class=\"date\">2000<\/dt>\r\n  <dd class=\"bar\">45%<\/dd>\r\n\r\n  <dt class=\"date\">2001<\/dt> \r\n  <dd class=\"bar\">100%<\/dd>\r\n  \r\n  <!-- etc\u2026 -->\r\n<\/dl><\/code><\/pre>\n

There are likely other ways to mark this up accessibly, but a dl<\/code> seemed clean and clear to me \u2013 with all the data and associated pairs available as structured text. By default, this displays year\/percentage pairs in a readable format. Now we have to make it beautiful.<\/p>\n

Grid Setup<\/h3>\n

I started from Robin’s grid, but my markup requires an extra row for the .date<\/code> elements. I add that to the end of my grid-template-rows<\/code>, and place my date\/bar elements appropriately:<\/p>\n

.chart {\r\n  display: grid;\r\n  grid-auto-columns: 1fr;\r\n  grid-template-rows: repeat(100, 1fr) 1.4rem;\r\n  grid-column-gap: 5px;\r\n}\r\n\r\n.date {\r\n  \/* fill the bottom row *\/\r\n  grid-row-start: -2;\r\n}\r\n\r\n.bar {\r\n  \/* end before the bottom row *\/\r\n  grid-row-end: -2;\r\n}<\/code><\/pre>\n

Normally, I would use auto<\/code> for that final row, but I needed an explicit height to make the background-grid work properly. Not not worth the trade-off, probably, but I was having fun.<\/p>\n

Passing Data to CSS<\/h3>\n

At this point, CSS has no access to the relevant numbers for styling a chart. We have no hooks for setting individual bars to different heights. Robin’s solution involves individual class-names for every bar-value, with a Sass to loop to create custom classes for each value. That works, but we end up with a long list of classes we may never use. Is there a way to pass data into CSS more directly?<\/p>\n

The most direct approach might be an inline style:<\/p>\n

<dd class=\"bar\" style=\"grid-row-start: 56\">45%<\/dd><\/code><\/pre>\n

The start position is the full number of grid lines (one more than the number of rows, or 101 in this case), minus the total value of the given bar: 101 - 45 = 56<\/code>. That works fine, but now our markup and CSS are tightly coupled. With CSS Variables, we can pass in raw data, and let the CSS decide how it is used:<\/p>\n

<dd class=\"bar\" style=\"--start: 56\">45%<\/dd><\/code><\/pre>\n

In the CSS we can wire that up to grid-row-start<\/code>:<\/p>\n

.bar {\r\n  grid-row-start: var(--start);\r\n}<\/code><\/pre>\n

We’ve replaced the class-name loop, and bloated 100-class output, with a single line of dynamic CSS. Variables also remove the danger normally associated with CSS-in-HTML. While an inline property like grid-row-start<\/code> will be nearly impossible to override from a CSS file, the inline variable can simply be ignored by CSS. There are no specificity\/cascade issues to worry about.<\/p>\n

Data-Driven Backgrounds<\/h3>\n

As a bonus, we can do more with the data than simply provide a grid-position \u2013 reusing it to style a fallback option, or even adjust the bar colors based on that same data:<\/p>\n

.bar {\r\n  background-image: linear-gradient(to right, green, yellow, orange, red);\r\n  background-size: 1600% 100%;\r\n  \r\n  \/* turn the start value into a percentage for position on the gradient *\/\r\n  background-position: calc(var(--start) * 1%) 0;\r\n}<\/code><\/pre>\n

I started with a horizontal background gradient from green to yellow, orange, and then red. Then I used background-size<\/code> to make the gradient much wider than the bar \u2013 at least 200% per color (800%). Larger gradient-widths will make the fade less visible, so I went with 1600% to keep it subtle. Finally, using calc()<\/code> to convert our start position (1-100) into a percentage, I can adjust the background position left-or-right based on the value \u2013 showing a different color depending on the percentage.<\/p>\n

The background grid is also generated using variables and background-gradients. Sadly, subpixel rounding makes it a bit unreliable, but you can play with the --line-every<\/code> value to change the level of detail. Take a look around, and see what other improvements you can make!<\/p>\n

Adding Scale [without Firefox]<\/h3>\n

Right now, we’re passing in a start position rather than a pure value (“56” for “45%”). That start position is based on an assumption that the overall scale is 100%<\/code>. In order to make this a more flexible tool, I thought it would be fun to contain all the math, including the scale, inside CSS. Here’s what it would look like:<\/p>\n

<dl class=\"chart\" style=\"--scale: 100\">\r\n  <dt class=\"date\">2000<\/dt>\r\n  <dd class=\"bar\" style=\"--value: 45\">45%<\/dd>\r\n\r\n  <dt class=\"date\">2001<\/dt> \r\n  <dd class=\"bar\" style=\"--value: 100\">100%<\/dd>\r\n  \r\n  <!-- etc\u2026 -->\r\n<\/dl><\/code><\/pre>\n

Then we can calculate the --start<\/code> value in CSS, before applying it.<\/p>\n

.bar {\r\n  --start: calc(var(--scale) + 1 - var(--value));\r\n  grid-row-start: var(--start);\r\n}<\/code><\/pre>\n

With both the overall scale and individual values in CSS, we can manipulate either one individually. Change the scale to 200%<\/code>, and watch the chart update accordingly:<\/p>\n

See the Pen Bar Chart with Sale – no firefox<\/a> by Miriam Suzanne (@mirisuzanne<\/a>) on CodePen<\/a>.<\/p>\n

Both Chrome and Safari handle it beautifully, but Firefox seems unhappy about calc<\/code> values in grid-positioning. I imagine they’ll get it fixed eventually. For now, we’ll just have to leave some calculations out of our CSS. <\/p>\n

Sad, but we’ll get used to it. 😉<\/p>\n

There is much more we could do, providing fallbacks for older browsers \u2013\u00a0but I do think this is a viable option with potential to be accessible, semantic, performant, and beautiful. Thanks for starting that conversation, Robin!<\/p>\n","protected":false},"excerpt":{"rendered":"

I loved Robin’s recent post, experimenting with CSS Grid for bar-charts. I’ve actually been using a similar approach on a client project, building a day-planner with CSS Grid. It’s a different use-case, but the same basic technique: using grid layouts to visualize data. (I recommend reading Robin’s article first, since I’m building on top of […]<\/p>\n","protected":false},"author":245622,"featured_media":257618,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_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,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2017\/08\/grid.png?fit=1126%2C556&ssl=1","jetpack-related-posts":[{"id":342448,"url":"https:\/\/css-tricks.com\/how-to-create-css-charts-with-interesting-shapes-glyphs-and-emoji\/","url_meta":{"origin":257419,"position":0},"title":"How to Create CSS Charts With Interesting Shapes, Glyphs and Emoji","date":"June 21, 2021","format":false,"excerpt":"Let\u2019s forego the usual circles and bars we typically see used in charts for more eccentric shapes. With online presentations more and more common today, a quick way to spruce up your web slides and make them stand out is to give the charts a shapely makeover \ud83e\ude84 I\u2019ll show\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/06\/chart-shapes.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":341572,"url":"https:\/\/css-tricks.com\/are-custom-properties-a-menu-of-what-will-change\/","url_meta":{"origin":257419,"position":1},"title":"Are Custom Properties a “Menu of What Will Change”?","date":"June 2, 2021","format":false,"excerpt":"PPK laid out an interesting situation in \"Two options for using custom properties\" where he and Stefan Judis had two different approaches for doing the same thing with custom properties. In one approach, hover and focus styles for a link are handled with two different custom properties, one for each\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/06\/custom-property-componentcolor.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":305295,"url":"https:\/\/css-tricks.com\/4-css-grid-properties-and-one-value-for-most-of-your-layout-needs\/","url_meta":{"origin":257419,"position":2},"title":"4 CSS Grid Properties (and One Value) for Most of Your Layout Needs","date":"March 30, 2020","format":false,"excerpt":"CSS Grid provides us with a powerful layout system for websites. The CSS-Tricks guide gives you a comprehensive overview of Grid\u2019s properties with layout examples. What we\u2019re going to do here is a reverse approach to show you the smallest possible set of grid properties you need to know to\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/css-grid-properties.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":326391,"url":"https:\/\/css-tricks.com\/how-to-make-an-area-chart-with-css\/","url_meta":{"origin":257419,"position":3},"title":"How to Make an Area Chart With CSS","date":"December 2, 2020","format":false,"excerpt":"You might know a few ways to create charts with pure CSS. Some of them are covered here on CSS-Tricks, and many others can be found on CodePen, but I haven\u2019t seen many examples of \u201carea charts\u201d (imagine a line chart with the bottom area filled in), particularly any in\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/11\/s_3B96DE4366834488A29D0D1C3D10A09AAB92882E189DDEECE4637A2D54E9C4CA_1605267833349_area-chart.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":334958,"url":"https:\/\/css-tricks.com\/how-to-map-mouse-position-in-css\/","url_meta":{"origin":257419,"position":4},"title":"How to Map Mouse Position in CSS","date":"March 1, 2021","format":false,"excerpt":"Let\u2019s look at how to get the user\u2019s mouse position and map it into CSS custom properties: --positionX and --positionY. We could do this in JavaScript. If we did, we could do things like make make an element draggable or move a background. But actually, we can still do similar\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/02\/css-mouse-cursor-mapping.gif?fit=900%2C450&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":257047,"url":"https:\/\/css-tricks.com\/making-a-bar-chart-with-css-grid\/","url_meta":{"origin":257419,"position":5},"title":"Making A Bar Chart with CSS Grid","date":"August 2, 2017","format":false,"excerpt":"Editors note: this post is just an experiment to play with new CSS properties and so the code below shouldn\u2019t be used without serious improvements to accessibility. I have a peculiar obsession with charts and for some reason, I want to figure out all the ways to make them with\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"featured_media_src_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2017\/08\/grid.png?fit=1024%2C506&ssl=1","_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/257419"}],"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\/245622"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=257419"}],"version-history":[{"count":11,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/257419\/revisions"}],"predecessor-version":[{"id":257622,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/257419\/revisions\/257622"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/257618"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=257419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=257419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=257419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}