巧用 CSS Grid Layout 实现百分比堆叠柱状图

1,005 阅读4分钟

前言

从事数据可视化、统计报表的同学必定对此图感到非常熟悉,根据 AntV 的官方说法,它学名叫做 百分比堆叠柱状图

柱子的各个层代表的是该类别数据占该分组总体数据的百分比,好处是能一目了然看到单个项目与整体之间的关系。

在最近的需求中,PM 要求以百分比堆叠柱状图来展示预算关系,前端组内过整体的技术方案评审时,提出了 3 个方案:

  1. 使用 AntV 的库
  2. 使用 Canvas 实现
  3. 使用 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

假设我们的原始数据如下表所示:

labelvaluecolor
A100pink
B200lightblue
C300gold

分别计算得出 A 占比为 16.666666666666664,B 占比为 33.33333333333333,C 占比为 50,将它们加上 fr 的单位赋值给 grid-template-columns 即可实现百分比堆叠柱状图。

.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 代码如下所示:

<div class="diagram">
  <div></div>
  <div></div>
  <div></div>
</div>
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 来帮你更好的了解和快速构建网格布局。

第一个是 cssgrid-generator.netlify.app/,它能根据你的输入实时呈现网格,最后生成代码供你开箱即用。

<div class="parent"></div>
.parent {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, 1fr);
  grid-column-gap: 0px;
  grid-row-gap: 0px;
}

第二个是 cssgr.id/,它不仅提供现代网页常用的排版布局,如 Gallery、HEADER & FOOTER、GENERIC WEBSITE,并且能自定义网格的数量(items),列数(columns),间隔(gap),同样也能生成代码。

<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>
.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;
}

Reference