点击下方星标公众号,实用前端技术文章及时了解

偶然在某思看到这样一个问题,如何使一个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);
})

这样,半透明效果的镂空效果就完成了。

完整代码可以访问:https://codepen.io/xboxyan/pen/VwzRaNZ

三、渐变也能实现半透明的效果

除了上述阴影扩展的方式,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。

backdrop-filter链接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/backdrop-filter

使用方式和 filter完全一致!

backdrop-filter: blur(10px);

下面是 MDN 中的一个示意效果:

backdrop-filter是让当前元素所在区域后面的内容模糊,要想看到效果,需要元素本身半透明或者完全透明;而filter是让当前元素自身模糊。

有兴趣的可以查看这篇文章:CSS backdrop-filter简介与苹果iOS毛玻璃效果 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com)

文章链接:https://www.zhangxinxu.com/wordpress/2019/11/css-backdrop-filter/

需要注意的是,这种模糊与背景的半透明度没有任何关系,哪怕元素本身是透明的,仍然会有效果。例如下面是去除背景后的效果 ,整块都是模糊的。

如果直接运用到上面的例子会怎么样呢?

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)
}

这样就实现了文章开头的效果:

完整代码可以查看:https://codepen.io/xboxyan/pen/porpoXJ

六、CSS MASK COMPOSITE 实现更丰富的镂空效果

除了使用径向渐变绘制遮罩层以外,还可以通过 CSS MASK COMPOSITE(遮罩合成)的方式来实现。

CSS MASK COMPOSITE 链接:https://developer.mozilla.org/en-US/docs/Web/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 链接:https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-composite

-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中的计算,这样也能很好的实现这个效果:

完整代码可以查看:https://codepen.io/xboxyan/pen/ExvMpQB

你可能已经发现,上述例子中的圆是通过 svg 绘制的,还用到了遮罩合成,看着好像更加繁琐了。其实呢,这是一种更加万能的解决方式,可以带来无限的可能性。比如我需要一个星星⭐️的镂空效果,很简单,先通过一个绘制软件画一个。

然后把这段 svg 代码转义一下,这里推荐使用张鑫旭老师的SVG在线压缩合并工具。

链接:https://www.zhangxinxu.com/sp/svgo/

替换到刚才的例子中就可以了。

.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)
}

星星镂空实现效果如下:

完整代码可以查看:https://codepen.io/xboxyan/pen/vYJPaVy

再比如一个心形❤,实现效果如下:

完整代码可以查看:https://codepen.io/xboxyan/pen/KKvEBjb

只有想不到,没有做不到

七、总结和说明

以上实现了一个鼠标跟随镂空的效果,从简单到复杂,从单一到通用,虽然借助了一点点 JS ,但是仅仅是“工具人”的角色,交互逻辑全部都由 CSS 完成,下面总结一下:

  1. 足够大的阴影是一个实现圆形镂空效果的小技巧

  2. CSS 渐变也能轻易的绘制出圆形镂空背景

  3. 借助 CSS 变量可以很方便的利用鼠标位置实现想要的效果

  4. backdrop-filter 可以想象成磨砂玻璃的功能

  5. CSS Mask 可以给磨砂玻璃打孔,实现镂空的效果

  6. 借助遮罩合成特性和SVG,可以实现任意形状的镂空效果

CSS MASK 还是非常强大的,有必要还是多掌握一下。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、在看、收藏、转发。

作者:XboxYan

https://segmentfault.com/a/1190000040996523

推荐链接

  1. 纯 CSS 自定义多行省略:从原理到实现

  2. 前端程序员简历模板整理和下载

  3. 这才是前端该写的代码:CSS常见套路续

关注公众号 前端开发博客,回复“加群”,秒进群

加入我们一起学习,天天进步

祝 您:2022 年暴富!万事如意!

点赞和在看就是最大的支持,比心❤️

CSS mask 实现鼠标跟随镂空效果相关推荐

  1. html++鼠标跟随动画,css3动画过渡实现鼠标跟随导航效果

    本篇文章主要介绍了css3动画过渡实现鼠标跟随导航效果,分享给大家,具体如下: 鼠标跟随导航效果 效果知识点:html/css布局思维, div+css讲解,css3动画,盒子模型, 浮动与定位,鼠标 ...

  2. html图片折叠,CSS 实现 图片鼠标悬停折叠效果

    CSS 实现 图片鼠标悬停折叠效果 1. 实现要点 折叠是由多个块级元素来完成的; 图片是以背景图片的方式呈现出来的; 给每个块级元素设置同一张背景图片,通过background-position来控 ...

  3. JQuery实现一个简单的鼠标跟随提示效果

    效果体验:http://hovertree.com/texiao/jsstudy/2/ 实现思路 1 鼠标移入标题(这里是<a>标签) 创建一个div,div的内容为鼠标位置的文本 将创建 ...

  4. 不可思议的纯 CSS 实现鼠标跟随效果

    不可思议的纯 CSS 实现鼠标跟随效果 原文:不可思议的纯 CSS 实现鼠标跟随效果 直接进入正题,鼠标跟随,顾名思义,就是元素会跟随着鼠标的移动而作出相应的运动.大概类似于这样: 通常而言,CSS ...

  5. 纯 CSS 实现鼠标跟随效果

    欢迎微信关注Jerome blog,用技术的心去生活 鼠标跟随效果,顾名思义,就是元素会跟随着鼠标的移动而作出相应的运动.大概类似于这样: 通常而言,CSS 负责表现,JavaScript 负责行为. ...

  6. CSS实现鼠标跟随 3D 旋转效果,让交互活起来

    一淘模板(56admin.com)给大家介绍一下如何使用CSS实现有意思的鼠标跟随 3D 旋转效果,让交互更加生动,希望对大家有所帮助! 今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实 ...

  7. 【js】鼠标跟随效果

    1.实现思想 ①鼠标跟随效果,发生在鼠标移动的时候,故需要使用onmousemove事件 ②当页面内容多于1屏时,就需要考虑滚动距离的问题 ③想实现鼠标跟随的效果需要:元素的left位置 = 鼠标当前 ...

  8. mousemove实现图片鼠标跟随效果

    前言 用html+css+JavaScript实现了一个图片鼠标跟随效果 一.思路 鼠标不断的移动,使鼠标移动事件:mousemove: 在页面中移动,给document注册事件: 图片要移动距离,而 ...

  9. JavaScript实现心形div块跟随鼠标移动(幻影效果)

    JavaScript实现心形div块跟随鼠标移动(幻影效果) 上篇博客讲解了怎样利用JavaScript实现一串div块跟随鼠标指针移动,然后有轩辕问我,想给女朋友做一个好看的可不可以.现在我们来实现 ...

最新文章

  1. [置顶]2010年东北大学ACM程序设计竞赛冬季校赛题解
  2. 【数据结构】树状数组 例题剖析
  3. python随机大小写字符串_python 随机产生特定类型字符的函数(大写、小写、数字)...
  4. 魔方机器人需要特制魔方吗_解魔方的机器人攻略18 – 魔方快速算法
  5. 【Java】7.3 基本类 7.4 Java 8 的日期、时间类
  6. CSS之中间固定两边自适应宽度
  7. jQuery / zepto ajax 全局默认设置
  8. win8.1重装系统计算机管理打不开,Windows8计算机打不开192.168.0.1怎么办
  9. Linux必备命令 - 常用命令集
  10. 【计量经济学论文】近十年烟台港发展情况的计量分析(节选)
  11. 专业技能与职业素养报告计算机,学生专业技能与职业素养专题报告怎么写
  12. 【uniapp 课程表】
  13. ctDNA早期肿瘤×××基因检测
  14. (淘宝无限适配)手机端rem布局
  15. 不得不珍藏的Chrome插件推荐
  16. CAD中如何布置火灾探测器?消防探测器范围计算
  17. 主数据治理项目前期调研
  18. 月盈则亏,水满则溢,欲速则不达,及时止损
  19. $.extend用法
  20. python编程的文件后缀是什么意思_编程语言通常有固定的后缀,如golang文件是test.go,Python文件后缀通常定义为以____结尾...

热门文章

  1. 项目中添加音效--依旧的简单使用
  2. u3d honey hex framework 代码解读记录(四)
  3. 兼容big sur的达芬奇后期调色软件
  4. python创建socket对象_python socket对象内建方法
  5. Git 安装与卸载 gitk安装与优化
  6. TensorFlow Object Detection API入门例子 (小浣熊检测下)
  7. 前有雅迪,后有九号,小牛电动的“智能”故事能动听多久?
  8. 各种投资产品的整理分析(持续更新)
  9. typeof NaN的结果是什么?
  10. 2021-2027全球与中国灭火机器人市场现状及未来发展趋势