伪元素及其应用

711 阅读6分钟

什么是伪元素

伪元素是一个附加至选择器末的关键词,允许你对被选择元素的特定部分修改样式

伪元素在CSS3之前就已经存在,当时还没有伪元素的概念,统称为伪类。很多人分不清楚伪类和伪元素, 一道常见的CSS面试题是:伪类和伪元素的区别?

用更俗的语言可以说:

1. 伪类表示被选择元素的某种状态,例如:hover

2. 伪元素表示的是被选择元素的某个部分,只存在于css中,例如:before:after

伪元素的语法

一个选择器中只能使用一个伪元素。伪元素必须紧跟在语句中的简单选择器/基础选择器之后。

注意: 按照规范,应该使用双冒号(::)而不是单个冒号(:),以便区分伪类和伪元素。但是,由于旧版本的 W3C 规范并未对此进行特别区分,因此目前绝大多数的浏览器都同时支持使用这两种方式来表示伪元素。::selection 永远只能以两个冒号开头(::)。因为IE8只支持单冒号的语法,所以,如果你想兼容IE8,保险的做法是使用单冒号。

伪元素所有用法和行为表现和真正的元素几乎完全一样;我们可以对它们进行任何的CSS样式设置,例如,改变它们的前景颜色,增加背景色/图,调整字体大小,调整对齐方式等等

伪元素使用是有区别的,像:before:after伪元素在页面中生成的元素在缺省情况(默认情况)下是“内联(inline)”元素,如果我们想指定它们的高度和宽度,需要首先定义它们为一个block元素,使用display: block;

伪类元素的应用

CSS样式表的主要作用是修饰Web页面上的HTML标记,但有时候,为了实现某个效果而往页面里反复添加某个HTML标记很繁琐,或者是显得多余,或者是由于某种原因而做不到。这就是CSS伪元素(Pseudo-Element)可以发挥作用的地方,所谓‘伪元素’,就是本身不存在的页面元素,HTML代码里并没有这样的元素,但在页面显示时,你却能看到这些本来不存在的元素发挥着作用。

1px绘制

一条border

.setOnePx{
  position: relative;
  &::after{
    position: absolute;
    content: '';
    background-color: #e5e5e5;
    display: block;
    width: 100%;
    height: 1px; /*no*/
    transform: scale(1, 0.5);
    top: 0;
    left: 0;
  }
}

四条border

.setBorderAll{
 position: relative;
   &:after{
       content:" ";
       position:absolute;
       top: 0;
       left: 0;
       width: 200%;
       height: 200%;
       transform: scale(0.5);
       transform-origin: left top;
       box-sizing: border-box;
       border: 1px solid #E5E5E5;
       border-radius: 4px;
  }
}
  • 优点:全机型兼容,实现了真正的1px,而且可以圆角。
  • 缺点:暂用了after 伪元素,可能影响清除浮动。

增大点击区域

  1. 伪元素使用绝对定位不会改变现有的文档流和布局尺寸
  2. 伪元素继承了元素的 cursor 属性,鼠标指针显示与元素保持一致
  3. 伪元素能触发事件并冒泡给元素
  4. 不影响现有布局的情况下,不增加多余元素
.btn {
    position: relative;
}

.btn::before {
    content: '';
    position: absolute;
    top: -20px;
    right: -20px;
    bottom: -20px;
    left: -20px;
}

清除浮动

.clear:after {
    content: '';
    /* 也可以是block,
    或者是list-item <li>元素默认的display是list-item,
    list-item在IE上有兼容问题
    <table>元素默认的display是table 
    实际开发中多用block */
    display:table;
    clear:both;
}

对话气泡等形状的实现

// CSS代码
.tooltip {
    position: relative;
    display: inline-block;
    padding: 5px 10px;
    background: #80D4C8;
}
.tooltip:before {
    content: "";
    display: block;
    position: absolute;
    left: 50%;
    margin-left: -5px;
    bottom: -5px;
    width: 0; 
    height: 0; 
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 5px solid #80D4C8;
}
// HTML代码
<div class="tooltip">I'm a tooltip.</div>

使用JS控制伪元素

为什么不能用JS直接获取伪元素呢?

譬如::before和::after伪元素,用于在CSS渲染中向元素的头部或尾部插入内容,它们不受文档约束,也不影响文档本身,只影响最终样式。这些添加的内容不会出现在DOM中,仅仅是在CSS渲染层中加入。

事实上, 伪元素可以被浏览器渲染,但本身并不是DOM元素。它不存在于文档中,所以JS无法直接操作它。 而jQuery的选择器都是基于DOM元素的,因此也并不能直接操作伪元素。

那该怎样操作伪元素的样式呢?

伪元素有六个,分别是 ::after、::before、::first-line、::first-letter、::selection、::backdrop

获取伪元素的属性值:

获取伪元素的属性值可以使用 window.getComputedStyle() 方法,获取伪元素的CSS样式声明对象。然后利用getPropertyValue方法或直接使用键值访问都可以获取对应的属性值。

语法:window.getComputedStyle(element[, pseudoElement])

参数如下:

element(Object):伪元素的所在的DOM元素;

pseudoElement(String):伪元素类型。可选值有:”:after”、”:before”、”:first-line”、”:first-letter”、”:selection”、”:backdrop”;

举个例子:

// CSS代码
#myId:before {
    content: "hello world!";
    display: block;
    width: 100px;
    height: 100px;
    background: red;
}
// HTML代码
<div id="myId"></div>
// JS代码
var myIdElement = document.getElementById("myId");
var beforeStyle = window.getComputedStyle(myIdElement, ":before");
console.log(beforeStyle); // [CSSStyleDeclaration Object]
console.log(beforeStyle.width); // 100px
console.log(beforeStyle.getPropertyValue("width")); // 100px
console.log(beforeStyle.content); // "hello world!"

备注:

1.getPropertyValue()和直接使用键值访问,都可以访问CSSStyleDeclaration Object。它们两者的区别有:

对于float属性,如果使用键值访问,则不能直接使用getComputedStyle(element, null).float,而应该是cssFloat与styleFloat; 直接使用键值访问,则属性的键需要使用驼峰写法,如:style.backgroundColor; 使用getPropertyValue()方法不必可以驼峰书写形式(不支持驼峰写法),例如:style.getPropertyValue(“border-top-color”); getPropertyValue()方法在IE9+和其他现代浏览器中都支持;在IE6~8中,可以使用getAttribute()方法来代替;

2.伪元素默认是”display: inline”。如果没有定义display属性,即使在CSS中显式设置了width的属性值为固定的大小如”100px”,但是最后获取的width值仍是”auto”。这是因为行内元素不能自定义设置宽高。解决办法是给伪元素修改display属性为”block”、”inline-block”或其他。

更改伪元素的样式

方法1. 更换class来实现伪元素属性值的更改:

举个栗子:

// CSS代码
.red::before { 
    content: "red"; 
    color: red; 
}
.green::before { 
    content: "green"; 
    color: green;
}
// HTML代码
<div class="red">内容内容内容内容</div>
// jQuery代码
$(".red").removeClass('red').addClass('green');

方法2. 使用CSSStyleSheet的insertRule来为伪元素修改样式:

举个栗子:

document.styleSheets[0].addRule('.red::before','color: green'); // 支持IE document.styleSheets[0].insertRule('.red::before { color: green }', 0); // 支持非IE的现代浏览器

方法3. 在<head>标签中插入 <style> 的内部样式:

var style = document.createElement("style"); 
document.head.appendChild(style); 
sheet = style.sheet; 
sheet.addRule('.red::before','color: green'); // 兼容IE浏览器
sheet.insertRule('.red::before { color: green }', 0); // 支持非IE的现代浏览器

或者用jQuery:

$('<style>.red::before{color:green}</style>').appendTo('head');

修改伪元素的content的属性值:

方法1. 使用CSSStyleSheet的insertRule来为伪元素修改样式:

var latestContent = "修改过的内容";
var formerContent = window.getComputedStyle($('.red'), '::before').getPropertyValue('content'); document.styleSheets[0].addRule('.red::before','content: "' + latestContent + '"'); document.styleSheets[0].insertRule('.red::before { content: "' + latestContent + '" }', 0);

方法2. 使用DOM元素的data-*属性来更改content的值

// CSS代码
.red::before {
content: attr(data-attr);
color: red;
}
// HTML代码
<div class="red" data-attr="red">内容内容内容内容</div>
// JacaScript代码
$('.red').attr('data-attr', 'green');