我是一名刚开始接触前端(甚至刚开始接触编程)的菜鸟,以前是做平面设计的,说得有问题的话请多包涵。
这篇文章记录一下我发现的一个小问题。
这几天在做一个饼图的内容,想要实现的效果大概就是一个这样的环形:
选择的方案是用SVG绘制圆形(circle),然后通过stroke-dasharray来控制显示部分。之前考虑过计算锚点位置直接用path来绘制,但是有点复杂,就选择了这种方式。
先简单介绍下stroke-dasharray画饼图的方法。
简单来说,stroke-dasharray是用来将svg图形的描边以虚线呈现的属性,其实线和空格的长度值是会头尾相接自动循环的,而第一个值是第一段实线的长度,第二个值是第一段空格的长度。那么,只要先计算出周长,然后将周长按比例分为两个长度,分别设置为stroke-dasharray的第一个值和第二个值,这样整个周长上虚线会被恰好循环1次,即可呈现出饼图的效果。不光环状的,扇形的其实也可以做到,可以通过stroke-width来控制。
如果是多段饼,用stroke-dashoffset或者transform:rotate()控制有点太复杂了。我的思路是直接在同一位置叠多个circle,最底层是一个整环,往上逐级递减,效果是一样的:
调整各层半径和stroke-width,还可以做出叠层的效果(类似行星环),这里不细说了。
理论存在,接下来就是实践了。
于是我尝试了比较简单的写法,也就是在CSS的:root里定义了一系列的相关变量和运算法则(下面大概示意一下我的做法,不是原代码)。
:root{
--inputnum:1;
--inputtotal:1;
--array1:calc(3.1415926 * 2 * var(--inputnum) / var(--inputtotal));
--array2:calc(3.1415926 * 2 - var(array2));
--array:var(--array1),var(--array2);
}
其中“2”是圆的直径。
接下来就是用js控制其中的元变量。我是自己定义了一个函数来方便地变更CSS的变量。
function dd(key,string){document.documentElement.style.setProperty(key,string);}
然后直接dd("--inputnum",xx)就行了。
最后<circle stroke-dasharray="var(--array)"/>即可。
哦对,默认情况下绘制应该是从3点方向开始的,如果想要实线部分从12点钟方向开始绘制,需要transform:rotate(-90deg)来逆时针旋转90度。也可以用stroke-dashoffset,但我觉得这个逻辑上简单太多了。
这套方法在Chrome和Safari上完美运行,所以我一开始没有急着做兼容测试就写别的内容去了。结果当晚测试的时候发现Firefox无论是PC端还是移动端都无法正常显示,整段都是实线。
然后抓狂的一晚上开始了。
一开始我以为是stroke-width的问题,因为看到有说法说Firefox在绘制的时候会除掉stroke-width,但我将SVG的viewbox缩小,减小半径,将stroke-width改为1之后,仍然是其他浏览器都没问题,唯独Firefox不行。
然后我尝试将stroke-dasharray写到style里而不是作为circle的一个属性,依然无效。
在搜遍整个互联网都没有找到满意的答案后,我突然想到,会不会是CSS变量的问题?
于是我检查了Firefox调试界面的CSS变量,发现确实读不出来值。当时我考虑是不是Firefox不支持calc()对CSS变量的运算?但这显然不对,因为我前面用到颜色的计算,也是采用的类似方式。
--r:0;
--g:100;
--b:170;
--c0:rgb(var(--r),var(--g),var(--b));
--c1:rgb(calc(var(--r) * 0.6),calc(var(--g) * 0.6),calc(var(--b) * 0.6));
类似这样的运算在任何主流浏览器上都没有兼容性问题。
同样,这也不太可能是多个变量合并为一个变量的问题,比如上面这段代码中的--c0,跟--array的格式几乎一模一样!
--array:var(--array1),var(--array2);
等下,真的是这样吗?
最后我发现,Firefox还真就是对--array这样的格式不支持。而且并不是不支持公式的嵌套(二次运算)而是不支持这个特定格式,因为我将svg部分改为:
<circle stroke-dasharray="var(--array1),var(--array2)"/>
在Firefox下同样是无效的(而其他浏览器都没有问题)。
总结起来就是,Firefox可能无法处理没有外括号并且用逗号分隔的两个CSS变量的组合。当然我并没有在其他属性上测试,所以也可能只是对stroke-dasharray属性存在这种情况。有时间我会测试一下其他类似属性的结果。
最后我只好改为用DOM方式来控制stroke-dasharry属性,这个我就不细说了~