5-css+html鼠标悬停tips

本文最后更新于:2021年2月15日 晚上

某2020前端互助群的每周议题(三) Part 2

题目

实现一个鼠标悬停的功能,如图

1606801197639

要求:只使用CSS和HTML

可以贴出代码的实现地址例如https://codepen.io/ 上提交自己的代码

实现

我的实现

思路

1.初步实现

hover后出现文本提示,考虑使用伪元素:after来实现

:after这是css2的写法,css3是::after

<style>
    .wrap {
    }
    .wrap img {
        width: 1em;
        height: 1em;
    }
    .wrap:hover:after {
        content: attr(logo-tip);
        background: #222;
        color: white;

        border-radius: .2em;
        padding: .5em;
        width: 5em;
        opacity: .5;
    }
</style>

<div class="wrap" logo-tip="添加链接啦啦啦啦">
    <img src="https://hexo-1259001110.cos.ap-shanghai.myqcloud.com/link.png">
</div>

初步效果如下,鼠标移上去会出现tip


2.调整位置

接下来调整提示框的位置,修改下布局,采用relative+absolute进行定位

<style>
    .wrap {
        position: relative;
        width: 1em;
        height: 1em;
        margin: 0 auto;
    }
    .wrap img {
        width: 100%;
        height: 100%;
    }
    .wrap:hover:after {
        content: attr(logo-tip);
        background: #222;
        color: white;

        border-radius: .2em;
        padding: .5em;
        width: 5em;
        opacity: .5;

        position: absolute;
        box-sizing: border-box; /* 方便计算宽高 */
        left: calc(50% - 2.5em);
        top: 1.4em;
    }
</style>

<div class="wrap" logo-tip="添加链接啦啦啦啦">
    <img src="https://hexo-1259001110.cos.ap-shanghai.myqcloud.com/link.png">
</div>

效果如下


3.制作小三角形

可以发现,我们实现的框,还少了个三角标,如图

1606805499179

那么,如何制作一个三角标呢?

看看下面这段代码,一个content为2em,border为2em的盒子

<style>
    div {
        background: orange;
        width: 2em;
        height: 2em;
        border: 2em dashed #222;
        border-color: red green #222 pink;
    }
</style>

<div> </div>

效果如下,橙色部分为content,彩色部分是border

1606807307250

看到这里,不知道你悟了没有。如果我把content的宽高设置为0,这样就得到四个三角形,再把border其他三边设置为透明,注释掉背景色,那么就得到一个三角形了。

  • content宽高设置为0:width: 0em; height:0em;

    1606807907331

  • 设置三边透明,去掉背景色

    div {
        /* background: orange; */
        width: 0em;
        height: 0em;
        border: 2em dashed #222;
        border-color: transparent transparent #222 transparent;
    }

    1606808125689

4.合并提示框+小三角形

然后,再把三角形和前面实现的提示框合起来。怎么合并呢?前面我们已经用过了一个伪元素:after,那么这次我们可以使用另一个伪元素:before( css3::before)

最终代码

<style>
    .wrap {
        position: relative;
        width: 1em;
        height: 1em;
        margin: 0 auto;
        cursor: pointer;

    }

    .wrap img {
        width: 100%;
        height: 100%;
    }

    /* 提示框 */
    .wrap:hover:after {
        content: attr(logo-tip);
        background: #222;
        color: white;

        border-radius: .2em;
        padding: .5em;
        width: 5em;
        opacity: .5;

        position: absolute;
        box-sizing: border-box; /* 方便计算宽高 */
        /* '-'运算符两边不加空格属性失效, 这一定是魔法!(原因见下文) */
        left: calc(50% - 2.5em);
        top: 1.4em;
    }

    /* 小三角标 */
    .wrap:hover:before{
        content: "";
        box-sizing: border-box;
        position: absolute;
        top: 1em;
        left: calc(50% - .2em);
        background: linen;
        width: .2em;
        height: .2em;
        border: .2em dashed #222;
        border-color: transparent transparent #222 transparent;
        opacity: .5;
    }
</style>
<div class="wrap" logo-tip="添加链接啦啦啦啦">
    <img src="https://hexo-1259001110.cos.ap-shanghai.myqcloud.com/link.png" alt="">
</div>

效果如下




后记

参考资料

MDN

图标引自阿里巴巴图标矢量库

注意

  1. 对于calc()+-运算符两边没加空格可能导致计算错误。详见MDN calc()

    The + and - operators must be surrounded by whitespace. For instance, calc(50% -8px) will be parsed as a percentage followed by a negative length — an invalid expression — while calc(50% - 8px) is a percentage followed by a subtraction operator and a length. Likewise, calc(8px + -50%) is treated as a length followed by an addition operator and a negative percentage.


  1. 对于attr()详见MDN attr()

    attr() 理论上能用于所有的CSS属性但目前支持的仅有伪元素的 content 属性,其他的属性和高级特性目前是实验性的。

关于美化

直接显示提示框其实有点僵硬,可以考虑使用transition属性来优化过渡。那么问题来了,给伪元素加transition好像很不方便……(额,其实可以的,比如先设置:after,再过渡到:hover:after)

最后我还是实现了,不过为了加这个过渡,多了一些不必要的修改。虽然效果有了,但代码不是很合理,如下。

代码以及演示地址

因为要实现一个过渡效果,因此:before:after必须有一个初始的状态。没错,就是这里刚开始让我觉得很难处理,因为这种情况下的hover似乎有bug。我把两个伪元素的widthheightpadingborder都预置为0,然后position:absolute;定位,在浏览器F12下查看这两个伪元素,很正常,宽高0 × 0,没有占据任何空间。然而,当我把鼠标移动到距离触发hover的区域还有一段距离时,hover就触发了。这很诡异!

虽然暂时不知道为啥,不过解决办法还是有的。直接给.wrap添加overflow: hidden;,然后新增一个:hover

.wrap:hover {
    overflow: visible;
}

道理很简单。直接把超出的内容(目前不清楚是啥,估计就那两个伪元素)给去掉,这样就不会影响:hover的作用范围了。等到触发:hover后再给它显示出来。

问题根源

观察了好一会儿才发现,是伪元素content的问题。即便我把宽高设置为0,文字依旧会显示(overflow的问题),如图。因为原来设置的字体颜色是白色。。所以一直没发现问题…..

在这里插入图片描述

解决

知道问题根源后,解决就很简单了

想到两个办法

  1. .wrap:after添加overflow: hidden;

    演示地址

  2. .wrap:after里设置font-size:0;,在.wrap:after里设置font-size:1em;

    这个改起来也简单,就不搞了


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!