The problem
饼图,随处可见,但是真正去实现,还是要下点功夫的。
比如我们要创建一个进度指示器,或者计时显示器,通常涉及使用外部图像编辑器为饼图的多个值创建图像,或使用js脚本设计更为复杂的图表。
现在有其他更好的方式去实现。
transform solution
首先,我们来画一个圆:
<pre>
.pie {
width: 100 px;
height: 100 px;
border-radius: 50 %;
background: yellowgreen;
}
</pre>
既然是饼图,比如双色饼图,就需要另一种颜色来显示进度,再画一个半圆:
可以用渐变来做:
background-image: linear-gradient(to right, transparent 50%, #655 0);
我们还需要创建一个遮罩层:虚线部分。
<pre>
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: inherit;
transform-origin: left;
}
</pre>
创建好了,不过有几点要注意的地方:
因为我们想让这个层盖住棕色的部分,所以我们可以给它加个绿色的背景,也可以用
<pre>
background-color: inherit;
</pre>来避免重复声明。旋转的中心点是圆心,我们可以这样声明:
<pre>
transform-origin: left;
//或者
transform-origin: 0 50%;
</pre>我们创建遮罩层的目的是盖住棕色的那部分,它需要是个半圆,但是我们现在写的是个矩形,所以为了避免侧漏,我们用border-radius 让它也变成半圆:
<pre>
border-radius: 0 100% 100% 0 / 50%;
</pre>
遮罩层也就就绪了,现在给一个旋转角度看看:
<pre>
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background: #655;
transform-origin: left;
transform: rotate(.1turn);
}
</pre>
现在加点动画让它动起来:
<pre>
@keyframes spin {
to {
transform: rotate(.5turn)
}
}
@keyframes bg {
50% {
background: #655
}
}
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0/50%;
background-color: inherit;
transform-origin: left;
animation: spin 3s linear infinite,bg 6s step-end infinite
}
</pre>
点击查看:
http://dabblet.com/gist/722909b9808c14eb7300
现在第一步好了,更进一步,想想,如果我们在html中定义百分数,就能显示对应的比例,那简直是不能更好了。
就像这样定义:
<pre>
<div class="pie">20%</div>
<div class="pie">60%</div>
</pre>
一个显示20%,另一个显示60% .
首先,我们试试能不能用行内样式,然后用一段脚本去解析。
回头想一想:我们是要控制伪元素的旋转度数来显示百分比的,那问题来了(挖掘机技术哪家强。。XD),我们没法直接给伪元素添加行内样式...怎么办呢?
The solution comes from one of the most unlikely places.
我们刚才定义了动画,现在它该停停了。
我们将使用animation的delay 来实现,与正常的使用不同的是,我们将使用负数 让它停在我们定义的位置。很迷惑是不是,animation-delay 的参数为负数,这是不符合规范的,但是在某些情况下,它是很有用的,看描述:
“A negative delay is valid. Similar to a delay of 0s, it means that the ani-mation executes immediately, but is automatically progressed by the ab-solute value of the delay, as if the animation had started the specifiedtime in the past, and so it appears to start partway through its activeduration.”
— CSS Animations Level 1 (w3.org/TR/css-animations/#animation-delay)
因为动画被定义为pause 的时候,只会显示第一帧。
这时候,显示在饼图上的百分比就是我们定义的延迟时间占整个动画时间的百分比。
比如,我们的动画持续时间是6s, 延迟时间是-1.2s, 就会显示 20% ;
为了看起来方便,我们定义整个动画的持续时间为100s。
因为动画是静止的,所以设置多大的延迟是不会有其他影响的。
例子走起:
<pre>
<div class="pie" style="animation-delay: -20s"></div>
<div class="pie" style="animation-delay: -60s"></div>
</pre>
CSS 规则:
<pre>
@keyframes spin {
to {
transform: rotate(.5turn);
}
}
@keyframes bg {
50% {
background: #655;
}
}
.pie::before {
/* [Rest of styling stays the same] */
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}
</pre>
<pre>
$$('.pie').forEach(function(pie) {
var p = pie.textContent;
pie.style.animationDelay = '-' + parseFloat(p) + 's';
});
</pre>
我们现在不想看到这个百分比,怎么办呢?
<pre>
color: transparent;
</pre>
这样字体就看不到了,但是仍然是可以选中和打印的。
另外,我们可以让这个百分比居中,避免它被选中时,出现在别的地方。
几点注意的地方:
- 为了实现垂直居中,我们可以:
<pre>
height:100px;
line-height:100px;
</pre>
但是这样的代码是重复的,只写line-height 就好。
Convert height to line-height (or add a line-height equal to the height, but that’s pointless code duplication, because line- height would set the computed height to that as well ).
- 给伪元素 绝对定位,避免字飞出去。
- text-align:center; 实现水平居中。
最后的代码是这样的:
<pre>
.pie {
opacity: 1;
width: 100px;
height: 100px;
border-radius: 50%;
background-color: yellowgreen;
background-image: linear-gradient(to right ,transparent 50% , #655 0);
}
@keyframes spin {
to {
transform: rotate(.5turn);
}
}
@keyframes bg {
50% {
background: #655;
}
}
.pie::before {
/* [Rest of styling stays the same] */
animation: spin 50s linear infinite,
bg 100s step-end infinite;
animation-play-state: paused;
animation-delay: inherit;
}
</pre>
在线查看:http://scaukk.github.io/css/static_pie_chart.html
当然,还可以用svg 实现,篇幅有限,这里就不说了。
题外话:
这是张鑫旭 之前做的 摊鸡蛋饼 动画 XD
http://www.zhangxinxu.com/wordpress/2014/04/css3-pie-loading-waiting-animation/
既然 饼图我都写好了,干脆写点动画,也摊个鸡蛋饼。
原理差不多,有兴趣的可以看看。
访问地址:
http://scaukk.github.io/css/pie.html
本文内容大概就这么多,欢迎交流,欢迎反馈,如有错误,还请纠正,谢谢阅读。