DOM系列-操作CSS

262 阅读4分钟

我们知道JavaScript可以控制HTML文档的逻辑结构和内容,CSS可以控制文档的外观和布局。而实际上JavaScript也可以通过对CSS编程,实现控制文档的外观和布局。

CSS类

使用JavaScript控制样式最简单的方法是修改标签的class属性,好处在于可以一次性修改多个样式,避免了JavaScript与CSS的耦合问题。

元素有一个属性叫className,我们可以直接对其进行修改。

.box1 {
    width: 100px;
    height: 100px;
    background-color: green;
}

.box2{
    width: 200px;
    height: 200px;
    background-color: pink;
}
<div class="box1"></div>

<script>
    var oDiv = document.getElementsByTagName('div')[0];
    oDiv.className = 'box2';
</script>

在开发过程中我们有时还需要去修改伪元素的样式,对此我们也一样可以使用类去修改。

  • 比如以下代码实现了点击事件改变伪元素的背景色。
.box{
    width: 100px;
    height: 100px;
    padding: 10px;
    background-color: antiquewhite;
    border: 1px solid #000;
}

.box::after{
    content: "";
    display: block;
    width: 50px;
    height: 50px;
    background-color: red;
}

.box.active::after{
    background-color: green;
}
<div class="box">

</div>
<script>
    var oDiv = document.getElementsByTagName('div')[0];

    oDiv.onclick = function(){
        this.className += ' active';
    }

</script>

除了直接对className属性修改之外,还可以使用Element.classList属性进行设置样式,它是一个对象,为我们提供了对当前元素的类的各种操作方法。

Element.classList.add()方法 用于向元素中添加一个或多个class。

box1.classList.add('box2');

Element.classList.remove()方法 用于删除元素的一个或多个class。

box1.classList.remove('box2');

Element.classList.toggle()方法 用于切换元素中的一个class。

box1.classList.toggle('box2');

Element.classList.replace()方法 用于替换元素中的一个class。

box1.classList.replace('box1', 'box2'); // box2替换box1

Element.classList.contains()方法 用于检查元素是否包含指定class,返回true或false。

box1.classList.contains('box2');

行内样式

DOM可以通过 Element.style.Name = value的语法读取和修改CSS行内样式(每一次修改样式,页面都会重新渲染,所以一般采用修改class属性同时修改多个样式)。JavaScript中的style属性实际上是一个CSSStyleDeclaration对象,是对HTML中作为style属性值的CSS样式文本解析之后得到的一个表示。

如果一个元素没有设置行内样式,但是通过类设置了样式,那么通过上述属性访问得到的结果会是一个空字符串。

.box1 {
    width: 100px;
    height: 100px;
    background-color: green;
}

使用过程中我们可能会误以为打印出'100px',但实际上是空字符串''

<div class="box1">

</div>

<script>
    var oDiv = document.getElementsByTagName('div')[0];
    console.log(oDiv.style.width); // ''
</script>

而当我们对其进行赋值时,实际上就是通过添加行内样式去覆盖类设置的样式(注意是覆盖,而不是修改类设置的样式。),这个本质一定要理清。

var oDiv = document.getElementsByTagName('div')[0];
oDiv.style.width = '200px';
console.log(oDiv.style.width); // '200px'。

使用style对象还有如下的一些规则:

  • 连字符在JavaScript中会被解释为减号,所以不允许出现在属性名及其它标识符中,所以要用小驼峰命名法,比如JavaScript会使用borderLeftWidth属性访问boder-left-width这个CSS属性。

  • 属性值必须是字符串格式,要加引号""

e.style.display = 'block';
e.style.fontFamily = 'sans-serif';
e.style.backgroundColor = '#ffffff';
  • 许多CSS属性要求包含单位,比如"px"表示像素,因此JavaScript中对这类样式属性设置时单位是必须的,并且要注意如果是复合值需要要拆解赋值。
e.style.margin = `${top}px ${right}px ${bottom}px ${left}px`;
  • 保留字前面要加字符串"css"
e.style.cssFloat = 'left';

计算样式

元素的计算样式(computed style)是浏览器根据一个元素的行内样式和所有样式表中适用的样式规则导出(或计算得到)的一组属性值,浏览器实际上使用这组属性值来显示该元素。

getComputedStyle()方法 可以获取一个元素的计算样式,该方法返回的是一个元素样式属性集合对象。第一个参数是要查询的元素,可选的第二个参数用于指定一个CSS伪元素。

div{
    width: 100px;
    height: 100px;
    padding: 10px;
    background-color: antiquewhite;
    border: 1px solid #000;
}

div::after{
    content: "";
    display: block;
    width: 50px;
    height: 50px;
    background-color: red;
}
<div>

</div>
<script>
    var oDiv = document.getElementsByTagName('div')[0];

    console.log(getComputedStyle(oDiv).width); // '100px'

    console.log(getComputedStyle(oDiv, 'after').width); // '50px'
</script>
</script>

getComputedStyle()方法的返回值也是一个CSSStyleDeclaration对象,它与表示行内样式的CSSStyleDeclaration对象有一些重要的区别:

  • 计算样式的属性是只读的。
  • 计算样式的属性是绝对值,百分比和电灯相对单位都被转换成了绝对值。任何指定大小的属性都将以像素度量,值会包含"px"后缀。
  • 简写属性不会被计算,只有它们代表的基础属性会被计算。比如不能查询margin属性,但是可以查询marginLeftmarginTop等。
  • 计算样式的cssText属性是undefined

注意如果某元素没有被绝对定义,通过计算样式查询其topleft属性经常会返回auto。这是一个合法的CSS值,却不一定是我们想要的。

IE8及以下版本只支持通过elem.currentStyle属性去读取样式表中的属性,所以我们可以封装一个获取元素样式的方法。

// 获取元素某个样式
function getStyles(elem, prop){
    if(window.getComputedStyle){
        if(prop){
            return window.getComputedStyle(elem, null)[prop];
        }else{
            return window.getComputedStyle(elem, null);
        }
    }else{
        if(prop){
            return elem.currentStyle[prop];
        }else{
            return elem.currentStyle;
        }
    }
}