共计 5957 个字符,预计需要花费 15 分钟才能阅读完成。
偶尔在某思看到这样一个问题,如何使一个 div 的局部区域变通明而其余局部含糊掉?,最初实现成果是这样的
进一步,还能实现任意形态的镂空成果
鼠标通过的中央清晰可见,其余中央则是含糊的。
可能一开始无从下手,不要急,能够先从简略的、相似的成果开始,一步一步尝试,一起看看吧。
一、一般半透明的成果
比方平时开发中碰到更多的可能是一个半透明的成果,有点相似于探照灯(鼠标里面的中央是半透明遮罩,看起来会暗一点)。如下:
那先从这种成果开始吧,假如有这样一个布局:
<div class="wrap" id="img">
<img class="prew" src="https://tva1.sinaimg.cn/large/008i3skNgy1gubr2sbyqdj60xa0m6tey02.jpg">
</div>
那么如何绘制一个镂空的圆呢?先介绍一种办法
其实很简略,只须要一个足够大的投影就能够了,原理如下
这里能够用伪元素 ::before
来绘制,构造更加精简。用代码实现就是
.wrap::before{
content:'';
position: absolute;
width: 100px;
height: 100px;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%,-50%); /* 默认居中 */
box-shadow: 0 0 0 999vw rgba(0, 0, 0, .5); /* 足够大的投影 */
}
能够失去这样的成果
二、借助 CSS 变量传递鼠标地位
依照以往的教训,可能会在 js 中间接批改元素的 style 属性,相似这样
img.addEventListener('mousemove', (ev) => {
img.style.left = '...';
img.style.top = '...';
})
然而这样交互与业务逻辑混淆在一起,不利于前期保护。其实,咱们只须要鼠标的坐标,在 CSS 中也能齐全实现追随的成果。
这里借助 CSS 变量,那所有就好办了!假如鼠标的坐标是 [--x,--y]
(范畴是 [0, 1]
),那么遮罩的坐标就能够应用 calc
计算了
.wrap::before{left: calc(var(--x) * 100%);
top: calc(var(--y) * 100%);
}
而后鼠标坐标的获取能够应用 JS 来计算,也比拟容易,如下
img.addEventListener('mousemove', (ev) => {img.style.setProperty('--x', ev.offsetX / ev.target.offsetWidth);
img.style.setProperty('--y', ev.offsetY / ev.target.offsetHeight);
})
这样,半透明成果的镂空成果就实现了
残缺代码能够拜访:backdrop-shadow (codepen.io)
三、突变也能实现半透明的成果
除了上述暗影扩大的形式,CSS 径向突变 也能实现这样的成果
绘制一个从通明到半透明的突变,如下
.wrap::before{
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: radial-gradient(circle at center, transparent 50px, rgba(0,0,0,.5) 51px);
}
能够失去这样的成果
而后,把鼠标坐标映射下来就能够了。从这里就能够看出 CSS 变量的益处,无需批改 JS,只须要在 CSS 中 批改突变中心点 的地位就能够实现了
.wrap::before{background: radial-gradient( circle at calc(var(--x) * 100% ) calc(var(--y) * 100% ), transparent 50px, rgba(0,0,0,.5) 51px);
}
四、背景含糊的成果尝试
CSS 中有一个专门针对背景(元素前面区域)的属性:backdrop-filter。应用形式和 filter
完全一致!
backdrop-filter: blur(10px);
上面是 MDN 中的一个示意成果
backdrop-filter
是让以后 元素所在区域前面的内容 含糊,要想看到成果,须要元素自身半透明或者齐全通明;而 filter
是让以后 元素本身 含糊。有趣味的能够查看这篇文章:CSS backdrop-filter 简介与苹果 iOS 毛玻璃成果 « 张鑫旭 - 鑫空间 - 鑫生存 (zhangxinxu.com)
须要留神的是,这种 含糊与背景的半透明度没有任何关系,哪怕元素自身是通明的,依然会有成果。例如上面是去除背景后的成果,整块都是含糊的
如果间接使用到下面的例子会怎么样呢?
1. 暗影实现
在下面第一个例子中增加 backdrop-filter
.wrap::before{
content:'';
position: absolute;
width: 100px;
height: 100px;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%,-50%); /* 默认居中 */
box-shadow: 0 0 0 999vw rgba(0, 0, 0, .5); /* 足够大的投影 */
backdrop-filter: blur(5px)
}
失去成果如下
能够看到圆形区域是含糊的,正好和心愿的成果相同。其实也好了解,只有圆形区域才是实在的构造,里面都是暗影,所以最初作用的范畴也只有圆形局部
2. 突变实现
当初在第二个例子中增加 backdrop-filter
.wrap::before{
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: radial-gradient(circle at calc(var(--x) * 100% ) calc(var(--y) * 100% ), transparent 50px, rgba(0,0,0,.5) 51px);
backdrop-filter: blur(5px)
}
成果如下
曾经全副都含糊了,只是圆形区域外暗一些。因为 ::before
的尺寸占据整个容器,所以整个背地都变含糊了,圆形内部比拟暗是因为半透明突变的影响。
总之还是不能满足咱们的需要,须要寻求新的解决形式。
五、CSS MASK 实现镂空
与其说是让圆形区域不含糊,还不如说是把那块区域给镂空了。就好比之前是一整块磨砂玻璃,而后通过 CSS MASK 打了一个圆孔,这样透过圆孔看到前面必定是清晰的。
能够对第二个例子稍作批改,通过径向突变绘制一个通明圆,残余局部都是纯色的遮罩层,示意如下
用代码实现就是
.wrap::before{
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
-webkit-mask: radial-gradient(circle at calc(var(--x, .5) * 100% ) calc(var(--y, .5) * 100% ), transparent 50px, #000 51px);
background: rgba(0,0,0,.3);
backdrop-filter: blur(5px)
}
这样就实现了文章结尾的成果
残缺代码能够查看:backdrop-mask (codepen.io)
六、CSS MASK COMPOSITE 实现更丰盛的镂空成果
除了应用径向突变绘制遮罩层以外,还能够通过 CSS MASK COMPOSITE(遮罩合成)的形式来实现。规范要害值如下(firefox 反对):
/* Keyword values */
mask-composite: add; /* 叠加(默认)*/
mask-composite: subtract; /* 减去,排除掉下层的区域 */
mask-composite: intersect; /* 相交,只显示重合的中央 */
mask-composite: exclude; /* 排除,只显示不重合的中央 */
遮罩合成是什么意思呢?能够类比 photoshop 中的形态合成,简直是一一对应的
-webkit-mask-composite 与规范下的值有所不同,属性值十分多,如下(chorme、safari 反对)
-webkit-mask-composite: clear; /* 革除,不显示任何遮罩 */
-webkit-mask-composite: copy; /* 只显示上方遮罩,不显示下方遮罩 */
-webkit-mask-composite: source-over;
-webkit-mask-composite: source-in; /* 只显示重合的中央 */
-webkit-mask-composite: source-out; /* 只显示上方遮罩,重合的中央不显示 */
-webkit-mask-composite: source-atop;
-webkit-mask-composite: destination-over;
-webkit-mask-composite: destination-in; /* 只显示重合的中央 */
-webkit-mask-composite: destination-out;/* 只显示下方遮罩,重合的中央不显示 */
-webkit-mask-composite: destination-atop;
-webkit-mask-composite: xor; /* 只显示不重合的中央 */
是不是一脸懵?这里做了一个对应的效果图,如果不太纯熟,应用的时候晓得有这样一个性能,而后对着找就行了
回到这里,能够绘制一整块背景和一个圆形背景,而后通过遮罩合成排除(mask-composite: exclude
)打一个孔就行了,实现如下
.wrap::before{
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
-webkit-mask: url("data:image/svg+xml,%3Csvg width='50'height='50'viewBox='0 0 50 50'fill='none'xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='25'cy='25'r='25'fill='%23C4C4C4'/%3E%3C/svg%3E"), linear-gradient(red, red);
-webkit-mask-size: 50px, 100%;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: calc(var(--x, .5) * 100% + var(--x, .5) * 100px - 50px ) calc(var(--y, .5) * 100% + var(--y, .5) * 100px - 50px ), 0;
-webkit-mask-composite: xor; /* 只显示不重合的中央,chorem、safari 反对 */
mask-composite: exclude; /* 排除,只显示不重合的中央,firefox 反对 */
background: rgba(0,0,0,.3);
backdrop-filter: blur(5px)
}
须要留神 -webkit-mask-position
中的计算,这样也能很好的实现这个成果
残缺代码能够查看:backdrop-mask-composite (codepen.io)
你可能曾经发现,上述例子中的圆是通过 svg 绘制的,还用到了遮罩合成,看着如同更加繁琐了。其实呢,这是一种更加万能的解决形式,能够带来有限的可能性。比方我须要一个星星⭐️的镂空成果,很简略,先通过一个绘制软件画一个
而后把这段 svg 代码本义一下,这里举荐应用张鑫旭老师的 SVG 在线压缩合并工具
替换到方才的例子中就能够了
.wrap::before{
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
-webkit-mask: url("data:image/svg+xml,%3Csvg width='96'height='91'viewBox='0 0 96 91'fill='none'xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M48 0l11.226 34.55h36.327l-29.39 21.352L77.39 90.45 48 69.098 18.61 90.451 29.837 55.9.447 34.55h36.327L48 0z'fill='%23C4C4C4'/%3E%3C/svg%3E"), linear-gradient(red, red);
-webkit-mask-size: 50px, 100%;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: calc(var(--x, .5) * 100% + var(--x, .5) * 100px - 50px ) calc(var(--y, .5) * 100% + var(--y, .5) * 100px - 50px ), 0;
-webkit-mask-composite: xor; /* 只显示不重合的中央,chorem、safari 反对 */
mask-composite: exclude; /* 排除,只显示不重合的中央,firefox 反对 */
background: rgba(0,0,0,.3);
backdrop-filter: blur(5px)
}
星星镂空实现成果如下
残缺代码能够查看:backdrop-star (codepen.io)
再比方一个心形❤,实现成果如下
残缺代码能够查看:backdrop-heart (codepen.io)
只有想不到,没有做不到
七、总结和阐明
以上实现了一个鼠标追随镂空的成果,从简略到简单,从繁多到通用,尽管借助了一点点 JS,然而仅仅是“工具人”的角色,交互逻辑全副都由 CSS 实现,上面总结一下:
- 足够大的暗影是一个实现圆形镂空成果的小技巧
- CSS 突变也能轻易的绘制出圆形镂空背景
- 借助 CSS 变量能够很不便的利用鼠标地位实现想要的成果
- backdrop-filter 能够设想成磨砂玻璃的性能
- CSS Mask 能够给磨砂玻璃打孔,实现镂空的成果
- 借助遮罩合成个性和 SVG,能够实现任意形态的镂空成果
CSS MASK 还是十分弱小的,有必要还是多把握一下。最初,如果感觉还不错,对你有帮忙的话,欢送点赞、珍藏、转发❤❤❤