详解CSS实现仿Windows10鼠标照亮边框效果

详解CSS实现仿Windows10鼠标照亮边框效果,第1张

详解CSS实现仿Windows10鼠标照亮边框效果

安装最新 Windows 10 update 之后,注意到系统 UI 里有一个很棒的细节效果,在开始菜单的磁贴里或者 UWP 风格的设置界面中,元素的高亮边框是可以感知鼠标的,边框的高亮部分会跟随鼠标的移动而移动。


顿时灵机一动,这个效果用 CSS 可否实现?

分析

拿桌面日历中的效果为例,鼠标移动时附近的边框也渐变性可见。


这个效果不就是探照灯效果嘛!这个完全可以用 CSS 中的 mask 蒙版配合一个径向渐变实现。


但问题是,mask 蒙版是作用于整个元素的,没办法只作用于 border 而不影响内容。


这个,那只能把 border 和实际内容分离用不同层来表示了。


嗯,鼠标移动就更新蒙版位置,应该不成问题。


实现

准备工作

首先,撸好两层日历格子,一层展示日期信息,一层展示探照灯效果的边框。


用 flex 布局也好,grid 也好,哪怕 inline-block 也都是没有问题的,这都不重要,重要的是上下两层的格子一定要对齐,然后我们用 relative 的容器把这两层 absolute 层圈起来,固定住。


<div class="calendar">
    <div class="calendar-header">
        <div class="week-day">一</div>
        <div class="week-day">二</div>
        <div class="week-day">三</div>
        <div class="week-day">四</div>
        <div class="week-day">五</div>
        <div class="week-day">六</div>
        <div class="week-day">日</div>
    </div>
    <div class="calendar-body">
        <div class="grid-container border-layer">
            <div class="grid-item"></div>
            ...
            <div class="grid-item"></div>
        </div>
            <div class="grid-container number-layer">
            <div class="grid-item"><span>28</span><span>十四</span></div>
            <div class="grid-item"><span>29</span><span>十五</span></div>
            ...
            <div class="grid-item"><span>2</span><span>十九</span></div>
        </div>
    </div>
  </div>

层示意图:

效果就是这样了:

鼠标没有放上去的时候,先把 border 层隐藏掉。


.border-layer {
 ...
  visibility: hidden;
}

.calendar:hover .border-layer {
  visibility: visible;
}

CSS Mask

CSS Mask 类似于 Photoshop 中的图层蒙版,可以使用一张图作为蒙版用作在目标元素上,图片的 alpha 通道(也就是透明度信息)决定了目标元素哪部分可见(也可以选择使用亮度信息)。


举个例子,如果蒙版图片是一张半透明图,则作用到实际元素上效果和设置 opacity: 0.5 效果一样;如果蒙版图片是一张中间镂空的五角星,则效果就是元素被裁剪成五角星形状。


Mask 的语法和 background 的语法几乎完全一致,这里我们用径向渐变创建一个半径 80px 从中心白色到边缘透明的渐变圆,配合 mask-repeat 和 mask-size 防止 repeat 和变形。


-webkit-mask-image: radial-gradient(circle at center, white 0%, transparent 80px);
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: 160px 160px; /* 半径80px 所以 size 需要是 160px */

接下来我们来更新 mask-position 。


这里有两个点要注意,一是获取鼠标对目标元素的相对坐标,一是 position 偏移。


MouseEvent 中有一堆的 X/Y,我们用相对 document 的坐标 pageX/pageY,减去目标元素相对 document 的坐标,就能得到我们需要的坐标了。


向量公式: AB = AC - BC

不过,这里 mask-position 的坐标还需要处理一下。


我们定义的 mask 是一张 160x160 的圆形渐变,而 mask-position 和 background-position 一样,定义的是蒙层左上角 (0,0) 的位置实际需要和容器的哪个坐标对齐。


因此我们需要把计算得到的坐标再减去 (80, 80) 才能让渐变中心和鼠标的坐标保持一致。


var borderLayer = document.querySelector(".border-layer");

document.querySelector(".calendar").addEventListener("mousemove", function(ev){
  var x = ev.pageX;
  var y = ev.pageY;
  var bounding = borderLayer.getBoundingClientRect();
  
  borderLayer.style.webkitMaskPosition = `${x - bounding.x - 80}px ${y -bounding.y - 80}px`;
});

最终效果:https://codepen.io/liuxiaole-the-sasster/full/OGZgpv

后记

把 border 分层然后应用 mask 的方案只能是在特定场合下有效,分离另一个层增加了很多维护成本。


在查阅 MDN 资料的时候,偶然发现居然有个货叫 mask-border ,貌似是作用于 border 的 mask,目前还没有浏览器实现。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/617113.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-04-15
下一篇2022-04-15

发表评论

登录后才能评论

评论列表(0条)

    保存