H5Skills
H5Skills copied to clipboard
如何抗rotate剧齿
有时候,我们需要transform的rotate方法来使元素倾斜,但是角度倾斜会给元素带来意料之外的效果--锯齿。
如何在IOS下对抗rotate造成的锯齿
在IOS中,搞锯齿的方法很简单,只要开启元素的3d属性既开启了GPU加速后,能有效的实现抗锯齿。如果在开启了GPU后,ios页面仍出现锯齿现象,使用安卓的最终解决方案可以起最后的搞锯齿作用。
而安卓就比较复杂了,下面就如何在安卓下有效抗做一次梳理。
以下都是针对简单的方块模块(即一块div)进行研究
这里研究的安卓系统都是4.0以上的,2.3不做研究(因为份额几乎快没了)
如何在安卓下对抗rotate造成的锯齿
为了方便描述,把被rotate的元素简单地划分成两类:
- 图片(即
标签的元素)
- 带背景的div
本人已经通过验证了,以纯色作背景的div和以图片作背影的div在锯齿的表现上是一样的,所以把二者统一成一类。
图片rotate后抗锯齿方法
保证img在一个容器(如div)内,并使rotate作用于容器上,此时只要开启容器的GPU,和为容器添加一个透明border即可
如下: rotate-blur2.html:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="telephone=no" name="format-detection">
<meta content="email=no" name="format-detection">
<title>rotate锯齿 - 图片</title>
<style type="text/css">
html,body{width: 100%; height: 100%; margin: 0; padding: 30px 0 0 0; background-color: #000;}
.box{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -80px 0 0 -120px; color: #666; border:2px solid rgba(255,255,255,0);}
.box2{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -80px 0 0 20px; color: #666;}
.box3{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: 50px 0 0 -120px; color: #666; border:2px solid rgba(255,255,255,0);}
.box4{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: 50px 0 0 20px; color: #666;}
</style>
</head>
<body ontouchstart>
<input id="deg" value="0"/>
<div class="box" id="box">
<img src="http://smartpro.sinaapp.com//test/white.jpg">
</div>
<div class="box2" id="box2">
<img src="http://smartpro.sinaapp.com//test/white.jpg">
</div>
<div class="box3" id="box3">
<img src="http://smartpro.sinaapp.com//test/white.jpg">
</div>
<div class="box4" id="box4">
<img src="http://smartpro.sinaapp.com//test/white.jpg">
</div>
</body>
<script type="text/javascript">
deg.addEventListener("change",function(){
box.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg) translateZ(0)";
box2.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg) translateZ(0)";
box3.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg)";
box4.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg)";
});
//安卓结论抗锯齿的关键,加上3D属性translateZ(0)开启gpu,但是此时仍然会有锯齿问题,需要添加非0的border且颜色为rgba(255,255,255,0)
</script>
</html>
扫一扫:
以下是截图:
小米2
小米3
红米2
华为3c
魅蓝note
通过五部手机可以清楚地知道,华为3c对 rotate 锯齿的处理结果就很理想,加不加GPU和border值都没关系。而对于小米系列手机和魅蓝来说,只有加了border:1px solid rgba(255,255,255,0)和translateZ(0) 搞锯齿才起作用。
小结: 解决安卓下rotate图片锯齿的解决方法是为其容器添加"translateZ(0)"和"border:1px solid rgba(255,255,255,0)"两个属性
非图片元素rotate后搞锯齿的方法
对于纯颜色DIV来说,上述的方法是无法解决锯齿问题的。至于原因,这里涉及到border与容器的background之前的关系。
简略的分析如下:
容器可以细分为:外边距,边框,内边距和内容区。在内外边距都为0边框不为0的情况下,可以认为容器就只有边框和内容区,此时边框和内容区是紧挨在一起的,容器的尺寸等边框尺寸,内容区的尺寸略小于容器的尺寸。如下:
如果容器有填充(即有背景)的元素,那么它是怎么渲染过程如下:
也就是说此时的边框和容器的填充是有重叠的。 在图片rotate的例子中,图片和外部容器的border它却是不重叠的。
透明border去锯齿的原理:透明边框会在边缘处产生羽化的效果。
有扣图经验的小伙伴都知道羽化是去锯齿的利器。由于背景填充与边框重叠,羽化的区域被困死在重叠区中,起不了抗锯齿的作用。不过知道,搞锯齿的原理,就有办法解决锯齿问题。只要我不把羽化区困死,锯齿就不会有了。css3有一个叫background-clip的属性,用这个属性可以强制容器的填充是填充整个容器还是只填充内容区。现在我只需要填充内容区,于是用background-clip:content-box;那么容器的渲染就会变成:
根据上述原理,写了另一个demo
rotate-blur.html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="telephone=no" name="format-detection">
<meta content="email=no" name="format-detection">
<title>rotate锯齿</title>
<style type="text/css">
html,body{width: 100%; height: 100%; margin: 0; padding: 30px 0 0 0; background-color: #000;}
.box{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -160px 0 0 -120px; background:url(http://smartpro.sinaapp.com//test/white.jpg); color: #666; border:1px solid rgba(255,255,255,0);}
.box2{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -160px 0 0 20px; background:url(http://smartpro.sinaapp.com//test/white.jpg); color: #666;}
.box3{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -20px 0 0 -120px; background:url(http://smartpro.sinaapp.com//test/white.jpg); color: #666; border:1px solid rgba(255,255,255,0);}
.box4{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: -20px 0 0 20px; background:url(http://smartpro.sinaapp.com//test/white.jpg); color: #666;}
.box5{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: 120px 0 0 -120px; background:url(http://smartpro.sinaapp.com//test/white.jpg); color: #666; border:1px solid rgba(255,255,255,0); background-clip: content-box;}
.box6{position: absolute; left: 50%; top: 50%; width: 100px; height: 100px; margin: 120px 0 0 20px; background:url(http://smartpro.sinaapp.com//test/white.jpg); color: #666; border:1px solid rgba(255,255,255,0); background-clip: content-box;}
</style>
</head>
<body ontouchstart>
<input id="deg" value="0"/>
<div class="box" id="box">
有border有translateZ
</div>
<div class="box2" id="box2">
无border有translateZ
</div>
<div class="box3" id="box3">
有border无translateZ
</div>
<div class="box4" id="box4">
无border无translateZ
</div>
<div class="box5" id="box5">
有border有translateZ加background-clip:content-box;
</div>
<div class="box6" id="box6">
有border无translateZ加background-clip:content-box;
</div>
</body>
<script type="text/javascript">
deg.addEventListener("change",function(){
box.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg) translateZ(0)";
box2.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg) translateZ(0)";
box3.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg)";
box4.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg)";
box5.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg) translateZ(0)";
box6.style["-webkit-transform"]="rotate("+(parseFloat(this.value)||0)+"deg) translateZ(0)";
});
//安卓结论抗锯齿的关键,加上3D属性translateZ(0)开启gpu,但是此时仍然会有锯齿问题,需要添加非0的border且颜色为rgba(255,255,255,0)
</script>
</html>
扫一扫体验:
以下是实测截图:
小米2
小米3
红米2
华为3c
魅蓝note
通过上面的测试,可以发现原来处理锯齿很友好的华为3c也出现锯齿了,不过,使用了我们的抗锯样式后明显好多了。其它的四部手机也是。不过总的说来,抗锯的效果相对于图片来说差了一点。
安卓抗锯总结
综合上述两个解决方案,可以统一得出一个抗锯方案:
.border-blur{-webkit-transform:translateZ(0); border:1px solid rgba(255,255,255,0); background-clip:content-box;}
锯齿写错了 是锯齿
锯齿写错了 是锯齿
@h5m1007 谢谢指正