# css 其他要点难点学习

返回:UI

5cb4250096a247638b0bdbc22aca59f4.jpg

# 三大特性

  • 层叠性:css 样式冲突采取的原则(后者覆盖前者)
  • 继承性:对于部分属性样式会有天生的继承
  • 优先级:选择器优先级算法

# 选择器

参考阅读

# 打造自适应网站只用一个 CSS 属性就够了

clamp(minimum, preferred, maximum);
1

# js 生成操作 DOM

/**
 * 生产视频预览框
 * @param src 视频地址
 * @param videoHeight 视频框高度
 * @param extendWidth 视频框宽度
 * @param id video框id
 */
const generateVideo = ({
  src = "",
  videoHeight = 520,
  extendWidth = "max-width:1280px;",
  id = "videoBodyDiv",
}) => {
  const videoElement = document.createElement("video");
  // const videoElement = document.getElementById('videoBodyDiv');
  videoElement.setAttribute("src", src);
  videoElement.setAttribute("id", id);
  // videoElement.setAttribute('className', styleVideo.videoBody)
  videoElement.setAttribute("autoPlay", "true");
  videoElement.setAttribute("controls", "true");
  videoElement.setAttribute("playsInline", "true");
  videoElement.setAttribute("webkit-playsinline", "true");
  videoElement.style.cssText = `width: auto;height: ${videoHeight}px;${extendWidth}`;
  return videoElement;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

append 是追加到最后

const videoElement = generateVideo({
  src: finalUrl,
  id: `${containerId}Video`,
  videoHeight: 180,
  extendWidth: "max-width: 192px",
});
// videoElement.removeAttribute('controls')
videoPlay.appendChild(videoElement);
1
2
3
4
5
6
7
8

至于样式的设置

// 在单个语句中设置多个样式
videoElement.style.cssText = "color: blue; border: 1px solid black";
// 或者
videoElement.setAttribute("style", "color:red; border: 1px solid blue;");
// 设置特定样式,同时保持其他内联样式值不变
videoElement.style.color = "blue";
1
2
3
4
5
6

获取样式

要了解元素样式的信息,仅仅使用 style 属性是不够的,这是因为它只包含了在元素内嵌 style 属性(attribute)上声明的的 CSS 属性,而不包括来自其他地方声明的样式,如 <head> 部分的内嵌样式表,或外部样式表。要获取一个元素的所有 CSS 属性,你应该使用 window.getComputedStyle()

<!DOCTYPE html>
<html>
  <body style="font-weight:bold;">
    <div style="color:red" id="myElement">..</div>
  </body>
</html>
1
2
3
4
5
6
var element = document.getElementById("myElement");
var out = "";
var elementStyle = element.style;
var computedStyle = window.getComputedStyle(element, null);

for (prop in elementStyle) {
  if (elementStyle.hasOwnProperty(prop)) {
    out +=
      "  " +
      prop +
      " = '" +
      elementStyle[prop] +
      "' > '" +
      computedStyle[prop] +
      "'\n";
  }
}
console.log(out);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

输出结果

...
fontWeight = '' > 'bold'
color = 'red' > 'rgb(255, 0, 0)'
...
1
2
3
4

WARNING

请注意,计算样式中 font-weight 的值为“bold”,元素的 style 属性中缺少该值

# js 向现有 DOM 中插入 DOM

  • 如果这个 DOM 节点是空的,例如,<div></div>,那么,直接使用innerHTML = '<span>child</span>'就可以修改 DOM 节点的内容,相当于“插入”了新的 DOM 节点。
  • 如果这个 DOM 节点不是空的,那就不能这么做,因为 innerHTML 会直接替换掉原来的所有子节点。

此时该如何操作呢?

  • 一个是使用 appendChild,把一个子节点添加到父节点的最后一个子节点
<!-- HTML结构 -->
<p id="js">JavaScript</p>
<div id="list">
  <p id="java">Java</p>
  <p id="python">Python</p>
  <p id="scheme">Scheme</p>
</div>
1
2
3
4
5
6
7

<p id="js">JavaScript</p>添加到<div id="list">的最后一项

var js = document.getElementById("js"),
  list = document.getElementById("list");
list.appendChild(js);
1
2
3

动态创建一个节点然后添加到 DOM 树中,可以实现很多功能。举个例子,下面的代码动态创建了一个<style>节点,然后把它添加到<head>节点的末尾,这样就动态地给文档添加了新的 CSS 定义:

var d = document.createElement("style");
d.setAttribute("type", "text/css");
d.innerHTML = "p { color: red }";
document.getElementsByTagName("head")[0].appendChild(d);
1
2
3
4
  • insertBefore:parentElement.insertBefore(newElement, referenceElement);,子节点会插入到 referenceElement 之前

# JS 修改 css 样式的 8 种方式

  • 直接设置 style 的属性 某些情况用这个设置 !important值无效
    • 如果属性有’-'号,就写成驼峰的形式(如 textAlign) 如果想保留 - 号,就中括号的形式
element.style["text-align"] = "100px";
element.style.textAlign = "100px";
element.style.height = "100px";
1
2
3
  • 直接设置属性(只能用于某些属性,相关样式会自动识别)
element.setAttribute("height", 100);
element.setAttribute("height", "100px");
1
2
  • 设置 style 的属性
element.setAttribute("style", "height: 100px !important");
1
  • 使用 setProperty 如果要设置!important,推荐用这种方法设置第三个参数
element.style.setProperty("height", "300px", "important");
1
  • 改变 class 比如 JQ 的更改 class 相关方法
    • 因 JS 获取不到 css 的伪元素,所以可以通过改变伪元素父级的 class 来动态更改伪元素的样式
element.className = "blue";
element.className += "blue fb";
1
2
  • 设置 cssText
element.style.cssText = "height: 100px !important";
element.style.cssText += "height: 100px !important";
1
2
  • 创建引入新的 css 样式文件
function addNewStyle(newStyle) {
  var styleElement = document.getElementById("styles_js");

  if (!styleElement) {
    styleElement = document.createElement("style");
    styleElement.type = "text/css";
    styleElement.id = "styles_js";
    document.getElementsByTagName("head")[0].appendChild(styleElement);
  }

  styleElement.appendChild(document.createTextNode(newStyle));
}

addNewStyle(".box {height: 100px !important;}");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 使用 addRule、insertRule
// 在原有样式操作
document.styleSheets[0].addRule(".box", "height: 100px");
document.styleSheets[0].insertRule(".box {height: 100px}", 0);

// 或者插入新样式时操作
var styleEl = document.createElement("style"),
  styleSheet = styleEl.sheet;

styleSheet.addRule(".box", "height: 100px");
styleSheet.insertRule(".box {height: 100px}", 0);

document.head.appendChild(styleEl);
1
2
3
4
5
6
7
8
9
10
11
12

# @supports

@supports

是CSS中常见的@规则,可以用来检测当前浏览器是否支持某个css特性。

不支持animation的浏览器,使用gif动画,支持animation的浏览器,使用动画

.loading{
      width:10px;
      heigth:10px;
      background:url(./loading.gif);
}

/* 判断是否支持animation 属性,支持则增加动画效果 */
@support (animation:none) {
    .loading{
          width:10px;
          heigth:10px;
          background:url(./loading.png);
          animation: spin 1s linear infinite;
    }
    @keyframes spin{
        from { transform: rotate(360deg);}
        to {transform: rotate(0deg);}
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

使用position:sticky 实现滚动粘滞效果,传统浏览器使用js支持。

//js 判断是否支持positon:sticky 属性  CSS.supports(propertyName,value)
  if( !window.CSS || !CSS.supports || !CSS.supports('position','sticky'){
      //TODO 
  }
1
2
3
4

# fit-content

fit-content

把内容理解为"大腿",那么fit-content就是"紧身裤"

需求:文本少的时候,文本水平居中,多行文本的时候,文本向左对齐

/* // 传统实现 */
.content{
      display:table;
      margin:auto;
}
/* // 如果是内联元素 */
.content{
      display:inline-block;
      margin:auto;
}
/* // fit-content 实现 */
.content{
      width:fit-content;
      margin:auto;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# fit-content 优势

保护了元素原始的display计算值,例如 li 标签设置成display:table,前面的项目符号就不会出现,::marker伪元素也会失效。 让元素尺寸有了确定的值。
针对第二点让元素有了确定的值,我们的应用场景。例如:我们利用绝对布局,使用margin:auto 来实现居中效果,需要我们设置具体的with或者height的属性值。

有的时候我们不确定width,height,我们就会使用transform 来实现居中

.test3-center{
  position: absolute;
  left: 50%;
  top: 50%;
  background: red;
  transform: translate(-50%, -50%);
  
} 
1
2
3
4
5
6
7
8

这个时候我们如果需要给 test3-center 添加一个位移动画

@keyframes move{
    from { transform:translateY(5px);}
    to { transform:translateY(0); }
    
}
1
2
3
4
5

这个时候我们的transform就会受到位移动画干扰。

更好的方法是使用我们的 fit-content,这样就有了确定的宽高,居中可以生效了。

.test3-center{
    position: absolute;
    width:fit-content;
    height:fit-content;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    animation: move .2s;
    
} 
1
2
3
4
5
6
7
8
9
10
11
12

# border-image

# border-image 属性作用过程分为两个点

  • 源图像的划分(九宫格)
  • 九宫格尺寸的控制

# border-image 成员组成

border-image-source //图像资源,不讲解
border-image-slice
border-image-width
border-image-outset
border-image-repeat
1
2
3
4
5

border-image 应用场景

设计师给了我们一张list的背景图,背景图四个角有不同的小图案,中间区域可以拉伸,由于list的高度是不固定的,我们不能确定背景的高度,只能靠内容填充,这就需要我们的背景拉伸,设计师的原则:四个角不变形,中间区域拉伸。这个时候我们的border-image就可以出场了。

border-image 划分九宫格如下:

640.jpg

border-image 会将这九宫格作用在源图像上。

# border-image-slice

    /* //语法 */
border-image-slice: <number-percentage>{1,4} && fill?
1
2

表示支持1 ~ 4个数值或者1 ~ 4个百分比值,后面带一个fill关键字,fill关键字可选。border-image-slice 用于划分源图像,划分的方位和顺序为:上,右,下,左

例如:border-image-slice:100 ,表示距离源图像上方100px,距离源图像右侧100px,距离源图像下方100px,距离源图像左侧100px,这个时候四个角1,2,3,4都被固定了,其他区域拉伸。

.test5 {
        position: relative;
        width: 400px;
        height: 300px;
        border: 50px solid red;
        border-image-source: url("./bg1.png");
        border-image-slice: 100;

    }
1
2
3
4
5
6
7
8
9
  • border-image-slice 只是划分源图像。具体border的宽度跟border-width或者border-image-width有关。
  • border属性一定要写在border-image 属性前面,否则border-image无效。
  • border-image-slice 只能是数值或者百分比,不能带单位(px)。
  • 默认情况下源图像中心位置(9号位置)是不参与填充的,如果想要填充效果,使用fill关键字。
border-image-slice:22% fill;
1

# border-image-width

  • border-image-width 和border-image-outset 都是控制九宫格的尺寸。
  • border-image-width 属性和border-width的属性支持个数一样,都是1 ~ 4 个,值得对应方位也一样,只是值得类型不一样。
  • border-image-width 属性支持数值作为属性值,这个数值会作为系数与border-width的宽度相乘,最终的计算值作为边框的宽度。
  • border-image-width 属性值如果是具体的长度值(30px,20rem),则边框宽度与border-width就没有任何关系了。理论上,设置border-width为0,- border-image-width 设置具体长度值,就可以正常渲染边框,但是chrome不能正常渲染边框,因此我们为了让border-image-width生效,设置border-width 为0.02px;
  • border-image-width 为百分比,是相对元素自身尺寸计算,水平方向相对于宽度,垂直方向相对于高度。
  • border-image-width 设置为auto 关键字。会使用border-image-slice 属性划分的尺寸作为九宫格的长度值。(推荐)
  • border-image-width 和border-width 不支持负数值。
  • border-image-width 控制的是1-8区域的尺寸。

# border-image-outset

border-image-outset 控制中心区域(9号区域)的尺寸,是往外扩张的意思。同样支持四个方位的属性值。

.test5{
    border-image-source: url("./bg1.png");
    border-image-outset: 20px;
}
1
2
3
4

这里就是元素中心的区域(9号区域)向左右上下都扩大20px,所以9号区域的宽度为:9号区域原始宽度+40px,高度为:9号区域原始高度+40px

# border-image-repeat

border-image-repeat 控制 5-8号区域的图像的平铺规则。

 .test5{
     border-image-source: url("./bg1.png");
     /* //默认值,让源图像充满整个显示区域。 */
     border-image-repeat: stretch;
     /* //让源图像紧密相连,在边界位置会截断图像。 */
     border-image-repeat: repeat;
     /* //让源图像金币相连,适当伸缩,边界位置不会截断图像,完整显示图像。 */
     border-image-repeat: round;
     /* //让源图像保持原有尺寸,中间区域等宽留有空白,图像平铺,边界位置完整显示图像。 */
     border-image-repeat: space;
 }
1
2
3
4
5
6
7
8
9
10
11

# CSS中BFC的含义及其作用

块格式化上下文(Block Formatting Context)

BFC 是一个完全独立的盒子,内部的元素无论样式是什么,都不会影响到盒子外部的布局。

# 触发BFC

  • 根元素<html>
  • 浮动元素(float不为none
  • 固定定位、绝对定位元素(position为absolute或fixed
  • 行内块元素(display: inline-block
  • 表格单元格(display: table-cell)默认
  • 表格标题(display: table-caption)默认
  • overflow不为visible
  • 弹性元素(display: flex
  • 网格元素(display: grid

# 外边距塌陷

有如下代码,两个盒子,外边距margin都设置为50px,理应两个盒子的间距应该为100px,但其真实间距为50px。

这是因为发生了外边距塌陷问题,两个盒子的margin重叠到了一起,相互影响。

<style>
    .son {
        width: 100px;
        height: 100px;
        background-color: blue;
        margin: 50px;
    }
</style>
<body>
    <div class="son"></div>
    <div class="son"></div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12

可以利用 BFC 特性来解决外边距塌陷问题。将这两个盒子,分别放入两个 BFC 区域中,因为 BFC 是一个完全独立的盒子,内部的元素不会影响到外部区域。

将以上代码修改为如下即可解决,两盒子间距变为100px:

<style>
    .father {
        background-color: yellow;
        /* 触发BFC */
        overflow: hidden;
    }
    .son {
        width: 100px;
        height: 100px;
        background-color: blue;
        margin: 50px;
    }
</style>
<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 内边距包含塌陷

父子关系的盒子中,给子盒子加了margin-top,父盒子也会跟着一起下去。

<style>
    .top {
        height: 50px;
        width: 200px;
        background-color: pink;
    }
    .father {
        width: 200px;
        height: 200px;
        background-color: yellow;
    }
    .son {
        width: 100px;
        height: 100px;
        background-color: blue;
        margin-top: 50px;
    }
</style>
<body>
    <div class="top">顶部元素</div>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

可以利用 BFC 特性来解决包含塌陷问题。将父盒子设置为一个 BFC,这样父盒子内部的样式就不会影响到外部的布局了。

<style>
    .top {
        height: 50px;
        width: 200px;
        background-color: pink;
    }
    .father {
        width: 200px;
        height: 200px;
        background-color: yellow;
        /* 触发BFC */
        overflow: hidden;
    }
    .son {
        width: 100px;
        height: 100px;
        background-color: blue;
        margin-top: 50px;
    }
</style>
<body>
    <div class="top">顶部元素</div>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 清除浮动带来的影响

一个没有设置高度的父盒子,里面一个子盒子设置了浮动,那么父盒子失去了高度,不显示在页面上了。

<style>
    .top {
        height: 50px;
        width: 200px;
        background-color: pink;
    }
    .father {
        width: 200px;
        background-color: yellow;
    }
    .son {
        width: 100px;
        height: 100px;
        background-color: blue;
        float: left;
    }
</style>
<body>
    <div class="top">顶部元素</div>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

可以利用 BFC 特性来解决浮动问题。因为父盒子没有高度了,必然影响了外部元素的布局。那将父盒子触发 BFC,这样父盒子内部的子盒子就不会影响到外部布局了:

<style>
    .top {
        height: 50px;
        width: 200px;
        background-color: pink;
    }
    .father {
        width: 200px;
        background-color: yellow;
        /* 触发BFC */
        overflow: hidden;
    }
    .son {
        width: 100px;
        height: 100px;
        background-color: blue;
        float: left;
    }
</style>
<body>
    <div class="top">顶部元素</div>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 阻止浮动元素覆盖标准流

两个为兄弟关系的盒子,其中一个盒子设置浮动时,另一个还是标准流,那么浮动的盒子会覆盖标准流的盒子,显示出如下效果:

<style>
    .div1 {
        width: 100px;
        height: 100px;
        background-color: blue;
        float: left;
    }
    .div2 {
        height: 300px;
        background-color: yellow;
        font-size: 26px;
    }
</style>
<body>
    <div class="div1"></div>
    <div class="div2">
        我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

标准流的盒子(黄色的盒子)中的文字受到了浮动流盒子(蓝色盒子)的影响,文字环绕蓝色盒子周围。

可以利用 BFC 特性来解决这个问题。标准流盒子触发 BFC,浮动元素就不会覆盖标准流盒子了,也不会影响到里面的文字:

<style>
    .div1 {
        width: 100px;
        height: 100px;
        background-color: blue;
        float: left;
    }
    .div2 {
        height: 300px;
        background-color: yellow;
        font-size: 26px;
        /* 触发BFC */
        overflow: hidden;
    }
</style>
<body>
    <div class="div1"></div>
    <div class="div2">
        我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。我被挤开了。
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21