早在十几二十年前,我最开始接触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 ..
代码示例:
-
<style>
-
p::after{
-
content: "hahaha";
-
color: red;
-
}
-
p::before{
-
content: "hehehe";
-
color: coral;
-
}
-
</style>
层叠解析
我们来看一个HTML的结构的例子:
-
<div class="father">
-
<div class="child-1"></div>
-
<div class="child-2"></div>
-
</div>
在这个例子里,很明显的 div元素father 作为父级,与它的 子元素 div元素 child-1 和 child-2 就是嵌套关系。而两个子元素之间,就是层叠关系。那么我们在不改变他们的定位关系(postion)和Z轴层级(z-index)的前提下,看看他们是如何在浏览器中表现的:
-
/* css */
-
.father {
-
position: relative;
-
height: 400px;
-
width: 400px;
-
background: #ddd;
-
color: #fff;
-
-
}
-
.father::before {
-
content: "before";
-
width: 100px;
-
height: 100px;
-
background: blue;
-
}
-
.father::after {
-
content: "after";
-
width: 100px;
-
height: 100px;
-
background: orange;
-
/* transform: translate(60px,-240px); */
-
}
-
.child-1 {
-
display: block;
-
height: 100px;
-
width: 100px;
-
background: green;
-
/* transform: translate(20px,-80px); */
-
}
-
.child-2 {
-
display: block;
-
height: 100px;
-
width: 100px;
-
background: purple;
-
/* transform: translate(40px,-160px); */
-
}
首先,我们看看不做任何位移时,father元素的 ::before ::after 和它的两个子元素 child-1 child-2的 展示方式。刷新浏览器:
接下来,我们给子元素进行位移,不移动befoer和after,看看它们如何排列:
-
.father::before {
-
content: "before";
-
display: block;
-
width: 100px;
-
height: 100px;
-
background: blue;
-
}
-
.father::after {
-
content: "after";
-
display: block;
-
width: 100px;
-
height: 100px;
-
background: orange;
-
/* transform: translate(60px,-240px); */
-
}
-
.child-1 {
-
display: block;
-
height: 100px;
-
width: 100px;
-
background: green;
-
transform: translate(20px,-80px);
-
}
-
.child-2 {
-
display: block;
-
height: 100px;
-
width: 100px;
-
background: purple;
-
transform: translate(40px,-160px);
-
}
可以清晰的看到,child-1 和child-2 两个子元素发生了位移。但是,奇妙的事情发生了: after 层居然。。。就依然还在它原来的位置。它居然没有移动上去。这是为什么呢?
因为child-1 和child-2 的位移是用 transform: translate() 实现的,浏览器先在原位置渲染了每个div元素,也渲染了after和before层,然后让两个子元素发生了位移,但它们占位并没有消失。所以,它的位置在页面渲染时候就决定了,不会再改变。
接下来,我们给after也进行位移:
-
.father::after {
-
content: "after";
-
display: block;
-
width: 100px;
-
height: 100px;
-
background: orange;
-
transform: translate(60px,-240px);
-
}
这时候,我们就可以看到 father元素,和它的伪元素before,after ,与它的两个子元素之间的层叠关系了。
解析总结:
盒子在默认情况下,也就是没有设置Z-index的情况下:
- 一个盒子 它的 ::before伪类在最底层, ::after 伪元素在最上层, 其所有子元素在中间叠放。
- 盒子的 子元素堆叠关系,按照书写顺序自下而上排序:先写的叠放在下面,后写的在上面。
- 父元素在最下面。
应用案例
要应用伪元素::after 和 :: before,就必须用 content属性。关于content,我们必须知道:
content 属性 是 CSS 中一个非常有用的属性,可以用于插入生成内容,如在 ::before 和 ::after 伪元素中添加文本或图标。
- content 属性仅可用于 ::before 和 ::after 伪元素上,不能用于其他元素上。
- content属性值可以是字符串、特殊字符、URL、计数器等,常用的字符串值包括文字、图标等等。
- content属性不仅可以用于显示内容,也可以用于控制生成内容的样式和行为。
- content属性的值可以是动态的,比如可以使用 attr() 函数将元素的属性值作为伪元素内容。
- content属性可以与 :before 和 :after 伪元素的其他样式属性结合使用,比如 display、position、padding、border、background 等等。
- content 属性的值在页面上不会被选中、复制、粘贴,也不会对文档结构产生影响,仅仅是对生成的内容进行控制和定制。
- content 属性的使用可以让开发者在不改变 HTML 结构的情况下添加或修改一些内容,从而实现一些特殊的效果和功能。
基于上述介绍,我们接下来展示的案例,都是利用 content来实现的。
添加装饰性内容
html代码如下:
-
<blockquote>我是被引用的内容!</blockquote>
-
<br>
-
<blockquote class="new_quote">我是被引用的内容!</blockquote>
CSS代码如下:
-
/* 1. 添加装饰性内容 */
-
/* 默认的样式 */
-
blockquote{
-
text-align: left;
-
font-size: 2rem;
-
}
-
blockquote:before {
-
content: open-quote;
-
font-size: larger;
-
color: #666;
-
}
-
blockquote:after {
-
content: close-quote;
-
}
-
-
/* 1.1 配合guote属性,可以设置嵌套引用的引号类型。 */
-
.new_quote{
-
quotes: "<" ">";
-
}
结果:
那么,肯定不止有这么几个符号可以被引用,所有可以引用的引号字符可以参考下面表格:
效果 |
说明 |
实体编号 |
" |
双引号 |
" |
' |
单引号 |
' |
‹ |
单一的左尖括号 |
‹ |
› |
单一的右尖括号 |
› |
« |
双的左尖括号 |
« |
» |
双的右尖括号 |
» |
' |
左引号(单 high-6) |
‘ |
' |
右引号(单 high-9) |
’ |
" |
左引号(双 high-6) |
“ |
" |
右引号(双 high-9) |
” |
„ |
双引号 (双 low-9) |
„ |
在列表前(后)增加自定义图标
HTML代码如下:
-
<ul>
-
<li>我是一个列表项</li>
-
<li>我也是一个列表项</li>
-
<li class="completed">我也还是一个列表项</li>
-
</ul>
CSS代码如下:
-
/* 2. 在列表前(后)增加自定义图标 */
-
ul{
-
list-style: none;
-
}
-
li{
-
width: 100%;
-
margin: 4px 0px;
-
display: block;
-
text-align: left;
-
padding: 5px 10px;
-
height: 20px;
-
}
-
li.completed:after {
-
content: "\2713"; /* Unicode 字符:对勾 */
-
color: green;
-
font-size: 0.8em;
-
vertical-align: super;
-
}
刷新结果:
用于引用媒体文件
还是用上面的HTML文件,我们稍微增加一些CSS:
-
li:before {
-
display:inline-block;
-
content: url();
-
background: #fcc;
-
width: 12px;
-
height: 12px;
-
overflow: hidden;
-
padding-left: 20px;
-
margin-right: 5px;
-
}
注意:
1)URL不能使用引号。如果你将URL用引号括起来,那么它会变成一个字符串和插入文本“url()”作为其内容,插入的而不是图像本身。
2)content属性,直接使用图片,即使写width,height也无法改变图片大小; */
看效果:
序号自动增加排序的UL列表
这是一个content属性 结合 计数器 实现的效果。
CSS样式表:
-
/* 带序号排序的UL列表 */
-
.index_list{
-
position: relative;
-
clear: both;
-
width: 100%;
-
height: auto;
-
float: left;
-
display: block;
-
box-sizing: border-box;
-
padding: 20px;
-
background: #fff;
-
border-radius: 20px;
-
}
-
.index_list li a{
-
cursor: pointer;
-
}
-
.index_list li a:hover{
-
font-weight: bold;
-
}
-
.index_list li{
-
width: 100%;
-
list-style:none;
-
font-size:0.9rem;
-
counter-increment: mycounter; /* 设定计数器名称 */
-
display: block;
-
float: none;
-
padding: 5px 10px;
-
text-align: left;
-
/*文本不换行,这样超出一行的部分被截取,显示为“ ...” */
-
overflow: hidden;
-
text-overflow: ellipsis;
-
white-space: nowrap;
-
}
-
/* 使用“:before和:after伪类”递增列表序号样式*/
-
.index_list li:before{
-
content:counter(mycounter); /* 计数器显示 注意,这里不能加分号 */
-
color:#333;
-
margin-right:8px;
-
display:inline-block;
-
width:20px;
-
height:20px;
-
-moz-border-radius: 3px;
-
-webkit-border-radius: 3px;
-
border-radius: 3px; /* future proofing */
-
-khtml-border-radius:3px; /* for old Konqueror browsers */
-
text-align:center;
-
background:#e7e8e9;
-
font-size: 16px;
-
font-weight: bold;
-
line-height: 20px;
-
display: inline-block;
-
float:left;
-
-
}
-
/* 定义序号1·2·3的before伪类样式 */
-
.index_list li:nth-child(1):before{
-
background:#CC0033;
-
color: #fff;
-
}
-
.index_list li:nth-child(2):before{
-
background:#FF9933;
-
color: #fff;
-
}
-
.index_list li:nth-child(3):before{
-
background:#FFCC33;
-
color: #fff;
-
}
HTML代码:
-
<ul class="index_list">
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li,我长一点</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li,我特别特别长,我特别特别长,我特别特别长,我特别特别长</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
<li><a herf="###">我是一条内容,我是个有链接的li</a></li>
-
</ul>
清除浮动
-
.clearfix:after {
-
content: "";
-
display: table;
-
clear: both;
-
}
:after 常用于创建一个空的块级元素,配合 clear:both 来清除浮动对后续元素的影响,避免“高度塌陷”问题。将 .clearfix 类应用于需要清除内部浮动的容器元素
替代或扩展HTML内容
-
a[alt]:after {
-
content: " ->" attr(alt) "<-";
-
font-size: smaller;
-
color: gray;
-
}
利用 attr() 函数,可以从元素的属性中提取值作为 :after 的内容,实现动态文本展示。 当鼠标悬停在带有 alt 属性的 a 元素上时,会显示一个包含 alt 属性值的小字号灰色括注内容。
结合下面HTML:
<a href="###" title="去百度吧" alt="去哪儿都行">我这个链接去那里呢?</a>
我们看看效果:
实现复杂形状与动画
结合 content、background、border 等属性以及CSS3的 transform、transition 或 animation,可以使用 :after 创建复杂的形状和动画效果。
藏起来的标签
<div class="tips">我是个有提示的小角色!</div>
给它加个CSS
-
/* 实现复杂形状与动画
-
结合 content、background、border 等属性以及CSS3的 transform、transition 或 animation,可以使用 :after 创建复杂的形状和动画效果。 */
-
.tips{
-
float: left;
-
position: relative; /* 父相子绝 */
-
background: #cacaca;
-
border-radius: 10px;
-
padding: 15px 30px;
-
border: 1px solid #cacaca;
-
text-shadow: 1px 2px 1px rgba(255, 255, 255, 0.9);
-
}
-
.tips::before{
-
content: '我是隐藏大boss!';
-
position: absolute;
-
width: auto;
-
height: auto;
-
padding: 15px 30px;
-
color:#fff;
-
border-radius: 10px;
-
background: #ff3399;
-
white-space: nowrap;
-
top:0px;
-
right:-20px;
-
transition: transform 0.5s ease-in-out;
-
z-index: -1;
-
text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.3);
-
}
-
.tips::after{
-
content: '';
-
position: absolute;
-
width: 0;
-
height: 0;
-
border: 5px solid #fff;
-
border-radius: 50%;
-
right: -16px;
-
top:19px;
-
transition: transform 0.5s ease-in-out;
-
z-index: -1;
-
}
-
.tips:hover:before,
-
.tips:hover:after {
-
transform: translateX(11.5em) ;
-
transition: transform 0.5s ease-in-out;
彩带标题
HTML:
<h1>今天我们开联欢会</h1>
CSS:
-
h1 {
-
position: relative;
-
margin: 0 auto 20px;
-
padding: 10px 40px;
-
text-align: center;
-
background-color: #ff3399;
-
margin-bottom: 50px;
-
color:#660033;
-
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.5);
-
}
-
h1::before,
-
h1::after {
-
content: '';
-
width: 80px;
-
height: 100%;
-
background-color: #ff0080;
-
/* 定位彩带两端形状的位置,并且放在最底层 */
-
position: absolute;
-
z-index: -1;
-
top: 20px;
-
/* 彩带两端的形状 */
-
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 25% 50%);
-
/* 绘制并定位彩带的阴影三角形 */
-
background-image: linear-gradient(45deg, transparent 50%, #cc0066 50%);
-
background-size: 20px 20px;
-
background-repeat: no-repeat;
-
background-position: bottom right;
-
}
-
h1::before {
-
left: -60px;
-
}
-
h1::after {
-
right: -60px;
-
transform: scaleX(-1);/* 水平翻转 */
-
}
更加逼真的阴影
HTML:
<div class="box shadow"></div>
CSS:
-
/* 实现更逼真的阴影 */
-
.box{
-
margin:10px;
-
width:300px;
-
height:100px;
-
border-radius:10px;
-
background:#fff;
-
}
-
.shadow{
-
position:relative;
-
max-width:270px;
-
box-shadow:0 1px 4px rgba(0,0,0,.3),0 0 20px rgba(0,0,0,.1) inset
-
}
-
.shadow::after,.shadow::before{
-
position:absolute;
-
z-index:-1;
-
content:""
-
}
-
.shadow::after,.shadow::before{
-
position:absolute;
-
bottom:15px;
-
left:10px;
-
z-index:-1;
-
width:50%;
-
height:20%;
-
content:""
-
}
-
.shadow::after,.shadow::before{
-
position:absolute;
-
bottom:15px;
-
left:10px;
-
z-index:-1;
-
width:50%;
-
height:20%;
-
box-shadow:0 15px 10px rgba(0,0,0,.7);
-
content:"";
-
transform:rotate(-3deg)
-
}
-
.shadow::after{
-
right:10px;
-
left:auto;
-
transform:rotate(3deg)
-
}
绚丽光圈
HTML:
<div class="aperture">光圈</div>
CSS:
-
/*光圈*/
-
-
.aperture {
-
width: 136px;
-
height: 136px;
-
background-color: #ff3333;
-
border-radius: 50%;
-
line-height: 136px;
-
text-align: center;
-
color: #fff;
-
font-size: 24px;
-
cursor: pointer;
-
position: relative;
-
}
-
-
.aperture::before {
-
border: 6px dotted #ff3333;
-
content: "";
-
width: 144px;
-
height: 144px;
-
position: absolute;
-
border-radius: 50%;
-
left: -10px;
-
top: -10px;
-
animation: clockwise 5s linear infinite;
-
}
-
-
@keyframes clockwise {
-
100% {
-
transform: rotate(360deg);
-
}
-
}
限于篇幅,还有更多利用::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实现晃晃悠悠背景不停滚动的按钮特效