转载:使⽤CSScontent的attr实现⿏标悬浮提⽰(tooltip)效果原⽂:segmentfault/p/1210000018125552/read#top
当你的⽤户需要漂亮的图标给出额外的⽂字信息时,亦或是当他们在点击了按钮之后需要确认⾃⼰没点错时,⼜或是带图⽚和字幕的复活节彩蛋,提⽰框是⽤来增强⽤户界⾯的绝佳⼿段。现在,让我们来做⼏个动画提⽰框,没有别的,只有HTML和CSS。
样例
这是我们之后要做的:
See the Pen by xianzhiding () on .
在我们沉浸在写代码的过程中之前,让我们先来看看我们的意图是什么。主要⽬的是为了获得⼀种简单的添加提⽰框的⽅法,这样⼀来,我们之后就能够通过增加⼀个⾃定义的 tooltip 属性来做到这⼀点。
<span tooltip="message">visible text or icon, etc.</span>
让我们设定⼏个预期
不需要JavaScript
我们将会使⽤属性选择器(⽽不是类名),以及CSS内建的模式匹配
加到现有的DOM元素(你的标签中不需要新的元素)
代码例⼦中是没有前缀的(如有需要,为你的⽬标浏览器加上供应商前缀)
假设通过 mouseover/hover 来触发提⽰框
仅仅是纯⽂本提⽰框(HTML,图⽚等等都不⽀持)
当唤起提⽰框时,有巧妙的动画
好了,⽼司机要开车了!
哦,等等。我们还要先处理⼀个问题,是关于”不需要额外标签”的。毕竟,这很巧妙。我们的提⽰框真的不需要额外的DOM元素,因为它们完全是基于伪元素的(::before 和 ::after),我们可以通过CSS来控制。
如果你已经在其它样式集中使⽤了⼀个元素的伪元素,⼜希望在这个元素是加⼀个提⽰框,那么你可能需要稍稍做⼀些重构。
没什么⽐得上来⼀场提⽰框盛会了!
等等。⼩坏蛋!还有⼀个警告:CSS定位。为了提⽰框正常运作,它们的⽗元素(我们把提⽰框添加在它后⾯)需要是position: relative,或者
position: absolute,或
position: fixed
基本上,什么都⾏,只要不是 position: static — 这是浏览器赋给⼏乎所有元素的默认定位模式。提⽰框是绝对定位的,所以它们需要知道它们的绝对值在什么边界内是有意义的。默认的定位指令 static 不会声明它的边界,也不会给我们的提⽰框以上下⽂来进⾏相对定位。所以提⽰框会使⽤之后,最近的,有声明边界的⽗元素。
你还需要根据你如何使⽤提⽰框来决定哪个定位指令最为合适。这篇教程假设⽗元素是 postion: relative 如果你的UI依靠⼀个绝对定位的元素,那么在那个元素上部署⼀个提⽰框,也会需要⼀些重构(额外的标签)。
让我们开始吧。
属性选择器:快速回顾
⼤多数CSS规则印象中都是⽤类名写的,⽐如 .this-thing ,但是CSS有⼏个类型的选择器。我们巧妙的提⽰框打算使⽤属性选择器——也就是⽅括号表⽰法。
[foo] {
background: rgba(0, 0, 0, 0.8);
color: #fff;
}
当浏览器看到诸如此类的东西时:
<span foo>Check it out!</span>
浏览器会知道,它需要应⽤ [foo] 规则了,因为 <span> 标签有⼀个叫做 foo 的属性。在这个例⼦中,span⾃⾝会有⼀个半透明的⿊⾊背景,以及⽩⾊⽂字。
HTML元素有着各种各样的内置属性,但是我们也可以给出我们⾃⼰的属性。⽐如 foo ,⼜或者是 tooltip 。默认情况下,HTML不知道这些东西是什么意思,但是有了CSS,我们可以告诉HTML这些⾃定义属性是什么意思。
为什么⽤属性选择器?
我们后⾯会使⽤属性选择器,主要是出于侧重分离的⽬的。使⽤属性⽽不是类名,并不会让我们在详细程度上获得更多益处,类和属性在详细程度上是相同的。然⽽,通过使⽤属性,我们可以把我们的内容放在⼀块⼉,因为HTML属性可以有值,⽽类名没有值。
在这个例⼦的代码中,来权衡⼀下类名 .tooltip 对⽐属性 [tooltip] 。类名是 [class] 属性的值中的⼀个,⽽tooltip属性可以存放⼀个值,它就是我们要显⽰的⽂字。
<span class="tooltip another-classname">lorem ipsum</span>
<span tooltip="sit dolar amet">lorem ipsum</span>
现在让我们来看看提⽰框炼⾦术
我们的提⽰框会使⽤两种不同的属性:
tooltip: 这个属性存放了提⽰框的内容(⼀个纯⽂本字符串)
flow: 可选;这个属性允许我们控制如何显⽰提⽰框。我们可以⽀持很多⽅位,但是我们会覆盖4各常⽤⽅位:
上,左,右,下
现在,让我们为所有的提⽰框做好准备⼯作。步骤1-5的规则会应⽤到所有的提⽰框上,⽆论我们给 flow 属性什么值。步骤6-7对于不同的flow 值会有所区分。
1. 相对性
这是⽤在提⽰框的⽗元素上的。让我们来给定⼀个定位指令,这样提⽰框的组成部分(即::before 和 ::after 伪元素)的绝对定位就可以以⽗元素做参照进⾏定位,⽽不是以整个页⾯或祖⽗元素或DOM树上⽅的其它外围元素作为参照进⾏定位。
[tooltip] {
position: relative;
}
2. 伪元素准备时间
是时候准备伪元素了。在这⾥,我们要对 ::before 和 ::after 设置常⽤属性。content 属性是真正让伪元素⼯作的属性,不过我们稍后再讨论它。
[tooltip]::before,
[tooltip]::after {
line-height: 1;
user-select: none;
pointer-events: none;
position: absolute;
display: none;
opacity: 0;
/* opinions */
text-transform: none;
font-size: .9em;
}
3. 丁克帽
我不知道丁克帽是不是说得通,我只是⼀直这么叫它。它是⼀个尖尖的⼩三⾓形,通过指向它的调⽤者,为提⽰框提供对话⽓泡的感觉。注意到我们在边界颜⾊这⼀块,使⽤了 tranparent ;由于上⾊要根据提⽰框的 flow 值来,所以之后再加上颜⾊。
[tooltip]::before {
content: '';
z-index: 1001;
border: 5px solid transparent;
}
content: ”;声明中的值是⼀个空字符串,这并不是笔误。字符串⾥⾯,我们不想要任何东西,但是我们需要这个属性,使得伪元素得以存在。
为了⽣成⼀个三⾓形,我们定义了⼀个实现边框,在空的盒⼦(没有内容)上加了⼀些厚度,⽽不设定盒⼦的宽度和⾼度,仅仅对盒⼦的每⼀条边都给⼀个边框颜⾊。
4. ⽓泡!
这⾥是重点了。注意到 content: attr(tooltip) 这⼀部分是说:“这个伪类应该使⽤ tooltip 属性的值作为这个伪类的内容。”这也是为什么使⽤属性⽽不是类名会这么赞的原因。
[tooltip]::after {
content: attr(tooltip); /* magic! */
z-index: 1000;
/* most of the rest of this is opinion */
font-family: Helvetica, sans-serif;
text-align: center;
/*
Let the content set the size of the tooltips
but this will also keep them from being obnoxious
*/
min-width: 3em;
max-width: 21em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
/* visible design of the tooltip bubbles */
padding: 1ch 1.5ch;
border-radius: .3ch;
box-shadow: 0 1em 2em -.5em rgba(0, 0, 0, 0.35);
background: #333;
color: #fff;
}
注意看丁克帽和⽓泡的 z-index 值。这些值可以是任意的。但是要记住,z-index 值是相对的。解释:⼀个z-index值为1001的元素,在⼀个z-index为3的元素内部。仅仅意味着,z-index: 3 容器内部,1001元素是最顶层的元素。
⽓泡的z-index应该⾄少⽐丁克帽的z-index低⼀档。如果它和丁克的⼀样⾼,或更⾼的话,如果你提⽰框使⽤了 box-shadow 的话,结果在丁克帽上回得到不⼀致的颜⾊效果。
5. 交互动作
我们的提⽰框是通过把⿏标移动到带提⽰框的元素上⾯,来激活的。差不多是这样。
[tooltip]:hover::before,
[tooltip]:hover::after {
display: block;
}
如果你回顾在第2不中的样式部分,你会看到我们对提⽰框的组成部分,使⽤了 opacity: 0; 以及 display: none; 。我们这么做是为了当提⽰框显⽰和隐藏时,可以使⽤CSS动画效果。
display属性是不能做成动画的,但是opacity属性可以!我们留到最后来处理动画的问题。如果你对动画提⽰框没兴趣,只要把第2步中的opacity: 0; 删掉,⽆视第7步即可。
最后⼀件要应⽤到所有提⽰框上的是,如果提⽰框没有内容,能有⼀个⽅法来抑制提⽰框。如果你使⽤某种动态系统(Vue.js, Angular, 或者 React, PHP等等)来⽣成提⽰框的话,我们就不需要笨笨的空⽩⽓泡了!
/* don't show empty tooltips */
[tooltip='']::before,
[tooltip='']::after {
display: none !important;
}
6. 流控制
这⼀步会变得更加复杂,因为我们会使⽤⼀些不那么常见的选择器,来帮助我们的提⽰框基于 flow 值(或没有flow属性)来确定位置。
在我们写样式之前,让我们看看将要⽤到⼀些选择器模式。
[tooltip]:not([flow])::before,
[tooltip][flow^="up"]::before {
/* ...
properties: values
... */
}
这是在告诉浏览器:“对于所有带有 tooltip 属性来说,其中没有 flow 属性的元素,或者有flow元素,但它的值是以’up’开头的:将这些样式套⽤到这类元素的::before伪元素上。”
我们在这⾥使⽤了⼀个模式,这样⼀来,这些东西可以扩展到其它流上,⽽步需要重复这么多的CSS。这个模式 flow^=”up” 使⽤了 ^= (开头)匹配符。如果你想增加其它流控制的话,通过这个模式,也可以将样式应⽤在 up-right 和 up-left ⽅向上(代码中)。我们在这⾥不会讨论这些流控制,不过你可以在CodePen上,我原来的提⽰框演⽰中看到如何使⽤它们。
以下是教程中所讲到的4个流所对应的CSS代码块。
上(这是默认的⽅向)
/* ONLY the ::before */
[tooltip]:not([flow])::before,
[tooltip][flow^="up"]::before {
bottom: 100%;
border-bottom-width: 0;
border-top-color: #333;
}
/* ONLY the ::after */
[tooltip]:not([flow])::after,
[tooltip][flow^="up"]::after {
bottom: calc(100% + 5px);
}
/* Both ::before & ::after */
[tooltip]:not([flow])::before,
[tooltip]:not([flow])::after,
[tooltip][flow^="up"]::before,
[tooltip][flow^="up"]::after {
left: 50%;
transform: translate(-50%, -.5em);
}
下:
[tooltip][flow^="down"]::before {
top: 100%;
css 属性选择器
border-top-width: 0;
border-bottom-color: #333;
}
[tooltip][flow^="down"]::after {
top: calc(100% + 5px);
}
[tooltip][flow^="down"]::before, [tooltip][flow^="down"]::after {
left: 50%;
transform: translate(-50%, .5em);
}
左:
[tooltip][flow^="left"]::before {
top: 50%;
border-right-width: 0;
border-left-color: #333;
left: calc(0em - 5px);
transform: translate(-.5em, -50%);
}
[tooltip][flow^="left"]::after {
top: 50%;
right: calc(100% + 5px);
transform: translate(-.5em, -50%);
}
右:
[tooltip][flow^="right"]::before {
top: 50%;
border-left-width: 0;
border-right-color: #333;
right: calc(0em - 5px);
transform: translate(.5em, -50%);
}
[tooltip][flow^="right"]::after {
top: 50%;
left: calc(100% + 5px);
transform: translate(.5em, -50%);
}
7. 让⼀切都动起来
动画是很神奇的。动画可以做到:
让⽤户感觉舒服
让⽤户感受到你的⽤户界⾯的空间感注意到该看到的东西
让⽤户界⾯中本来⾮⿊即⽩的⽣硬效果变得柔和
我们的提⽰框属于最后那⼀种。如果仅仅是让⼀个⽂字泡泡出现然后突然消失,效果是不令⼈满意的,我们可以让它更柔和⼀些。
关键帧 (@keyframes)
我们需要两个关键帧 (@keyframe) 动画。向上/向下提⽰框要⽤到tooltips-vert关键帧,⽽向左/向右提⽰框使⽤tooltips-horz关键帧。注意,在这些关键帧中,我们只定义了提⽰框所需的终⽌状态。我们并不需要知道它们从何处来 (提⽰框本⾝就有状态信息)。我们只想控制它们要到哪⼉去。
@keyframes tooltips-vert {
to {
opacity: .9;
transform: translate(-50%, 0);
}
}
@keyframes tooltips-horz {
to {
opacity: .9;
transform: translate(0, -50%);
}
}
现在,当⼀个⽤户的⿏标移到触发元素 (具有[tooltip]属性的元素) 上时,我们需要将这些关键帧应⽤到提⽰框上。因为我们采⽤了不同的流来控制提⽰框的显⽰⽅式,我们需要在样式中对它们进⾏定义。
使⽤:hover将控制传递给动画
[tooltip]:not([flow]):hover::before,
[tooltip]:not([flow]):hover::after,
[tooltip][flow^="up"]:hover::before,
[tooltip][flow^="up"]:hover::after,
[tooltip][flow^="down"]:hover::before,
[tooltip][flow^="down"]:hover::after {
animation:
tooltips-vert
300ms
ease-out
forwards;
}
[tooltip][flow^="left"]:hover::before,
[tooltip][flow^="left"]:hover::after,
[tooltip][flow^="right"]:hover::before,
[tooltip][flow^="right"]:hover::after {
animation:
tooltips-horz
300ms
ease-out
forwards;
}
我们不能对display属性进⾏动画,但是可以通过操作opacity属性,在提⽰框上加上淡⼊效果。我们也可以动画transform属性,它可以给提⽰框加上微妙的动作,触发的元素就像飞⼊某点的⼀样。
主要forward关键词在动画的声明中,这告诉动画当完成时不重置,⽽是继续停留在结束。
棒极了!我们在这个教程⾥已经覆盖了很多,⼀堆提⽰框效果。
我们仅仅摸索了⽤css做提⽰框的表⾯。好好享受它们,继续试验,调制出你⾃⼰的⽅⼦!
© 著作权归原作者所有

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。