巧用 CSS Grid Layout 实现百分比堆叠柱状图
December 10, 2021
前言
从事数据可视化、统计报表的同学必定对此图感到非常熟悉,根据 AntV 的官方说法,它学名叫做 百分比堆叠柱状图。
柱子的各个层代表的是该类别数据占该分组总体数据的百分比,好处是能一目了然看到单个项目与整体之间的关系。
在最近的需求中,PM 要求以百分比堆叠柱状图来展示预算关系,前端组内过整体的技术方案评审时,提出了 3 个方案:
- 使用 AntV 的库
- 使用 Canvas 实现
- 使用 CSS Grid Layout 实现
方案一、二都十分复杂,拖累排期,最终我选择了方案三,又好又快。
关于 CSS Grid Layout
CSS Grid Layout,又称网格布局、栅格布局,是我认为现代 Web 开发最高效的布局方式,它创造性的改动就是将流式布局、Flex 布局等传统一维布局方式上升到二维,这波属于降维打击。
在网页排版中,我们往往只能沿 X 轴或 Y 轴单个方向排布元素,CSS Grid Layout 允许我们同时沿着 X、Y 轴排布元素。
早在 2017 年,彼时的我是个前端小白,竞赛老师要求我们的电脑上必须安装 Chrome,当时我不以为然,因为我从高中开始,便一直使用 QQ 浏览器,也没觉得哪里比 Chrome 差了。
直到我在 CodePen 搜到了一个关于 CSS Grid Layout 的 Demo,结果在 Chrome 上能完美运行,QQ 浏览器上样式表现混乱,年轻的我还不知道兼容性这个概念,QQ 浏览器在我心目中的形象瞬间垮塌,而 Chrome 跃居高位。
Chrome 57 于 2017.3.9 发布,成为市面上第一个正式支持 CSS Grid Layout 的官方浏览器,到 2021 年底,CSS Grid Layout 用将近五年的时间变成了各大主流浏览器厂商 100% 支持的 CSS 属性。
这无疑,也侧面说明前端领域虽日新月异,但一门新特性从被提案到全面落地,不仅需要前沿开发者们忍受兼容性带来的阵痛,还需要浏览器巨头们、W3C 的不懈努力,最终促成如今 CSS Grid Layout 的 “大好河山”。
写一个最简单的 Demo
假设我们的原始数据如下表所示:
label | value | color |
---|---|---|
A | 100 | pink |
B | 200 | lightblue |
C | 300 | gold |
分别计算得出 A 占比为 16.666666666666664
,B 占比为 33.33333333333333
,C 占比为 50
,将它们加上 fr
的单位赋值给 grid-template-columns
即可实现百分比堆叠柱状图。
css
.diagram {display: grid;grid-template-columns: 16.666666666666664fr 33.33333333333333fr 50fr;}
css
.diagram {display: grid;grid-template-columns: 16.666666666666664fr 33.33333333333333fr 50fr;}
在 CSS Grid Layout 中,存在新单位 fr
,它是一种占比单位,1fr
代表占据可使用空间的一部分,与 flex: 1
相似。
Fr is a fractional unit and 1fr is for 1 part of the available space.
正所谓青出于蓝胜于蓝,CSS Grid Layout 可以在声明了 display: grid
的父元素直接设置子元素的占比情况,而 Flex 需要分别对子元素进行设置。
具体的介绍可以看这篇文章:CSS Grid Layout: The Fr Unit,相关的 W3C 规范可以戳:Flexible Lengths: the fr unit
完整的 HTML 和 CSS 代码如下所示:
html
<div class="diagram"><div></div><div></div><div></div></div>
html
<div class="diagram"><div></div><div></div><div></div></div>
css
body {margin: 0;}.diagram {display: grid;grid-template-columns: 16.666666666666664fr 33.33333333333333fr 50fr;grid-template-rows: 1fr;height: 3vh;width: 100vw;}.diagram div:nth-child(1) {background: pink;}.diagram div:nth-child(2) {background: lightblue;}.diagram div:nth-child(3) {background: gold;}
css
body {margin: 0;}.diagram {display: grid;grid-template-columns: 16.666666666666664fr 33.33333333333333fr 50fr;grid-template-rows: 1fr;height: 3vh;width: 100vw;}.diagram div:nth-child(1) {background: pink;}.diagram div:nth-child(2) {background: lightblue;}.diagram div:nth-child(3) {background: gold;}
彩蛋
恭喜,如果你看到这,你将收获两个关于 CSS Grid Layout 的优质网站。
它们能作为 playground 来帮你更好的了解和快速构建网格布局。
第一个是 https://cssgrid-generator.netlify.app/,它能根据你的输入实时呈现网格,最后生成代码供你开箱即用。
html
<div class="parent"></div>
html
<div class="parent"></div>
css
.parent {display: grid;grid-template-columns: repeat(5, 1fr);grid-template-rows: repeat(5, 1fr);grid-column-gap: 0px;grid-row-gap: 0px;}
css
.parent {display: grid;grid-template-columns: repeat(5, 1fr);grid-template-rows: repeat(5, 1fr);grid-column-gap: 0px;grid-row-gap: 0px;}
第二个是 https://cssgr.id/,它不仅提供现代网页常用的排版布局,如 Gallery、HEADER & FOOTER、GENERIC WEBSITE,并且能自定义网格的数量(items),列数(columns),间隔(gap),同样也能生成代码。
html
<div class="grid"><div class="span-col-3 span-row-2">Item 1</div><div>Item 2</div><div class="span-row-2">Item 3</div><div class="span-row-3">Item 4</div><div>Item 5</div><div>Item 6</div><div>Item 7</div><div class="span-col-3 span-row-2">Item 8</div><div class="span-col-2 span-row-2">Item 9</div><div>Item 10</div><div>Item 11</div><div>Item 12</div><div>Item 13</div><div>Item 14</div></div>
html
<div class="grid"><div class="span-col-3 span-row-2">Item 1</div><div>Item 2</div><div class="span-row-2">Item 3</div><div class="span-row-3">Item 4</div><div>Item 5</div><div>Item 6</div><div>Item 7</div><div class="span-col-3 span-row-2">Item 8</div><div class="span-col-2 span-row-2">Item 9</div><div>Item 10</div><div>Item 11</div><div>Item 12</div><div>Item 13</div><div>Item 14</div></div>
css
.grid {display: grid;grid-template-columns: repeat(6, 1fr);grid-gap: 10px;}.span-col-3 {grid-column: span 3 / auto;}.span-col-2 {grid-column: span 2 / auto;}.span-row-2 {grid-row: span 2 / auto;}.span-row-3 {grid-row: span 3 / auto;}
css
.grid {display: grid;grid-template-columns: repeat(6, 1fr);grid-gap: 10px;}.span-col-3 {grid-column: span 3 / auto;}.span-col-2 {grid-column: span 2 / auto;}.span-row-2 {grid-row: span 2 / auto;}.span-row-3 {grid-row: span 3 / auto;}