Css Secrets - Simple Pie Charts


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>

旋转36度

现在加点动画让它动起来:

<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


本文内容大概就这么多,欢迎交流,欢迎反馈,如有错误,还请纠正,谢谢阅读。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    love2013阅读 2,301评论 0 11
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    wzhiq896阅读 1,730评论 0 2
  • 1.CSS3 边框 border-radius CSS属性用来设置边框圆角。当使用一个半径时确定一个圆形;当使用两...
    garble阅读 629评论 0 0
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,401评论 25 707
  • 我是个怪女孩。 刚出生时,不喝白开水,喝了就吐,逼着我爸半夜三更满大街给我去买奶粉。 不到一岁,便学会了说话,说的...
    牛奶艾特咖啡阅读 267评论 0 0