Open leeenx opened 7 years ago
有时候,我们需要transform的rotate方法来使元素倾斜,但是角度倾斜会给元素带来意料之外的效果--锯齿。
在IOS中,搞锯齿的方法很简单,只要开启元素的3d属性既开启了GPU加速后,能有效的实现抗锯齿。如果在开启了GPU后,ios页面仍出现锯齿现象,使用安卓的最终解决方案可以起最后的搞锯齿作用。
而安卓就比较复杂了,下面就如何在安卓下有效抗做一次梳理。
以下都是针对简单的方块模块(即一块div)进行研究
这里研究的安卓系统都是4.0以上的,2.3不做研究(因为份额几乎快没了)
为了方便描述,把被rotate的元素简单地划分成两类:
本人已经通过验证了,以纯色作背景的div和以图片作背影的div在锯齿的表现上是一样的,所以把二者统一成一类。
保证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)"两个属性
对于纯颜色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>
扫一扫体验:
以下是实测截图:
通过上面的测试,可以发现原来处理锯齿很友好的华为3c也出现锯齿了,不过,使用了我们的抗锯样式后明显好多了。其它的四部手机也是。不过总的说来,抗锯的效果相对于图片来说差了一点。
综合上述两个解决方案,可以统一得出一个抗锯方案:
.border-blur{-webkit-transform:translateZ(0); border:1px solid rgba(255,255,255,0); background-clip:content-box;}
锯齿写错了 是锯齿
@h5m1007 谢谢指正
有时候,我们需要transform的rotate方法来使元素倾斜,但是角度倾斜会给元素带来意料之外的效果--锯齿。
如何在IOS下对抗rotate造成的锯齿
在IOS中,搞锯齿的方法很简单,只要开启元素的3d属性既开启了GPU加速后,能有效的实现抗锯齿。如果在开启了GPU后,ios页面仍出现锯齿现象,使用安卓的最终解决方案可以起最后的搞锯齿作用。
而安卓就比较复杂了,下面就如何在安卓下有效抗做一次梳理。
以下都是针对简单的方块模块(即一块div)进行研究
这里研究的安卓系统都是4.0以上的,2.3不做研究(因为份额几乎快没了)
如何在安卓下对抗rotate造成的锯齿
为了方便描述,把被rotate的元素简单地划分成两类:
本人已经通过验证了,以纯色作背景的div和以图片作背影的div在锯齿的表现上是一样的,所以把二者统一成一类。
图片rotate后抗锯齿方法
保证img在一个容器(如div)内,并使rotate作用于容器上,此时只要开启容器的GPU,和为容器添加一个透明border即可
如下: rotate-blur2.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去锯齿的原理:透明边框会在边缘处产生羽化的效果。
根据上述原理,写了另一个demo
rotate-blur.html
扫一扫体验:
以下是实测截图:
小米2
小米3
红米2
华为3c
魅蓝note
通过上面的测试,可以发现原来处理锯齿很友好的华为3c也出现锯齿了,不过,使用了我们的抗锯样式后明显好多了。其它的四部手机也是。不过总的说来,抗锯的效果相对于图片来说差了一点。
安卓抗锯总结
综合上述两个解决方案,可以统一得出一个抗锯方案: