6.3 弹出层
弹出层(也叫提示条)指的是在鼠标悬停于某个元素之上时显示的一个界面组件。在页面空间有限的情况下,弹出层是为用户提供更多信息的一种有效手段。而且,在用户把鼠标移动到关注的元素之上时,显示一个弹出层也是件自然而然的事儿。乍一听,弹出层不是个太复杂的东西。但是,一会儿你就知道我为什么把它放在本章最后才讲了。围绕创建弹出层,我会跟大家讲两个CSS中非常强大,但又没多少人真正理解的特性:z-index
属性和动态生成HTML元素。我会在接下来的练习中用到三张图片,每张图片都配一个图题。以下就是练习的HTML标记,其中使用了HTML5新增的figure
和figcaption
元素。
<figure>
<img src="images/pink_heels.jpg" alt="pink heels" />
<figcaption>
<h3>Pink Platforms</h3>
<a href="#">More info</a>
</figcaption>
</figure>
<figure class="click_me">
<img src="images/leopard_heels.jpg" alt="leopard heels" />
<figcaption>
<h3>Leopard Platforms</h3>
<a href="#">More info</a>
</figcaption>
</figure>
<figure class="click_me">
<img src="images/red_heels.jpg" alt="red heels" />
<figcaption>
<h3>Red Platforms</h3>
<a href="#">More info</a>
</figcaption>
</figure>
大家注意,如果要使用figcaption
,必须确保它在figure
中是唯一的。而且,它要么是第一个子元素,要么是最后一个子元素。首先,我们设定figure
元素的样式,让它在视觉上成为一个包围图片的盒子。
figure {
width:144px; /*图片盒子宽度*/
height:153px; /*图片盒子高度*/
margin:20px 20px; /*图片盒子间距*/
border:1px solid #666; /*图片边框*/
position:relative; /*为弹出层提供定位上下文*/
float:left; /*让图片并排显示*/
}
img {display:block;} /*去掉图片下方的基线空白*/
图6-20 为图片添加了边框,并且让它们并排显示
如图6-20所示,figure
元素的边框之内恰好能容纳图片,而且浮动也让它们并排显示在一行。figcaption
元素目前就显示在它默认的位置,但下一步它就会变成我们的弹出层。为什么把图片设定为display:block
呢?因为图片默认是行内元素,行内元素的定位原则是与文本基线对齐,而不是与它们容器的底边对齐。在把它们放在块级元素内部时(像这里一样),把图片转换为块级元素可以解决这个问题。另外,这里还把figure
元素设定为相对定位,这样随后就可以把它作为定位上下文来定位figcaption
了,下面就是相应的样式。
figcaption {
display:none; /*隐藏弹出层*/
position:absolute; /*相对于容器(图片)定位*/
left:74%; top:14px; /*把弹出层放到图片右侧*/
width:130px; /*弹出层宽度*/
padding:10px; /*弹出层内边距*/
background:#f2eaea;
border:3px solid red;
border-radius:6px;
}
figure:hover figcaption {display:block;} /*鼠标悬停在图片上时显示弹出层*/
figcaption h3 { /*弹出层的内容*/
font-size:14px;
color:#666;
margin-bottom:6px;
}
figcaption a { /*弹出层的内容*/
display:block;
text-decoration:none;
font-size:12px;
color:#000;
}
这里我们又用到了实现下拉菜单时的技术,即先隐藏弹出层,然后在鼠标悬停时再显示它。为了把弹出层定位在图片盒子的右侧,我们把它的left
属性设定为74%。或许有人认为在这里应该使用right
属性,但那样就是设定图片盒子右边与弹出层右边的相对位置了。
图6-21 鼠标移动图片上时,会在弹出层中显示图题。可是,前两个截图的弹出层被右边的图片给挡住了
6.3.1 堆叠上下文和z-index
从图6-21中的前两个截图来看,前两张图片的弹出层被右边的图片给挡住了一部分。这是由于figure
元素的堆叠次序导致的。在一个包含多个同辈元素的容器内,就像这里body
元素的三个figure
子元素一样,这些同辈元素都会构造一个堆叠上下文。在这个上下文中,它们的子元素会上下堆叠起来。假如通过定位让前两个figure
元素重叠,那么你会发现第一个figure
元素,以及它的堆叠上下文中的所有子元素,都将位于第二个figure
元素的后面。第一个插图的弹出层属于第一个figure
元素的堆叠上下文,因此它默认会在第二个figure
元素的堆叠上下文中所有元素的后面。
CSS中有一个z-index
属性,用于控制元素的在堆叠上下文中的次序。换句话说,通过它可以改变元素堆叠时的默认次序。z-index
值较大的元素,在堆叠层次中位于z-index
值较小的元素上方。z-index
属性的值可以是0到任意大的数值;负值也可以,但在某些浏览器中并不可靠。默认情况下,所有堆叠元素的z-index
的值为auto
,相当于0。
不过,z-index
只对那些position
值为static
之外的元素有效。换句话说,涉及的两个元素必须是absolute
、relative
或fixed
定位才行。在我们的例子中,弹出层已经是绝对定位了,其位置相对于相对定位的figure
元素。所以,只要给弹出层应用大于0的z-index
值,就可以让它们在堆叠中处于最高层。这里,我们把z-index
设定为0。
figure:hover figcaption {display:block; z-index:2;} /*把悬停图片的弹出层放到最前面*/
图6-22 在给弹出层设定了较大的z-index
属性后,它们就能显示在所有图片之前了
这个例子告诉我们,应该只给悬停状态设定z-index
属性,而不要试图通过设定个别元素的z-index
来确保元素不会重叠。只要坚持“悬停时设定z-index
”,你就能放心地摆放图片,而且知道在触发弹出层时,它一定会显示在页面的最前面,如图6-22所示。
6.3.2 用CSS创造三角形
现在,我在考虑怎么让弹出层和图片的关系更加明确。嗯,可以给弹出层左边添加一个三角箭头,让它指向图片。这就涉及利用盒子三角形对接的边框来创建三角形了。下面我用一个div
来演示这个技术。
图6-23 使用宽边框创建三角形
以下是图6-23所示效果的代码。
div {
border:12px solid;
border-color:transparent red transparent transparent;
height:0px;
width:0px;
}
如图6-23所示,通过加宽盒子的边框,将盒子的宽和高都设定为0,同时将其他三个边框设定为transparent
,就可以用CSS造出一个三角形。现在,我把这个技术与::before
伪元素结合起来。大家知道,::before
和::after
这两个伪元素是用于添加文本或图标等少量内容的。不过,完全可以为它们生成的内容设定任何样式,就像给标记中其他元素设定样式一样。在这个例子中,就是要把伪元素生成内容的盒子,通过CSS制作成一个三角形,并把它放到弹出层的左边。
figcaption::after { /*红色三角形的盒子*/
content:""; /*需要有内容,这里是一个空字符串*/
position:absolute; /*相对于弹出层定位*/
border:12px solid;
border-color:transparent red transparent transparent;
right:100%; top:17px; /*相对于盒子边框定位三角形*/
height:0px; width:0px; /*收缩边框创造三角形*/
}
图6-24 一个小三角形,就从视觉上把弹出层和相关图片联系起来了
好了,代码生成的三角形已经被绝对定位到了弹出层左侧,而弹出层本身又相对于图片定位,如图6-24所示。这么20来行CSS,就能显示无数个图片的弹出层! 谁说编程没有创造性来着?要注意的是,::before
伪元素的content
属性中必须有点内容,否则就不能显示生成的元素。因为我们并不真需要什么内容,所以就用一对双引号指定了一个空字符串给它。这个练习好玩吧?肯定比表单好玩多了,是不是?