资讯专栏INFORMATION COLUMN

CSS遮罩层:hover状态丢失及解决方案

Steven / 1242人阅读

摘要:在时,亦可进一步改变该遮罩层的色彩和透明度。遮罩层实现及状态丢失问题代码代码在时,如果快速点击鼠标,可能会丢失的效果。状态丢失的简单解决方案基本思路是,点击鼠标时给添加,强制它显示里的样式。

CSS遮罩层,顾名思义就是在div上,再“铺”一层半透明的div。在hover时,亦可进一步改变该遮罩层的色彩和透明度。我们可以通过css定位和背景色实现。

CSS遮罩层实现及hover状态丢失问题

CSS代码:

 .block {
            position: relative; 
            top: 100px;
            left: 100px;
            display: inline-block;
            width: 300px;
            border-radius: 4px;
            border:1px solid ;
        }

        .block__overlay {
            position: absolute;
            top:0;
            left:0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, .3);
        }

        .block:hover .block__overlay {
            background-color: rgba(100, 200, 0, .5);
        }

Html代码:

在Mouse hover时,如果快速点击鼠标,可能会丢失mouse hover的效果。这在windows上的浏览器经常出现,造成"闪烁"。虽然在macbook上出现的时候很少。

解决方案:点击鼠标时,添加isActive 样式,强制显示"hover"里的样式。等mouse out时,去掉isActive class。

普通状态下的效果:

鼠标Hover时的效果图:

问题是,在鼠标hover的时候多次快速点击鼠标,会导致hover状态失效。这个问题在windows的浏览器(包括windows版本的Chrome, FireFox)时常发生,尽管在macOs的各种浏览器挺少发生。

Hover状态丢失的简单解决方案

基本思路是,点击鼠标时给.block添加isActive class,强制它显示Hover里的样式。在鼠标不断点击以致于丢失hover时,也会因为添加了isActive class而照样显示hover里的样式。

/*.isActive 拥有:hover相同的样式*/
  .block:hover .block__overlay,
        .block.isActive .block__overlay {
            background-color: rgba(100, 200, 0, .5);
        }

JS文件:

    var block = document.getElementsByClassName("block")[0];
    block.addEventListener("mouseout", function (evt) {
        // mouse hover时,不断地快速点击鼠标,可能会触发mouseout事件,尽管并不是真正将鼠标move out了。
        // 这里通过offsetX,offsetY来判断鼠标的位置,是否真正还在.block内
        if (evt.offsetX <= 0 || evt.offsetY <= 0 || evt.offsetX >= block.offsetWidth || evt.offsetY >= block.offsetHeight) {
            console.log("Really moved out");
            if (this.classList.contains("isActive")) {
                this.classList.remove("isActive");
            }
        }
    }, false);

    block.addEventListener("click", function (evt) {
        if (!this.classList.contains("isActive")) {
            this.classList.add("isActive");
        }
    }, false);
Hover状态丢失的通用解决方案

若.block里有多个定位元素,鼠标在子元素内部向上移动时,虽然鼠标可能依旧在.block内部,但是evt.offsetY可能是负数。依照上述简单方案判断结果是,鼠标在.block外部,就不对了。为此我们需要一种通用的方案。

以下图效果举例。我们在.block里添加一个红色⭕️和对勾

CSS代码较多,请参考:https://github.com/JackieGe/a...

摘出HTML代码:可以看到添加了block__circle.

在鼠标从红色圆圈向上移动到圆圈外部 但仍在.block内时, offsetY是小于0的。 如果依旧应用简单方案里的js,就会错误地得出鼠标在.block外的结论。
为此我们使用toElement属性,它表示mouse移动到哪个元素。如果该元素是.block的子孙元素,我们就认为鼠标还在.block内。FireFox的event没有toElement属性,我们用getToElement函数解决。

 function getToElement(evt) {
        var node;
        if (evt.type == "mouseout") {
            node = evt.relatedTarget;
        } else if (evt.type == "mouseover") {
            node = evt.target;
        }

        if (!node) {
            return;
        }

        while (node.nodeType != 1) {
            node = node.parentNode;
        }
        return node;
    }

    var findElement = (function(){
        var found = false;

        function doFindElement(target, scope) {
            if (!found && scope && scope.childElementCount > 0) {
                for (var i=0; i< scope.childElementCount; i++) {
                    var child = scope.children[i];
                    if (target == child) {
                        found = true;
                        return;
                    } else if (child.childElementCount > 0) {
                        doFindElement(target, child, found)
                    }
                }
            }
        }

        return function (target, scope) {
            found = false;
            doFindElement(target, scope);
            return found;
        };
    })();

    var block = document.getElementsByClassName("block")[0];
    block.addEventListener("mouseout", function (evt) {

        var toElement = evt.toElement || getToElement(evt) || evt.srcElement;
        if (toElement == this || findElement(toElement, this)) {
            console.log("Does NOT really move out");
        } else {
            console.log("Really moved out");
            if (this.classList.contains("isActive")) {
                this.classList.remove("isActive");
            }
        }

        /***
         * The below code: the old way no long works correctly, because offsetX, offsetY rely on fromElement.
         * When mouse move up direction out of "circle", the OffsetY could be negative, but mouse
         * is still inside the outermost .block.
         */

        /*
        if (evt.offsetX <= 0 || evt.offsetY <= 0 || evt.offsetX >= block.offsetWidth || evt.offsetY >= block.offsetHeight) {
            console.log("OLD way: Really moved out");
            if (this.classList.contains("isActive")) {
                this.classList.remove("isActive");
            }
        } else {
            console.log("OLD way: Doest NOT move out");
        }*/

    }, false);

    block.addEventListener("click", function (evt) {
        if (!this.classList.contains("isActive")) {
            this.classList.add("isActive");
        }
    }, false);

控制台查看鼠标点击.block div后的class:

鼠标移走之后,.block div的class:

总结

本文介绍了CSS遮罩的简单实现,以及在鼠标点击.block时如何保持遮罩层的hover 状态。具体代码可查看 https://github.com/JackieGe/a...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/112420.html

相关文章

  • CSS罩层hover状态丢失解决方案

    摘要:在时,亦可进一步改变该遮罩层的色彩和透明度。遮罩层实现及状态丢失问题代码代码在时,如果快速点击鼠标,可能会丢失的效果。状态丢失的简单解决方案基本思路是,点击鼠标时给添加,强制它显示里的样式。 CSS遮罩层,顾名思义就是在div上,再铺一层半透明的div。在hover时,亦可进一步改变该遮罩层的色彩和透明度。我们可以通过css定位和背景色实现。 CSS遮罩层实现及hover状态丢失问题 ...

    vincent_xyb 评论0 收藏0
  • 支持多框架的组件库KPC 1.0正式发布

    摘要:自从年月份对外公布以来,已经经过了个月的迭代,期间发布了几十个正式版本,但一直没有到,因为我们觉得是个里程碑版本,我们必须做的足够完善才敢称之为。 自从17年11月份对外公布以来,KPC已经经过了8个月的迭代,期间发布了几十个正式版本,但一直没有到1.0,因为我们觉得1.0是个里程碑版本,我们必须做的足够完善才敢称之为1.0。而如今我们有信心对外宣布:KPC 1.0终于来了! 其实距离...

    刘厚水 评论0 收藏0
  • 支持多框架的组件库KPC 1.0正式发布

    摘要:自从年月份对外公布以来,已经经过了个月的迭代,期间发布了几十个正式版本,但一直没有到,因为我们觉得是个里程碑版本,我们必须做的足够完善才敢称之为。 自从17年11月份对外公布以来,KPC已经经过了8个月的迭代,期间发布了几十个正式版本,但一直没有到1.0,因为我们觉得1.0是个里程碑版本,我们必须做的足够完善才敢称之为1.0。而如今我们有信心对外宣布:KPC 1.0终于来了! 其实距离...

    Cheng_Gang 评论0 收藏0
  • HTML 练习实现罩层

    Title .left{ float: left; } .clearfix:after{ content: .; display: block; clear: both; visibility: hidden; ...

    harriszh 评论0 收藏0
  • 2017-08-20 前端日报

    摘要:前端日报精选数组所有全解密原生实现最简单的图片懒加载译如何抓取数据中种常见的内存泄露陷阱内部原理,第一部分基础渲染前端国际化中文深入理解笔记模块掘金译热的冷的掘金模块,桌面端的支付请求,和迷津欲有问遮罩层状态丢失及解决方案全 2017-08-20 前端日报 精选 JavaScript数组所有API全解密原生JS实现最简单的图片懒加载【译】React如何抓取数据JavaScript 中 ...

    molyzzx 评论0 收藏0

发表评论

0条评论

Steven

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<