用CSS和SVG制作饼图

507 查看

在涉及到CSS技术时,没有人会比Lea Verou更执着、但是又足够聪明,努力去找寻问题的各种解决方案。最近,Lea自己撰写、设计和出版了一本书——CSS Secrets,这本书非常有趣,包括一些CSS小技巧以及解决常见问题的技术。如果你觉得自己的CSS技术还不错,看看这本书,你会吃惊的。在这篇文章中,我们发布了书里的一些片段,这也被发表在Lea最近在SmashingConf New York的演讲内容中——用CSS设计简单的饼图。注意,因为浏览器的支持有限,有些demo可能不能正常运行。——编辑

饼图,即使是最简单的只有两种颜色的形式,用Web技术创建也并不简单,尽管都是一些常见的信息内容,从简单的统计到进度条指标还有计时器。通常是使用外部图像编辑器来分别为多个值创建多个图像来实现,或是使用大型的JavaScript框架来设计更复杂的图表。

尽管这个东西并不像它曾经看起来那么难以实现,但是也没有什么直接并且简单的方法。但是,现在已经有很多更好、更易于维护的方式来实现它。

基于变换的解决方案


这个方案从HTML的角度来说是最好的:它只需要一个元素,其它的都可以用伪元素、变换和CSS渐变完成。我们从下面这个简单的元素开始:

现在,假设我们希望显示一个 20% 比例的饼图。灵活性的问题我们后面再解决。我们先给元素添加样式,让它变成一个圆,也就是我们的背景:

图1:第一步是先画一个圆(或者可以说是显示0%比例的饼图)

 

我们的饼图是绿色(特指 yellowgreen )和棕色( #655 )显示的百分比。可能会在比例部分尝试使用 transform 中的 skew ,但是经过几次试验之后表明,这是一个非常混乱的方案。因此,我们用这两种颜色为这个饼图的左右部分分别着色,然后对于我们想要的百分比,使用旋转的伪元素来实现。

我们使用一个简单的线性渐变,给右半部分着棕色:

图2:用一个简单的线性渐变给右半圆着棕色

如图2所示,这样就完成了。现在,我们可以继续为伪元素添加样式,让它成为一个蒙版:

图3:虚线内的内容表示伪元素将作为蒙版的区域

你可以在图3中看到我们的伪元素当前定位相对于我们的pie元素。目前,它还没有添加样式,也没有覆盖任何东西,只是一个透明的矩形。在开始添加样式之前,我们先来分析一下:

  • 因为我们希望它覆盖圆的棕色部分,我们需要给它应用一个绿色的背景,使用 background-color: inherit 来避免重复定义,因为我们本来就希望它和父元素的背景颜色保持一致。
  • 我们希望它绕着圆的中心点旋转,中心点在伪元素的左边,所以我们需要给它的 transform-origin ,应用一个 0 50% ,或者是直接一个 left 。
  • 我们不想要它是一个矩形,因为它会超过饼图的边缘,所以我们需要给 .pie 应用 overflow: hidden ,或者是一个恰当的 border-radius 让它成为一个半圆。

综上所述,伪元素的CSS样式如下:

图4:添加样式之后的伪元素(这里用虚线表示)

注意:不要使用 background: inherit; ,要用 background-color: inherit ;,否则父元素背景图像上的渐变也会被继承

我们的饼图目前如图4所示。现在开始有趣起来了!我们可以开始旋转伪元素,给它应用一个 rotate() 变换。要显示 20% 的比例,我们可以给它一个 72deg ( 0.2 x 360 = 72 ),或 解决方案。最近,Lea自己撰写、设计和出版了一本书——CSS Secrets,这本书非常有趣,包括一些CSS小技巧以及解决常见问题的技术。如果你觉得自己的CSS技术还不错,看看这本书,你会吃惊的。在这篇文章中,我们发布了书里的一些片段,这也被发表在Lea最近在SmashingConf New York的演讲内容中——用CSS设计简单的饼图。注意,因为浏览器的支持有限,有些demo可能不能正常运行。——编辑

饼图,即使是最简单的只有两种颜色的形式,用Web技术创建也并不简单,尽管都是一些常见的信息内容,从简单的统计到进度条指标还有计时器。通常是使用外部图像编辑器来分别为多个值创建多个图像来实现,或是使用大型的JavaScript框架来设计更复杂的图表。

尽管这个东西并不像它曾经看起来那么难以实现,但是也没有什么直接并且简单的方法。但是,现在已经有很多更好、更易于维护的方式来实现它。

基于变换的解决方案


这个方案从HTML的角度来说是最好的:它只需要一个元素,其它的都可以用伪元素、变换和CSS渐变完成。我们从下面这个简单的元素开始:

现在,假设我们希望显示一个 20% 比例的饼图。灵活性的问题我们后面再解决。我们先给元素添加样式,让它变成一个圆,也就是我们的背景:

图1:第一步是先画一个圆(或者可以说是显示0%比例的饼图)

 

我们的饼图是绿色(特指 yellowgreen )和棕色( #655 )显示的百分比。可能会在比例部分尝试使用 transform 中的 skew ,但是经过几次试验之后表明,这是一个非常混乱的方案。因此,我们用这两种颜色为这个饼图的左右部分分别着色,然后对于我们想要的百分比,使用旋转的伪元素来实现。

我们使用一个简单的线性渐变,给右半部分着棕色:

图2:用一个简单的线性渐变给右半圆着棕色

如图2所示,这样就完成了。现在,我们可以继续为伪元素添加样式,让它成为一个蒙版:

图3:虚线内的内容表示伪元素将作为蒙版的区域

你可以在图3中看到我们的伪元素当前定位相对于我们的pie元素。目前,它还没有添加样式,也没有覆盖任何东西,只是一个透明的矩形。在开始添加样式之前,我们先来分析一下:

  • 因为我们希望它覆盖圆的棕色部分,我们需要给它应用一个绿色的背景,使用 background-color: inherit 来避免重复定义,因为我们本来就希望它和父元素的背景颜色保持一致。
  • 我们希望它绕着圆的中心点旋转,中心点在伪元素的左边,所以我们需要给它的 transform-origin ,应用一个 0 50% ,或者是直接一个 left 。
  • 我们不想要它是一个矩形,因为它会超过饼图的边缘,所以我们需要给 .pie 应用 overflow: hidden ,或者是一个恰当的 border-radius 让它成为一个半圆。

综上所述,伪元素的CSS样式如下:

图4:添加样式之后的伪元素(这里用虚线表示)

注意:不要使用 background: inherit; ,要用 background-color: inherit ;,否则父元素背景图像上的渐变也会被继承

我们的饼图目前如图4所示。现在开始有趣起来了!我们可以开始旋转伪元素,给它应用一个 rotate() 变换。要显示 20% 的比例,我们可以给它一个 72deg ( 0.2 x 360 = 72 ),或

 

我们的饼图是绿色(特指