tuy

微信X5内核浏览器不支持-webkit-filter

一:前言

在制作7月份市民卡微信超值抢的活动中,偶遇微信浏览器跟pc端的webkit浏览器的一个区别,由于这次的实现方案跟5月份的有些区别,所以才暴露了这个问题。页面结构布局如图:

二:DOM结构

页面很简单,主图就是上面两张,另外的就是一些规范的兑换流程界面,与我们本次主题无关,当用户抢了券之后,就可以进到我的卡券里面查看已经抢到的券,继续点击兑换,就能跳转到相关商品详情页面进行优惠券的使用消费,最后这张券就变成了已兑换的灰色样式;此处的重心就是变灰,优惠券单张的DOM结构如下:

<section>
       <div>
               <div>
                 <img src="images/test.png"> <!--上传图片大小:436*220-->
                 <article>
                  <aside>我是标题</ aside >
                   <ul>
                        <li><span>现价:¥9.9</span><i>¥13.9</i></li>
                        <li>有效期至:2015/08/18</li>
                   </ul>
                 </article>
               </div>
               <div>
                     <a class="get01"></a>
                     <a class="detail"></a>
               </div>
       </div>
    <div></div>
</section>

三:实现方案探索

根据这个文档结构,我脑海中最快浮现的是两种方式去变灰:1、直接把section整个容器使用filter滤镜变灰,因为filter不仅仅是用在img元素上,也可以在div中生效;2、给section添加上一个灰色的class,然后调整下面的每一个子元素,通过新增父容器约束样式,来实现整个子内容重新渲染。

方案1:

section.gray{
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);  
    filter: grayscale(100%);
    filter: gray;
 }

方案2:

//这里引用的图片都是用作图软件制作好的灰色图标,边框也用样式变成灰色
section.gray .item{border:1px solid #aaa;}
section.gray a.get01:before{
content:'已抢完';line-height:82px;padding-left:13px;
}
section.gray a.dui01:before{
content:'已兑换';line-height:82px;padding-left:13px;
}
section.gray  a:last-child{background: url(../images/detail_.png) 12px center no-repeat;background-size:52px 21px;}
section.gray .div{width:6px;height:112px;background: url(../images/i_.png) center center no-repeat;background-size:5.5px 112px;position:absolute;left:215px;top:0px}
section.gray  .left img{filter: gray;}
.cover{width:218px;height:112px;border:1px solid #aaa;background:#000;position:absolute;left:0;top:0;opacity:1;border-radius:6px;display:none}
section.gray .cover{display:block}

方案1一看就是最简洁的,而且我放到chrome和QQ浏览器跑了一下,都完全OK,顺利变成灰色,但是当开发人员把页面调整完毕,部署到测试环境,通过测试公众号在微信访问的时候,测试人员发现图片根本没有变灰,通过查阅相关资料得知,腾讯的微信浏览器(x5)虽然是基于webkit内核引擎,但出于引擎在移动端的优化,有一些pc端的功能还未完全支持,就比如这个-webkit-filter、 flexbox 等等,查看其它X5兼容性问题请点击:微信浏览器X5内核css问题汇总,无奈只能绕开-webkit-filter方式,采用方案2,方案2有一个比较累赘的地方就是我们每一张彩色图片都要做一张灰色图片,这是枯燥的图片处理工作,应该避免。

由于对后台图片处理不是太了解,于是先尝试从前端角度去变灰,鉴于刚刚的css3已经失败了,开始着手js方法,首先想到的就是html5 canvas元素,然后马上查看了一下x5内核,确定它是支撑画布的。开工!

四:准备工作

a. 如何往Canvas对象绘制一个DOM img

var img = document.getElementById("source");
tempContext.drawImage(img, 0, 0, width,height);//这里的width是把img的宽度缩放到多少绘制进去,高度同理,而不是画布的高和宽,因为画布已经是固定大小的,就像ps软件里面的画布跟图像一样,画布是背景,图像是我们当前绘制上去的可见对象。

b.如何拿到Canvas对象的像素数据

var canvas = document.getElementById("canvas ");
var context = canvas. .getContext("2d");
var canvasData = context.getImageData(0, 0, canvas.width, canvas.height); //这里就表示拿到整块画布的数据,因为我们把宽跟高都传入了画布的尺寸
var imgData = canvasData.data;

c. 灰色调:获取一个像素点RGB值r, g,b,然后再对RGB分别调整,重新赋值。

var gray = .299 * r + .587 * g + .114 * b;

五:代码整合

    window.onload = function () {
	    $('section.gray').each(function(){
		var canvas = $(this).find('canvas').get(0);
		var image = $(this).find('img').get(0);
        // 将图片的高宽赋值给画布
        canvas.width = image.width;
        canvas.height = image.height;
        // 获得二维渲染上下文
        if (canvas.getContext) {//为了安全起见,先判断浏览器是否支持canvas
            var context = canvas.getContext("2d");
            context.drawImage(image, 0, 0,217,110);//将得到的image图像绘制在canvas对象中
            var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);//返回ImageData对象
           // alert(canvasData.width.toString());
           // alert(canvasData.height.toString());
            // 填充灰色【读取像素值和实现灰度计算】
            for (var x = 0; x < canvasData.width; x++) {
                for (var y = 0; y < canvasData.height; y++) {
                    // Index of the pixel in the array
                    var idx = (x + y * canvasData.width) * 4;
                    var r = canvasData.data[idx + 0];
                    var g = canvasData.data[idx + 1];
                    var b = canvasData.data[idx + 2];
                    // 灰度的计算
                    var gray = .299 * r + .587 * g + .114 * b;
                    // assign gray scale value
                    canvasData.data[idx + 0] = gray; // Red channel
                    canvasData.data[idx + 1] = gray; // Green channel
                    canvasData.data[idx + 2] = gray; // Blue channel
                    canvasData.data[idx + 3] = 255; // Alpha channel
                }
            }
            context.putImageData(canvasData, 0, 0); // 处理完成的数据重新载入到canvas二维对象中
        } else {
            alert("your browser does not support canvas!");
        }		
		
		}); 
    }

 猛戳右侧查看demo:纯粹使用filter的页面使用canvas画布实现的页面

六:小结

微信端的网页做到现在,多少会有些感概,个人觉得有几个css3的优秀布局都没有在微信的X5内核浏览器中实现,除了上面描述的图片变灰属性,还有一个是flex。它是css3强大的弹性盒模型,多列和多行布局非常方便。由于不支持flex,很多可以几行代码解决的布局,使用了繁琐的table结构,或者使用了div+js的结构,js是对dom的二次渲染,即消耗性能,又会有微妙的延时。总的来说还是希望微信内核在未来的版本更新中,在不影响性能的情况下,越来越接近pc的webkit,让每个前端参与微信交互时能够更加高效,跨平台,享受开发过程。


码字很辛苦,转载请注明来自tuy博客《微信X5内核浏览器不支持-webkit-filter》

评论

  1. 高老庄的呆子 #1

    好顶赞

    回复
    2015-07-13
  2. 花千骨头 #2

    准备工作里面的c步奏,为什么对RGB进行系数调整.299 * r + .587 * g + .114 * b;它就变成灰色了呢!!!? :shock:

    回复
    2015-07-13
    • admin
      admin

      @花千骨头,关于色彩转换是一门比较复杂的学科,我也是拿来主义,使用了前辈们已经研究出来的图形转换成果。您刚刚提到的系数调整是计算机领域RGB转灰度值的心理学公式 Gray =.299 * r + .587 * g + .114 * b;百度百科里面告诉我们一共有五种算法:
      1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
      2.整数方法:Gray=(R*30+G*59+B*11)/100
      3.移位方法:Gray =(R*77+G*151+B*28)>>8;
      4.平均值法:Gray=(R+G+B)/3;
      5.仅取绿色:Gray=G;
      url:http://baike.baidu.com/view/2796249.htm
      希望对您有帮助;
      如果还对计算机图形有浓厚兴趣可以看看维基百科的介绍,很全面,好像目前只有英文版本:https://en.wikipedia.org/wiki/Grayscale

      回复
      2015-07-13
  3. miki #3

    请问 context.drawImage(image, 0, 0,217,110); 如果没办法知道图片的宽度和高度怎么办?
    pc-chrome会报这个错误。
    Uncaught SecurityError: Failed to execute ‘getImageData’ on ‘CanvasRenderingContext2D’: The canvas has been tainted by cross-origin data

    回复
    2015-12-18
    • admin
      admin

      @miki,您好,无法获知图片尺寸进行绘图,只会绘制图片的原尺寸,demo:http://runjs.cn/code/ntw5dhtv
      你描述的报错并非尺寸问题,cross-origin是跨域问题,你的项目是否只是简单的跑了一下静态,没有放到服务器环境(电脑文件夹的 html网页),因为纯静态页面用的图片是文件夹内的,js跨域限制是不能获取非同一域名下的数据,而电脑文件夹只有路径没有域名,导致报错。尝试部署到测试服务器上试试,当然跨域也有可能是你服务器上的页面访问其它域名的图片导致。
      当把域不同的图片放到canvas上,这个canvas就成为 “tainted”(被污染的),浏览器禁止我们操作任何像素,也是为了阻止多种类型的XSS/CSRF攻击(两种典型的跨站攻击)。有问题欢迎继续交流,祝你成功。

      参考资料:
      http://www.w3school.com.cn/tags/canvas_drawimage.asp
      http://www.zhihu.com/question/26379635
      http://blog.csdn.net/freshlover/article/details/44223467

      回复
      2015-12-20