前端必修技能:高手进阶核心知识分享 - css盒的before、after和子元素的层叠关系解析及应用

时间:2024-10-06 07:02:57

早在十几二十年前,我最开始接触CSS的时候,根本没听说过 before 和 after ,那时候公司的浏览器更新到了IE8,我那个老古董的WINXP系统的浏览器升级到IE7,市面上甚至大部分电脑的浏览器还都是IE6。那时候每次做页面 ,最头疼的就是各个浏览器的兼容问题。甚至公司专门请了个人坐在两台电脑前,装了各个品牌,各个版本的浏览器,在那不停的刷我们的项目。现在好了,浏览器兼容问题越来越少了,跨平台成为前端要解决的新的高峰。学习的氛围越来越好,国内的高手大神们也越来越多了,但要学的技术也越来越多了。。。CSS都从原来那么简陋的玩意儿,变成现在可以写动画的浏览器前端利器,甚至能解决一部分原来必须JS才能解决的问题。唉。。老了。

话题扯远了,这篇文章呢,主要是分享一下关于 ::before、::after 和 子元素的层叠关系 以及 这几种元素结合的应用。

前端必修技能:高手进阶核心知识分享 - css盒的before、after和子元素的层叠关系解析及应用

CSS层叠由来

在前端的世界里,浏览器不应该是平面的。它不但有X轴(水平方向),有Y轴(竖直方向),它还有个Z轴(垂直方向:我们的视线与浏览器平面的垂直方向)。你必须能够理解这个方向,才能合理而熟练的利用它(层叠的关系),制作出精美的页面和漂亮的动画。

Z轴的存在,就引申出 一个问题:各元素之间 距离 观察者 谁近谁远的 问题:---- 上下文堆叠顺序 (stack contex)。CSS的中文全称叫什么来着:层叠样式表。没错,CSS本来就为了解决HTML各个标签之间的层叠关系和样式表现而诞生的。

HTML页面中的各个标签,从书写角度上看,存在这两种关系。一种是顺序(层叠),一种是嵌套。那么它们在浏览器解析的时候,如果不发生位置的重叠,全部排开铺在网页上,这个情况是好解决的。但是,如果,需要位置重叠时候,谁在前(上)面,谁又在后(下)面呢?顺序排列的几个标签,如何叠放?嵌套的标签,又如何显示? 什么又是 伪元素 ::before 和::after 呢?

伪元素::before 和 ::after

 ::before和::after:::before表示元素的开始,::after表示元素的最后,before和after必须结合content属性来使用。

特别需要注意的是:单标签 不支持伪元素 ::before 和 ::after ..

代码示例:

  1. <style>
  2. p::after{
  3. content: "hahaha";
  4. color: red;
  5. }
  6. p::before{
  7. content: "hehehe";
  8. color: coral;
  9. }
  10. </style>

层叠解析

我们来看一个HTML的结构的例子:

  1. <div class="father">
  2. <div class="child-1"></div>
  3. <div class="child-2"></div>
  4. </div>

在这个例子里,很明显的 div元素father 作为父级,与它的 子元素 div元素 child-1 和 child-2 就是嵌套关系。而两个子元素之间,就是层叠关系。那么我们在不改变他们的定位关系(postion)和Z轴层级(z-index)的前提下,看看他们是如何在浏览器中表现的:

  1. /* css */
  2. .father {
  3. position: relative;
  4. height: 400px;
  5. width: 400px;
  6. background: #ddd;
  7. color: #fff;
  8. }
  9. .father::before {
  10. content: "before";
  11. width: 100px;
  12. height: 100px;
  13. background: blue;
  14. }
  15. .father::after {
  16. content: "after";
  17. width: 100px;
  18. height: 100px;
  19. background: orange;
  20. /* transform: translate(60px,-240px); */
  21. }
  22. .child-1 {
  23. display: block;
  24. height: 100px;
  25. width: 100px;
  26. background: green;
  27. /* transform: translate(20px,-80px); */
  28. }
  29. .child-2 {
  30. display: block;
  31. height: 100px;
  32. width: 100px;
  33. background: purple;
  34. /* transform: translate(40px,-160px); */
  35. }

首先,我们看看不做任何位移时,father元素的 ::before ::after 和它的两个子元素 child-1 child-2的 展示方式。刷新浏览器:

接下来,我们给子元素进行位移,不移动befoer和after,看看它们如何排列:

  1. .father::before {
  2. content: "before";
  3. display: block;
  4. width: 100px;
  5. height: 100px;
  6. background: blue;
  7. }
  8. .father::after {
  9. content: "after";
  10. display: block;
  11. width: 100px;
  12. height: 100px;
  13. background: orange;
  14. /* transform: translate(60px,-240px); */
  15. }
  16. .child-1 {
  17. display: block;
  18. height: 100px;
  19. width: 100px;
  20. background: green;
  21. transform: translate(20px,-80px);
  22. }
  23. .child-2 {
  24. display: block;
  25. height: 100px;
  26. width: 100px;
  27. background: purple;
  28. transform: translate(40px,-160px);
  29. }

可以清晰的看到,child-1 和child-2 两个子元素发生了位移。但是,奇妙的事情发生了: after 层居然。。。就依然还在它原来的位置。它居然没有移动上去。这是为什么呢?

因为child-1 和child-2 的位移是用 transform: translate() 实现的,浏览器先在原位置渲染了每个div元素,也渲染了after和before层,然后让两个子元素发生了位移,但它们占位并没有消失。所以,它的位置在页面渲染时候就决定了,不会再改变。

接下来,我们给after也进行位移:

  1. .father::after {
  2. content: "after";
  3. display: block;
  4. width: 100px;
  5. height: 100px;
  6. background: orange;
  7. transform: translate(60px,-240px);
  8. }

这时候,我们就可以看到 father元素,和它的伪元素before,after ,与它的两个子元素之间的层叠关系了。

解析总结:

盒子在默认情况下,也就是没有设置Z-index的情况下:

  1. 一个盒子 它的 ::before伪类在最底层, ::after 伪元素在最上层, 其所有子元素在中间叠放。
  2. 盒子的 子元素堆叠关系,按照书写顺序自下而上排序:先写的叠放在下面,后写的在上面。
  3. 父元素在最下面。

应用案例

要应用伪元素::after 和 :: before,就必须用 content属性。关于content,我们必须知道:

content 属性 是 CSS 中一个非常有用的属性,可以用于插入生成内容,如在 ::before 和 ::after 伪元素中添加文本或图标。

  1. content 属性仅可用于 ::before 和 ::after 伪元素上,不能用于其他元素上。
  2. content属性值可以是字符串、特殊字符、URL、计数器等,常用的字符串值包括文字、图标等等。
  3. content属性不仅可以用于显示内容,也可以用于控制生成内容的样式和行为。
  4. content属性的值可以是动态的,比如可以使用 attr() 函数将元素的属性值作为伪元素内容。
  5. content属性可以与 :before 和 :after 伪元素的其他样式属性结合使用,比如 display、position、padding、border、background 等等。
  6. content 属性的值在页面上不会被选中、复制、粘贴,也不会对文档结构产生影响,仅仅是对生成的内容进行控制和定制。
  7. content 属性的使用可以让开发者在不改变 HTML 结构的情况下添加或修改一些内容,从而实现一些特殊的效果和功能。

基于上述介绍,我们接下来展示的案例,都是利用 content来实现的。

添加装饰性内容

html代码如下:

  1. <blockquote>我是被引用的内容!</blockquote>
  2. <br>
  3. <blockquote class="new_quote">我是被引用的内容!</blockquote>

CSS代码如下:

  1. /* 1. 添加装饰性内容 */
  2. /* 默认的样式 */
  3. blockquote{
  4. text-align: left;
  5. font-size: 2rem;
  6. }
  7. blockquote:before {
  8. content: open-quote;
  9. font-size: larger;
  10. color: #666;
  11. }
  12. blockquote:after {
  13. content: close-quote;
  14. }
  15. /* 1.1 配合guote属性,可以设置嵌套引用的引号类型。 */
  16. .new_quote{
  17. quotes: "<" ">";
  18. }

结果:

那么,肯定不止有这么几个符号可以被引用,所有可以引用的引号字符可以参考下面表格:

效果

说明

实体编号

"

双引号

"

'

单引号

'

单一的左尖括号

单一的右尖括号

«

双的左尖括号

«

»

双的右尖括号

»

'

左引号(单 high-6)

'

右引号(单 high-9)

"

左引号(双 high-6)

"

右引号(双 high-9)

双引号 (双 low-9)

在列表前(后)增加自定义图标

HTML代码如下:

  1. <ul>
  2. <li>我是一个列表项</li>
  3. <li>我也是一个列表项</li>
  4. <li class="completed">我也还是一个列表项</li>
  5. </ul>

CSS代码如下:

  1. /* 2. 在列表前(后)增加自定义图标 */
  2. ul{
  3. list-style: none;
  4. }
  5. li{
  6. width: 100%;
  7. margin: 4px 0px;
  8. display: block;
  9. text-align: left;
  10. padding: 5px 10px;
  11. height: 20px;
  12. }
  13. li.completed:after {
  14. content: "\2713"; /* Unicode 字符:对勾 */
  15. color: green;
  16. font-size: 0.8em;
  17. vertical-align: super;
  18. }

刷新结果:

用于引用媒体文件

还是用上面的HTML文件,我们稍微增加一些CSS:

  1. li:before {
  2. display:inline-block;
  3. content: url();
  4. background: #fcc;
  5. width: 12px;
  6. height: 12px;
  7. overflow: hidden;
  8. padding-left: 20px;
  9. margin-right: 5px;
  10. }

注意:

1)URL不能使用引号。如果你将URL用引号括起来,那么它会变成一个字符串和插入文本“url()”作为其内容,插入的而不是图像本身。

2)content属性,直接使用图片,即使写width,height也无法改变图片大小; */

看效果:

序号自动增加排序的UL列表

这是一个content属性 结合 计数器 实现的效果。

CSS样式表:

  1. /* 带序号排序的UL列表 */
  2. .index_list{
  3. position: relative;
  4. clear: both;
  5. width: 100%;
  6. height: auto;
  7. float: left;
  8. display: block;
  9. box-sizing: border-box;
  10. padding: 20px;
  11. background: #fff;
  12. border-radius: 20px;
  13. }
  14. .index_list li a{
  15. cursor: pointer;
  16. }
  17. .index_list li a:hover{
  18. font-weight: bold;
  19. }
  20. .index_list li{
  21. width: 100%;
  22. list-style:none;
  23. font-size:0.9rem;
  24. counter-increment: mycounter; /* 设定计数器名称 */
  25. display: block;
  26. float: none;
  27. padding: 5px 10px;
  28. text-align: left;
  29. /*文本不换行,这样超出一行的部分被截取,显示为“ ...” */
  30. overflow: hidden;
  31. text-overflow: ellipsis;
  32. white-space: nowrap;
  33. }
  34. /* 使用“:before和:after伪类”递增列表序号样式*/
  35. .index_list li:before{
  36. content:counter(mycounter); /* 计数器显示 注意,这里不能加分号 */
  37. color:#333;
  38. margin-right:8px;
  39. display:inline-block;
  40. width:20px;
  41. height:20px;
  42. -moz-border-radius: 3px;
  43. -webkit-border-radius: 3px;
  44. border-radius: 3px; /* future proofing */
  45. -khtml-border-radius:3px; /* for old Konqueror browsers */
  46. text-align:center;
  47. background:#e7e8e9;
  48. font-size: 16px;
  49. font-weight: bold;
  50. line-height: 20px;
  51. display: inline-block;
  52. float:left;
  53. }
  54. /* 定义序号1·2·3的before伪类样式 */
  55. .index_list li:nth-child(1):before{
  56. background:#CC0033;
  57. color: #fff;
  58. }
  59. .index_list li:nth-child(2):before{
  60. background:#FF9933;
  61. color: #fff;
  62. }
  63. .index_list li:nth-child(3):before{
  64. background:#FFCC33;
  65. color: #fff;
  66. }

HTML代码:

  1. <ul class="index_list">
  2. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  3. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  4. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  5. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  6. <li><a herf="###">我是一条内容,我是个有链接的li,我长一点</a></li>
  7. <li><a herf="###">我是一条内容,我是个有链接的li,我特别特别长,我特别特别长,我特别特别长,我特别特别长</a></li>
  8. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  9. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  10. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  11. <li><a herf="###">我是一条内容,我是个有链接的li</a></li>
  12. </ul>

清除浮动

  1. .clearfix:after {
  2. content: "";
  3. display: table;
  4. clear: both;
  5. }

:after 常用于创建一个空的块级元素,配合 clear:both 来清除浮动对后续元素的影响,避免“高度塌陷”问题。将 .clearfix 类应用于需要清除内部浮动的容器元素

替代或扩展HTML内容

  1. a[alt]:after {
  2. content: " ->" attr(alt) "<-";
  3. font-size: smaller;
  4. color: gray;
  5. }

利用 attr() 函数,可以从元素的属性中提取值作为 :after 的内容,实现动态文本展示。 当鼠标悬停在带有 alt 属性的 a 元素上时,会显示一个包含 alt 属性值的小字号灰色括注内容。

结合下面HTML:

<a href="###" title="去百度吧" alt="去哪儿都行">我这个链接去那里呢?</a>

我们看看效果:

实现复杂形状与动画

结合 content、background、border 等属性以及CSS3的 transform、transition 或 animation,可以使用 :after 创建复杂的形状和动画效果。

藏起来的标签

<div class="tips">我是个有提示的小角色!</div>

给它加个CSS

  1. /* 实现复杂形状与动画
  2. 结合 content、background、border 等属性以及CSS3的 transform、transition 或 animation,可以使用 :after 创建复杂的形状和动画效果。 */
  3. .tips{
  4. float: left;
  5. position: relative; /* 父相子绝 */
  6. background: #cacaca;
  7. border-radius: 10px;
  8. padding: 15px 30px;
  9. border: 1px solid #cacaca;
  10. text-shadow: 1px 2px 1px rgba(255, 255, 255, 0.9);
  11. }
  12. .tips::before{
  13. content: '我是隐藏大boss!';
  14. position: absolute;
  15. width: auto;
  16. height: auto;
  17. padding: 15px 30px;
  18. color:#fff;
  19. border-radius: 10px;
  20. background: #ff3399;
  21. white-space: nowrap;
  22. top:0px;
  23. right:-20px;
  24. transition: transform 0.5s ease-in-out;
  25. z-index: -1;
  26. text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.3);
  27. }
  28. .tips::after{
  29. content: '';
  30. position: absolute;
  31. width: 0;
  32. height: 0;
  33. border: 5px solid #fff;
  34. border-radius: 50%;
  35. right: -16px;
  36. top:19px;
  37. transition: transform 0.5s ease-in-out;
  38. z-index: -1;
  39. }
  40. .tips:hover:before,
  41. .tips:hover:after {
  42. transform: translateX(11.5em) ;
  43. transition: transform 0.5s ease-in-out;

彩带标题

HTML:

<h1>今天我们开联欢会</h1>

CSS:

  1. h1 {
  2. position: relative;
  3. margin: 0 auto 20px;
  4. padding: 10px 40px;
  5. text-align: center;
  6. background-color: #ff3399;
  7. margin-bottom: 50px;
  8. color:#660033;
  9. text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.5);
  10. }
  11. h1::before,
  12. h1::after {
  13. content: '';
  14. width: 80px;
  15. height: 100%;
  16. background-color: #ff0080;
  17. /* 定位彩带两端形状的位置,并且放在最底层 */
  18. position: absolute;
  19. z-index: -1;
  20. top: 20px;
  21. /* 彩带两端的形状 */
  22. clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 25% 50%);
  23. /* 绘制并定位彩带的阴影三角形 */
  24. background-image: linear-gradient(45deg, transparent 50%, #cc0066 50%);
  25. background-size: 20px 20px;
  26. background-repeat: no-repeat;
  27. background-position: bottom right;
  28. }
  29. h1::before {
  30. left: -60px;
  31. }
  32. h1::after {
  33. right: -60px;
  34. transform: scaleX(-1);/* 水平翻转 */
  35. }

更加逼真的阴影

HTML:

<div class="box shadow"></div>

CSS:

  1. /* 实现更逼真的阴影 */
  2. .box{
  3. margin:10px;
  4. width:300px;
  5. height:100px;
  6. border-radius:10px;
  7. background:#fff;
  8. }
  9. .shadow{
  10. position:relative;
  11. max-width:270px;
  12. box-shadow:0 1px 4px rgba(0,0,0,.3),0 0 20px rgba(0,0,0,.1) inset
  13. }
  14. .shadow::after,.shadow::before{
  15. position:absolute;
  16. z-index:-1;
  17. content:""
  18. }
  19. .shadow::after,.shadow::before{
  20. position:absolute;
  21. bottom:15px;
  22. left:10px;
  23. z-index:-1;
  24. width:50%;
  25. height:20%;
  26. content:""
  27. }
  28. .shadow::after,.shadow::before{
  29. position:absolute;
  30. bottom:15px;
  31. left:10px;
  32. z-index:-1;
  33. width:50%;
  34. height:20%;
  35. box-shadow:0 15px 10px rgba(0,0,0,.7);
  36. content:"";
  37. transform:rotate(-3deg)
  38. }
  39. .shadow::after{
  40. right:10px;
  41. left:auto;
  42. transform:rotate(3deg)
  43. }

绚丽光圈

HTML:

<div class="aperture">光圈</div>

CSS:

  1. /*光圈*/
  2. .aperture {
  3. width: 136px;
  4. height: 136px;
  5. background-color: #ff3333;
  6. border-radius: 50%;
  7. line-height: 136px;
  8. text-align: center;
  9. color: #fff;
  10. font-size: 24px;
  11. cursor: pointer;
  12. position: relative;
  13. }
  14. .aperture::before {
  15. border: 6px dotted #ff3333;
  16. content: "";
  17. width: 144px;
  18. height: 144px;
  19. position: absolute;
  20. border-radius: 50%;
  21. left: -10px;
  22. top: -10px;
  23. animation: clockwise 5s linear infinite;
  24. }
  25. @keyframes clockwise {
  26. 100% {
  27. transform: rotate(360deg);
  28. }
  29. }

限于篇幅,还有更多利用::before 和 ::after 伪元素结合动画实现的精彩的按钮效果:

请参考我的CSS特效每日一例专题文章:

CSS技巧专栏:一日一例1.会讨好的热情按钮

CSS技巧专栏:一日一例 2.纯CSS实现 多彩边框按钮特效

CSS技巧专栏:一日一例 3.纯CSS实现炫酷多彩按钮特效

CSS技巧专栏:一日一例 4.纯CSS实现两款流光溢彩的酷炫按钮特效

CSS技巧专栏:一日一例 5-纯CSS实现背景色从四周向中心填充的按钮特效

CSS技巧专栏:一日一例 6 - 纯CSS实现粉红色跳出来的立体按钮特效

CSS技巧专栏:一日一例 7 - 纯CSS实现炫光边框按钮特效

CSS技巧专栏:一日一例 8 - 纯CSS利用mask属性实现按钮边框对称包围特效

CSS技巧专栏:一日一例 9 -纯CSS实现按钮边框依次填充特效

CSS技巧专栏:一日一例 10 -纯CSS实现表爱心的小可爱按钮特效

CSS技巧专栏:一日一例 11 -纯CSS实现多彩渐变按钮系列特效

CSS技巧专栏:一日一例 12 -纯CSS实现边框上下交错的按钮特效

CSS技巧专栏:一日一例 13 -纯CSS实现晃晃悠悠背景不停滚动的按钮特效