CSS mask 实现鼠标跟随镂空效果
点击下方星标本公众号,实用前端技术文章及时了解
偶然在某思看到这样一个问题,如何使一个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 完成,下面总结一下:
足够大的阴影是一个实现圆形镂空效果的小技巧
CSS 渐变也能轻易的绘制出圆形镂空背景
借助 CSS 变量可以很方便的利用鼠标位置实现想要的效果
backdrop-filter 可以想象成磨砂玻璃的功能
CSS Mask 可以给磨砂玻璃打孔,实现镂空的效果
借助遮罩合成特性和SVG,可以实现任意形状的镂空效果
CSS MASK 还是非常强大的,有必要还是多掌握一下。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、在看、收藏、转发。
作者:XboxYan
https://segmentfault.com/a/1190000040996523
推荐链接
纯 CSS 自定义多行省略:从原理到实现
前端程序员简历模板整理和下载
这才是前端该写的代码:CSS常见套路续
关注公众号 前端开发博客,回复“加群”,秒进群
加入我们一起学习,天天进步
祝 您:2022 年暴富!万事如意!
点赞和在看就是最大的支持,比心❤️
CSS mask 实现鼠标跟随镂空效果相关推荐
- html++鼠标跟随动画,css3动画过渡实现鼠标跟随导航效果
本篇文章主要介绍了css3动画过渡实现鼠标跟随导航效果,分享给大家,具体如下: 鼠标跟随导航效果 效果知识点:html/css布局思维, div+css讲解,css3动画,盒子模型, 浮动与定位,鼠标 ...
- html图片折叠,CSS 实现 图片鼠标悬停折叠效果
CSS 实现 图片鼠标悬停折叠效果 1. 实现要点 折叠是由多个块级元素来完成的; 图片是以背景图片的方式呈现出来的; 给每个块级元素设置同一张背景图片,通过background-position来控 ...
- JQuery实现一个简单的鼠标跟随提示效果
效果体验:http://hovertree.com/texiao/jsstudy/2/ 实现思路 1 鼠标移入标题(这里是<a>标签) 创建一个div,div的内容为鼠标位置的文本 将创建 ...
- 不可思议的纯 CSS 实现鼠标跟随效果
不可思议的纯 CSS 实现鼠标跟随效果 原文:不可思议的纯 CSS 实现鼠标跟随效果 直接进入正题,鼠标跟随,顾名思义,就是元素会跟随着鼠标的移动而作出相应的运动.大概类似于这样: 通常而言,CSS ...
- 纯 CSS 实现鼠标跟随效果
欢迎微信关注Jerome blog,用技术的心去生活 鼠标跟随效果,顾名思义,就是元素会跟随着鼠标的移动而作出相应的运动.大概类似于这样: 通常而言,CSS 负责表现,JavaScript 负责行为. ...
- CSS实现鼠标跟随 3D 旋转效果,让交互活起来
一淘模板(56admin.com)给大家介绍一下如何使用CSS实现有意思的鼠标跟随 3D 旋转效果,让交互更加生动,希望对大家有所帮助! 今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实 ...
- 【js】鼠标跟随效果
1.实现思想 ①鼠标跟随效果,发生在鼠标移动的时候,故需要使用onmousemove事件 ②当页面内容多于1屏时,就需要考虑滚动距离的问题 ③想实现鼠标跟随的效果需要:元素的left位置 = 鼠标当前 ...
- mousemove实现图片鼠标跟随效果
前言 用html+css+JavaScript实现了一个图片鼠标跟随效果 一.思路 鼠标不断的移动,使鼠标移动事件:mousemove: 在页面中移动,给document注册事件: 图片要移动距离,而 ...
- JavaScript实现心形div块跟随鼠标移动(幻影效果)
JavaScript实现心形div块跟随鼠标移动(幻影效果) 上篇博客讲解了怎样利用JavaScript实现一串div块跟随鼠标指针移动,然后有轩辕问我,想给女朋友做一个好看的可不可以.现在我们来实现 ...
最新文章
- [置顶]2010年东北大学ACM程序设计竞赛冬季校赛题解
- 【数据结构】树状数组 例题剖析
- python随机大小写字符串_python 随机产生特定类型字符的函数(大写、小写、数字)...
- 魔方机器人需要特制魔方吗_解魔方的机器人攻略18 – 魔方快速算法
- 【Java】7.3 基本类 7.4 Java 8 的日期、时间类
- CSS之中间固定两边自适应宽度
- jQuery / zepto ajax 全局默认设置
- win8.1重装系统计算机管理打不开,Windows8计算机打不开192.168.0.1怎么办
- Linux必备命令 - 常用命令集
- 【计量经济学论文】近十年烟台港发展情况的计量分析(节选)
- 专业技能与职业素养报告计算机,学生专业技能与职业素养专题报告怎么写
- 【uniapp 课程表】
- ctDNA早期肿瘤×××基因检测
- (淘宝无限适配)手机端rem布局
- 不得不珍藏的Chrome插件推荐
- CAD中如何布置火灾探测器?消防探测器范围计算
- 主数据治理项目前期调研
- 月盈则亏,水满则溢,欲速则不达,及时止损
- $.extend用法
- python编程的文件后缀是什么意思_编程语言通常有固定的后缀,如golang文件是test.go,Python文件后缀通常定义为以____结尾...
热门文章
- 项目中添加音效--依旧的简单使用
- u3d honey hex framework 代码解读记录(四)
- 兼容big sur的达芬奇后期调色软件
- python创建socket对象_python socket对象内建方法
- Git 安装与卸载 gitk安装与优化
- TensorFlow Object Detection API入门例子 (小浣熊检测下)
- 前有雅迪,后有九号,小牛电动的“智能”故事能动听多久?
- 各种投资产品的整理分析(持续更新)
- typeof NaN的结果是什么?
- 2021-2027全球与中国灭火机器人市场现状及未来发展趋势