6.3 弹出层

弹出层(也叫提示条)指的是在鼠标悬停于某个元素之上时显示的一个界面组件。在页面空间有限的情况下,弹出层是为用户提供更多信息的一种有效手段。而且,在用户把鼠标移动到关注的元素之上时,显示一个弹出层也是件自然而然的事儿。乍一听,弹出层不是个太复杂的东西。但是,一会儿你就知道我为什么把它放在本章最后才讲了。围绕创建弹出层,我会跟大家讲两个CSS中非常强大,但又没多少人真正理解的特性:z-index属性和动态生成HTML元素。我会在接下来的练习中用到三张图片,每张图片都配一个图题。以下就是练习的HTML标记,其中使用了HTML5新增的figurefigcaption元素。

  1. <figure>
  2. <img src="images/pink_heels.jpg" alt="pink heels" />
  3. <figcaption>
  4. <h3>Pink Platforms</h3>
  5. <a href="#">More info</a>
  6. </figcaption>
  7. </figure>
  8. <figure class="click_me">
  9. <img src="images/leopard_heels.jpg" alt="leopard heels" />
  10. <figcaption>
  11. <h3>Leopard Platforms</h3>
  12. <a href="#">More info</a>
  13. </figcaption>
  14. </figure>
  15. <figure class="click_me">
  16. <img src="images/red_heels.jpg" alt="red heels" />
  17. <figcaption>
  18. <h3>Red Platforms</h3>
  19. <a href="#">More info</a>
  20. </figcaption>
  21. </figure>

大家注意,如果要使用figcaption,必须确保它在figure中是唯一的。而且,它要么是第一个子元素,要么是最后一个子元素。首先,我们设定figure元素的样式,让它在视觉上成为一个包围图片的盒子。

  1. figure {
  2. width:144px; /*图片盒子宽度*/
  3. height:153px; /*图片盒子高度*/
  4. margin:20px 20px; /*图片盒子间距*/
  5. border:1px solid #666; /*图片边框*/
  6. position:relative; /*为弹出层提供定位上下文*/
  7. float:left; /*让图片并排显示*/
  8. }
  9. img {display:block;} /*去掉图片下方的基线空白*/

enter image description here图6-20 为图片添加了边框,并且让它们并排显示

如图6-20所示,figure元素的边框之内恰好能容纳图片,而且浮动也让它们并排显示在一行。figcaption 元素目前就显示在它默认的位置,但下一步它就会变成我们的弹出层。为什么把图片设定为display:block呢?因为图片默认是行内元素,行内元素的定位原则是与文本基线对齐,而不是与它们容器的底边对齐。在把它们放在块级元素内部时(像这里一样),把图片转换为块级元素可以解决这个问题。另外,这里还把figure元素设定为相对定位,这样随后就可以把它作为定位上下文来定位figcaption了,下面就是相应的样式。

  1. figcaption {
  2. display:none; /*隐藏弹出层*/
  3. position:absolute; /*相对于容器(图片)定位*/
  4. left:74%; top:14px; /*把弹出层放到图片右侧*/
  5. width:130px; /*弹出层宽度*/
  6. padding:10px; /*弹出层内边距*/
  7. background:#f2eaea;
  8. border:3px solid red;
  9. border-radius:6px;
  10. }
  11. figure:hover figcaption {display:block;} /*鼠标悬停在图片上时显示弹出层*/
  12. figcaption h3 { /*弹出层的内容*/
  13. font-size:14px;
  14. color:#666;
  15. margin-bottom:6px;
  16. }
  17. figcaption a { /*弹出层的内容*/
  18. display:block;
  19. text-decoration:none;
  20. font-size:12px;
  21. color:#000;
  22. }

这里我们又用到了实现下拉菜单时的技术,即先隐藏弹出层,然后在鼠标悬停时再显示它。为了把弹出层定位在图片盒子的右侧,我们把它的left属性设定为74%。或许有人认为在这里应该使用right属性,但那样就是设定图片盒子右边与弹出层右边的相对位置了。

enter image description here图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之外的元素有效。换句话说,涉及的两个元素必须是absoluterelativefixed定位才行。在我们的例子中,弹出层已经是绝对定位了,其位置相对于相对定位的figure元素。所以,只要给弹出层应用大于0的z-index值,就可以让它们在堆叠中处于最高层。这里,我们把z-index设定为0。

  1. figure:hover figcaption {display:block; z-index:2;} /*把悬停图片的弹出层放到最前面*/

enter image description here图6-22 在给弹出层设定了较大的z-index属性后,它们就能显示在所有图片之前了

这个例子告诉我们,应该只给悬停状态设定z-index属性,而不要试图通过设定个别元素的z-index来确保元素不会重叠。只要坚持“悬停时设定z-index”,你就能放心地摆放图片,而且知道在触发弹出层时,它一定会显示在页面的最前面,如图6-22所示。

6.3.2 用CSS创造三角形

现在,我在考虑怎么让弹出层和图片的关系更加明确。嗯,可以给弹出层左边添加一个三角箭头,让它指向图片。这就涉及利用盒子三角形对接的边框来创建三角形了。下面我用一个div来演示这个技术。

enter image description here图6-23 使用宽边框创建三角形

以下是图6-23所示效果的代码。

  1. div {
  2. border:12px solid;
  3. border-color:transparent red transparent transparent;
  4. height:0px;
  5. width:0px;
  6. }

如图6-23所示,通过加宽盒子的边框,将盒子的宽和高都设定为0,同时将其他三个边框设定为transparent,就可以用CSS造出一个三角形。现在,我把这个技术与::before伪元素结合起来。大家知道,::before::after这两个伪元素是用于添加文本或图标等少量内容的。不过,完全可以为它们生成的内容设定任何样式,就像给标记中其他元素设定样式一样。在这个例子中,就是要把伪元素生成内容的盒子,通过CSS制作成一个三角形,并把它放到弹出层的左边。

  1. figcaption::after { /*红色三角形的盒子*/
  2. content:""; /*需要有内容,这里是一个空字符串*/
  3. position:absolute; /*相对于弹出层定位*/
  4. border:12px solid;
  5. border-color:transparent red transparent transparent;
  6. right:100%; top:17px; /*相对于盒子边框定位三角形*/
  7. height:0px; width:0px; /*收缩边框创造三角形*/
  8. }

enter image description here图6-24 一个小三角形,就从视觉上把弹出层和相关图片联系起来了

好了,代码生成的三角形已经被绝对定位到了弹出层左侧,而弹出层本身又相对于图片定位,如图6-24所示。这么20来行CSS,就能显示无数个图片的弹出层! 谁说编程没有创造性来着?要注意的是,::before伪元素的content属性中必须有点内容,否则就不能显示生成的元素。因为我们并不真需要什么内容,所以就用一对双引号指定了一个空字符串给它。这个练习好玩吧?肯定比表单好玩多了,是不是?