「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
前天有同学建议我可以写一篇关于 mask-image 的文章,我不知道这是个啥,今天就来探索一下。
学习思路
- 看 mdn 文档: mask-image - CSS(层叠样式表) | MDN (mozilla.org)
- 写个 demo 在浏览器上debug
- 分析细节
从mdn文档了解的
这是一个实验性的 css 属性,在 mdn 上的描述很简略,就是用于设置元素遮罩层的图像,mask-image 是mask的一个子配置,通常配合 mask-repeat、mask-size等属性一起使用,具体来说效果就像ps的剪切蒙版功能,设置了mask-image后,只有mask-image图片的非透明部分与元素重叠的部分可以被显示,元素的其他区域编程透明。比如di标签是背景填充成青色的正方形,设置了mask-image为一张五角星的图片(五角星以外的区域是透明的),那最终视觉效果就是一个青色的五角星。。
mdn 官网给了一个 demo ,然而我在电脑上看到的例子的效果预览是空白的,看了个寂寞,所以我把示例代码拷到自己的网页运行一下,用chrome开发者工具看一下。
demo调试过程
css代码是这样的:
#masked {
width: 100px;
height: 100px;
background-color: #8cffa0;
mask-image: url(https://mdn.mozillademos.org/files/12676/star.svg);
-webkit-mask-image: url(https://mdn.mozillademos.org/files/12676/star.svg);
}
从开发者工具中看到的是这样的:
从元素的style 可以看出来我现在的浏览器要用mask-image,只有加 -webkit前缀是有效的。对于url中的图片我打开看了下,是个灰色五角星的svg,但是在网页上显示效果是仍然是空白的——准确地说是透明的,如果div#masked标签内有内容,比如放了一个img标签和一段文字,理应显示一张图片和文字,但是结果还是透明的,图文都没有显示出来,但是div#masked盒子被作为子元素的图文撑起来了,有非 0 的宽高;
这样的表现太奇怪了,我重新看一下浏览器兼容性,借助caniuse.com查询兼容的具体情况
通过 chrome://version查看版本号看到我的chrome浏览器版本是95,应该是支持的。我还用版本号为94的 firefox试了一遍,还是不行。
因为在开发者工具看到的style的 -webkit-mask-image 没有被划掉,加上caniuse也说明我现在的浏览器版本是支持的,所以排除浏览器的问题,然后我想会不会是图片的问题,我将图片url换成另一张图片——一个react的logo的svg图片,结果居然可以了
mask-image 原图
元素未设置 mask-image的效果
元素设置了 mask-image的效果
都是svg图片,为什么mdn给的图片就不行呢,其中到底有什么玄机?
我重新点开原来的图片url,发现url存在一个重定向,我将 mask-image 的url改成重定向后的url后就可以正常显示了
也就是说图片重定向会导致 mask-image 出错。以前没听说过有因为图片重定向而无法显示的问题啊,所以我验证了一下background-image的url 和 img的 src,尽管有重定向,但都不影响图片显示。 在验证的过程中,我用开发者工具观察网络请求的情况,结果我发现了这个
这是在将 mask-image的 url定义成重定向前的url的case中出现的,结果出现了 CORS 错误。所以说,问题是出在同源策略限制上的, mask-image 的url限制了跨域。
那为什么重定向前有cors错误,重定向后就没有呢?
原因分析
我是在本地服务器运行的demo,必然是和图片重定向前后的两个url都不同源的。我尝试在网页放一个img标签,src指向重定向前的url,发起get请求得到302响应,自动发送一个对重定向后的url的get请求,响应码是200,这两个响应都没有Access-Control-Allow-Origin, 所以存在同源策略限制的mask-image就加载不了遮罩了。
而如果直接访问重定向后的 url,从抓包结果上看,服务端设置了 CORS(跨域资源共享),允许所有域访问,自然也就能被mask-image正常解析了。
access-control-allow-origin: *
access-control-allow-methods: GET
access-control-control-max-age: 3000
PS: mdn 放的 demo 该更新了,官方的 demo 却看不到正常的预期表现,实在很尴尬啊。