CSS分类面试题

CSS 单位总结

经典真题

  • pxem 的区别

CSS 中的哪些单位

首先,在 CSS 中,单位分为两大类,绝对长度单位相对长度单位

绝对长度单位

我们先来说这个,绝对长度单位最好理解,和我们现实生活中是一样的。在我们现实生活中,常见的长度单位有米(m)、厘米(cm)、毫米(mm),每一种单位的长度都是固定,比如 5cm,你走到任何地方 5cm 的长度都是一致的

例如:

<div class="container"></div>
.container{
  width: 5cm;
  height: 5cm;
  background-color: pink;
}

在上面的代码中,我们设置了盒子的宽高都是 5cm,这里用的就是绝对长度单位。

常见的绝对单位长度如下:

image-20210914153818508

这些值中的大多数在用于打印时比用于屏幕输出时更有用。例如,我们通常不会在屏幕上使用 cm

惟一一个经常使用的值,估计就是 px(像素)。

相对长度单位

相对长度单位相对于其他一些东西,比如父元素的字体大小,或者视图端口的大小。使用相对单位的好处是,经过一些仔细的规划,我们可以使文本或其他元素的大小与页面上的其他内容相对应。

下表列出了 web 开发中一些最有用的单位。

image-20210914154021389

上面的单位中,常用的有 em、rem、vw、vh,其中 vwvh 代表的是视口的宽度和高度,例如:

<div class="container"></div>
*{
  margin: 0;
  padding: 0;
}
.container {
  width: 50vw;
  height: 100vh;
  background-color: pink;
}

在上面的代码中,我们设置了容器的宽度为 50vw,也就是占视口的一半,而高度我们设置的是 100vh,就是占满整个视图。

接下来来看一下 emrem

emrem 相对于 px 更具有灵活性,他们是相对长度单位,意思是长度不是定死了的,更适用于响应式布局。

对于 emrem 的区别一句话概括:em 相对于父元素,rem 相对于根元素。

来看关于 emrem 示例。

em 示例

<div>
  我是父元素div
  <p>
    我是子元素p
    <span>我是孙元素span</span>
  </p>
</div>
* {
  margin: 0;
  padding: 0;
}

div {
  font-size: 40px;
  width: 10em;
  /* 400px */
  height: 10em;
  outline: solid 1px black;
  margin: 10px;
}

p {
  font-size: 0.5em;
  /* 20px */
  width: 10em;
  /* 200px */
  height: 10em;
  outline: solid 1px red;
}

span {
  font-size: 0.5em;
  width: 10em;
  height: 10em;
  outline: solid 1px blue;
  display: block;
}

效果:

image-20210914155219732

rem 示例

rem 是全部的长度都相对于根元素,根元素是谁?

那就是 html元素。通常做法是给 html 元素设置一个字体大小,然后其他元素的长度单位就为 rem

例如:

<div>
  我是父元素div
  <p>
    我是子元素p
    <span>我是孙元素span</span>
  </p>
</div>
* {
  margin: 0;
  padding: 0;
}

html {
  font-size: 10px;
}

div {
  font-size: 4rem;
  /* 40px */
  width: 30rem;
  /* 300px */
  height: 30rem;
  /* 300px */
  outline: solid 1px black;
  margin: 10px;
}

p {
  font-size: 2rem;
  /* 20px */
  width: 15rem;
  /* 150px */
  height: 15rem;
  /* 150px */
  outline: solid 1px red;
}

span {
  font-size: 1.5rem;
  width: 10rem;
  height: 10rem;
  outline: solid 1px blue;
  display: block;
}

所以当用 rem 做响应式时,直接在媒体中改变 htmlfont-size,此时用 rem 作为单位的元素的大小都会相应改变,很方便。

看到这里我想大家都能够更深刻的体会了 emrem 的区别了,其实就是参照物不同。

真题解答

  • pxem 的区别

参考答案:

pxpixel 像素,是相对于屏幕分辨率而言的,是一个绝对单位,但是具有一定的相对性。因为在同一设备上每个设备像素所代表的物理长度是固定不变的(绝对性),但在不同设备间每个设备像素所代表的物理长度是可以变化的(相对性)。

em 是相对长度单位,具体的大小要相对于父元素来计算,例如父元素的字体大小为 40px,那么子元素 1em 就代表字体大小和父元素一样为 40px0.5em 就代表字体大小为父元素的一半即 20px

-EOF-

居中方式总结

经典真题

  • 怎么让一个 div 水平垂直居中

盒子居中

首先题目问到了如何进行居中,那么居中肯定分 2 个方向,一个是水平方向,一个是垂直方向。

水平方向居中

水平方向居中很简单,有 2 种常见的方式:

  1. 设置盒子 margin : 0 auto:这种居中方式的原理在于设置 margin-leftauto 时,margin-left 就会被设置为能有多大就设置多大,所以盒子会跑到最右边,而设置 margin-rightauto 时,同理盒子就会跑到最左边。所以,当我们设置左右的 margin 都是 auto 的时候,盒子就跑到了中间,从而形成了水平居中。

  2. 第二种常见的方式就是通过 display : flex 设置盒子的外层盒子是一个弹性盒,然后通过 justify-content : center 使得内部的盒子居中。

垂直方向居中

关于盒子的垂直方向居中,方法就比较多了,这里介绍几种:

  1. 通过 verticle-align:middle 实现垂直居中

通过 vertical-align:middle 实现垂直居中是最常使用的方法,但是有一点需要格外注意,vertical 生效的前提是元素的 display:inline-block。并且在使用 vertical-align:middle 的时候需要一个兄弟元素做参照物,让它垂直于兄弟元素的中心点。vertical-align 对齐的方法是寻找兄弟元素中最高的元素作为参考。

代码示例如下:

<div class="container">
  <div class="item"></div>
  <div class="brotherBox"></div>
</div>
.container{
  width: 500px;
  height: 300px;
  background-color: pink;
  text-align: center;
}
.item{
  width: 100px;
  height: 100px;
  background-color: skyblue;
  vertical-align: middle;
  margin: 0 auto;
  display: inline-block;
}
.brotherBox{
  height: 100%;
  /* width: 2px; */
  background: red;
  display: inline-block;
  vertical-align: middle;
}
  1. 通过伪元素 :before 实现垂直居中

平白无故添加一个无意义的参考元素不怎么好,我们可以去除作为参考的兄弟元素,转为给父元素添加一个伪元素,如下:

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 500px;
  height: 300px;
  background-color: pink;
  text-align: center;
}
.container::before{
  content : '';
  display: inline-block;
  vertical-align: middle;
  height: 100%;
}
.item{
  width: 100px;
  height: 100px;
  background-color: skyblue;
  vertical-align: middle;
  margin: 0 auto;
  display: inline-block;
}
  1. 通过绝对定位实现垂直居中

这种方式需要设置父元素为相对定位,子元素为绝对定位,然后配合 margin-left 为负的盒子高度一半来实现垂直居中

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 500px;
  height: 300px;
  background-color: pink;
  position: relative;
}
.item{
  width: 100px;
  height: 100px;
  background-color: skyblue;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -50px;
  margin-top: -50px;
}
  1. 通过 transform 实现垂直居中

可以通过定位配合 transform 也可以实现垂直居中

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 500px;
  height: 300px;
  background-color: pink;
  position: relative;
}
.item{
  width: 100px;
  height: 100px;
  background-color: skyblue;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateX(-50px) translateY(-50px);
}
  1. 使用弹性盒子居中

通过设置父元素为弹性盒子,然后使用 justify-content: centeralign-items: center 来设置内部盒子水平垂直居中

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 500px;
  height: 300px;
  background-color: pink;
  display: flex;
  justify-content: center;
  align-items: center;
}
.item{
  width: 100px;
  height: 100px;
  background-color: skyblue;
}

以上就是比较常见的盒子居中的解决方案,当然目前来讲最推荐的就是使用弹性盒子,这是目前最常用的一种方式,也是最推荐的一种方式。

真题解答

  • 怎么让一个 div 水平垂直居中

参考答案:

  1. 通过 verticle-align:middle 实现垂直居中
  2. 通过父元素设置伪元素 :before ,然后设置子元素 verticle-align:middle 实现垂直居中
  3. 通过绝对定位实现垂直居中
  4. 通过 transform 实现垂直居中
  5. 使用弹性盒子居中

-EOF-

隐藏元素方式总结

经典真题

  • 隐藏页面中的某个元素的方法有哪些?

隐藏元素方案汇总

首先什么叫隐藏元素,大家第一反应就是 display:none,元素就被隐藏了。

没错,这确实是隐藏元素的一种,但是太过于片面。我们隐藏元素实际上可以分为 3 大类:

  • 完全隐藏:元素从渲染树中消失,不占据空间。
  • 视觉上的隐藏:屏幕中不可见,占据空间。
  • 语义上的隐藏:读屏软件不可读,但正常占据空间。

完全隐藏

display 属性

首先就是设置 displaynone,这样元素就被隐藏了,并且是不占据空间的。

hidden 属性

这是 HTML5 新增属性,相当于 display: none,直接写在元素上面,例如:

<div hidden></div>

视觉上隐藏

视觉上的隐藏,就是说元素还占据着位置,只是视觉上不可见而已。

opacity 属性

这是大家比较熟知的一种方式,将透明度设置为 0,视觉上就会变得不可见。

opacity:0

visibility:hidden

这也是大家比较熟知的一种方式,通过 CSS 中的 visibility 属性来隐藏元素,使其不可见,但是仍然会占位

visibility:hidden

绝对定位

这种方式以前用的比较多,设置 posoitionabsolutefixed,通过设置 top、left 等值,将其移出可视区域。例如:

position: absolute;
left: -999px;
top: -999px;

设置 margin

通过设置 margin 值,将其移出可视区域范围(可视区域占位)。例如:

margin-left: -99999px;

设置宽高为 0

这也是比较常见的一种方式,简单说就是将元素的 margin、border、padding、heightwidth 等影响元素盒模型的属性设置成 0,如果元素内有子元素或内容,还应该设置其 overflow:hidden 来隐藏其子元素

width: 0px;
height: 0px;
overflow: hidden

裁剪元素

隐藏元素的另一种方法是通过剪裁它们实现,具体是通过 clip-path 属性,这个属性比较新,浏览器兼容性也会比较差,但是了解一下还是非常有必要的。例如:

clip-path: polygon(0px 0px,0px 0px,0px 0px,0px 0px);

语义上隐藏

aria-hidden 属性

通过设置 aria-hidden 属性为 true 使读屏软件不可读,但是元素仍然占据空间并且可见。

<div aria-hidden="true"></div>

真题解答

  • 隐藏页面中的某个元素的方法有哪些?

参考答案:

隐藏元素可以分为 3 大类:

  • 完全隐藏:元素从渲染树中消失,不占据空间。
  • 视觉上的隐藏:屏幕中不可见,占据空间。
  • 语义上的隐藏:读屏软件不可读,但正常占据空。

完全隐藏的方式有:设置 display:none、为元素设置 hidden 属性。

视觉上隐藏的方式有:设置 opacity 属性为 0、绝对定位的 lefttop 值设置为 -999px、设置 margin-left 值为 -999px、设置宽高为 0、裁剪元素。

语义上的隐藏方式为将 aria-hidden 属性设置为 true 使读屏软件不可读。

-EOF-

浮动

经典真题

  • 清除浮动的方法
  • 以下选项能够清除浮动的是( )

A. 空 div

B. hover 伪选择器

C. clear 属性

D. overflow 属性

关于浮动,你需要知道的东西

浮动出现的背景

浮动属性产生之初是为了实现“文字环绕”的效果,让文字环绕图片,从而使网页实现类似 word 中“图文混排”的效果。来看下面的例子:

<div class="container">
  <img src="./ok.png" alt="" width="200">
  <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Doloribus quos est rerum repellat alias maiores
    nobis harum recusandae corrupti assumenda qui aut ipsam deserunt dolorem modi, culpa hic ex illo repellendus
    atque. Numquam iste porro perspiciatis. Harum esse magni exercitationem, perspiciatis libero soluta quo ea
    dolorem. Delectus tempore magnam vitae voluptatibus, non quasi laudantium, aliquam consequuntur perspiciatis
    maiores esse neque animi voluptate. Animi pariatur debitis quam aliquam recusandae quis ut nisi totam sint
    consectetur distinctio, quos saepe cum quo iure natus delectus! Ad, dolore. Ut temporibus ea autem fugiat
    laboriosam quidem iste rerum laborum. Repellendus recusandae sequi id excepturi alias?</p>
</div>
.container {
  width: 800px;
  border: 1px solid;
}

效果如下:

image-20210918111724895

由于 p 段落是块级元素,所以独占一行,图片和段落是分开的。

接下来我们设置图片浮动:

.container {
  width: 800px;
  border: 1px solid;
}
img{
  float: left;
}

效果如下:

image-20210918112006064

当我们设置了图片浮动后,就出现了类似 “word” 的文字环绕效果。

这实际上也是浮动最初被设计出来的目的。

浮动实现布局

到了后面,浮动渐渐被应用到了页面布局上。因为 HTML 里面的元素,要么是行内元素,要么是块级元素,这种方式是没办法做页面布局的,例如我想实现两个块级元素在一行。此时开发人员就想到了浮动,因为任何东西都可以浮动,而不仅仅是图像,所以浮动的使用范围扩大了,能够用来进行布局。

两列布局

下面我们来看一下使用浮动实现的两列布局:

<h1>2 column layout example</h1>
<div>
  <h2>First column</h2>
  <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem
    placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet
    nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum,
    tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada
    et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus
    sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius
    commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p>
</div>

<div>
  <h2>Second column</h2>
  <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est,
    posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam
    lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis
    finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in
    interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
</div>
body {
  width: 90%;
  max-width: 900px;
  margin: 0 auto;
}

div:nth-of-type(1) {
  width: 48%;
  float: left;
}

div:nth-of-type(2) {
  width: 48%;
  float: right;
}

效果:

image-20210918130208288

在上面的代码中,我们让两个 div 一个左浮动一个右浮动,从而实现了两列布局的效果。

三列布局

现在我们已经有了一个两列布局工作,添加一个第三列(或更多)并不是太难。

下面是一个使用浮动实现的三列布局。

<h1>3 column layout example</h1>
<div>
  <h2>First column</h2>
  <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem
    placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet
    nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum,
    tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada
    et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus
    sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius
    commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p>
</div>

<div>
  <h2>Second column</h2>
  <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est,
    posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam
    lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis
    finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in
    interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
</div>
<div>
  <h2>Third column</h2>
  <p>Nam consequat scelerisque mattis. Duis pulvinar dapibus magna, eget congue purus mollis sit amet. Sed euismod
    lacus sit amet ex tempus, a semper felis ultrices. Maecenas a efficitur metus. Nullam tempus pharetra
    pharetra. Morbi in leo mauris. Nullam gravida ligula eros, lacinia sagittis lorem fermentum ut. Praesent
    dapibus eros vel mi pretium, nec convallis nibh blandit. Sed scelerisque justo ac ligula mollis laoreet. In
    mattis, risus et porta scelerisque, augue neque hendrerit orci, sit amet imperdiet risus neque vitae lectus.
    In tempus lectus a quam posuere vestibulum. Duis quis finibus mi. Nullam commodo mi in enim maximus
    fermentum. Mauris finibus at lorem vel sollicitudin.</p>
</div>
body {
  width: 90%;
  max-width: 900px;
  margin: 0 auto;
}

div:nth-of-type(1) {
  width: 36%;
  float: left;
}

div:nth-of-type(2) {
  width: 30%;
  float: left;
  margin-left: 4%;
}

div:nth-of-type(3) {
  width: 26%;
  float: right;
}

效果:

image-20210918130610163

浮动的特性

在上面,我们已经实现了两列布局和三列布局,可以看出,浮动确实能够拿来布局。

接下来我们就需要具体研究一下浮动有哪些特性了。

  1. 脱离标准流

浮动的第一个特点就是脱离标准流,例如:

<div class="one"></div>
<div class="two"></div>
.one {
  width: 80px;
  height: 80px;
  background-color: red;
  float: left;
}

.two {
  width: 150px;
  height: 150px;
  background-color: blue;
}

效果如下:

image-20210918131127272

由于红色的 div 浮动脱离了标准流,所以蓝色的 div 自然而然就往上走了。

  1. 浮动的元素互相贴靠

如果有多个浮动的元素,那么会相互贴靠,如果宽度不够,会重启一行。

.two {
  width: 150px;
  height: 150px;
  background-color: blue;
  float: left;
}

还是上面的 DOM 结构,我们让 two 这个盒子也浮动,效果如下:

image-20210918131424633

如果宽度不足以让后面的盒子贴靠,那么后面浮动的元素会被排列到下一行:

.two {
  width: 850px;
  height: 150px;
  background-color: blue;
  float: left;
}

效果:

image-20210918131627324

在上面的示例中,我们将蓝色盒子的宽度修改为了 850px,当我们缩小浏览器时,由于宽度不够蓝色盒子重新排列到了第二排。

  1. 宽度收缩

在没有设置宽度的情况下,块级元素在标准流时很多时独占一行,宽度也会占满整个容器,但是一旦被设置为浮动后,宽度就会收缩。

例如:

<div>this is a test</div>
div{
  background-color: red;
  float: left;
}

本来 div 是占满整行的,但是当我们设置了浮动后,由于 div 又没有设置宽度,所以宽度就收缩了。

清除浮动

有些时候,浮动会带来副作用,所以我们需要清除浮动带来的副作用。

例如:

<ul>
  <li>导航1</li>
  <li>导航2</li>
  <li>导航3</li>
</ul>
<ul>
  <li>游戏</li>
  <li>动漫</li>
  <li>音乐</li>
</ul>
li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

效果:

image-20210918132700157

在上面的示例中,我们本来是打算做两个导航栏的,但是由于浮动的贴靠性质,导致所有的 li 都在一行了。

这个时候我们就需要一些方式来清除浮动。

  1. 给父元素设置高度

在上面的示例中,由于 li 的父元素 ul 没有高度,所以导致明明不是同一个父元素下的浮动子元素,也会相互贴靠。

此时我们就给 li 的父元素 ul 设置一个高度即可。例如:

ul{
  height: 50px;
}
li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

效果:

image-20210918133638708

需要注意给父元素设置高度时,这个高度值一定要大于浮动子元素的高度,这样才能关注浮动。例如:

ul{
  height: 30px;
}
li {
  float: left;
  width: 100px;
  height: 70px;
  background-color: pink;
}

效果:

image-20210918133928678

在上面的示例中,虽然我们给父元素 ul 设置了高度,但是这个高度值是小于浮动元素 li 的高度的,此时我们会发现仍然有贴靠的现象。

因此,如果一个元素要浮动,那么它的祖先元素一定要有高度。有高度的盒子,才能关住浮动

只要浮动在一个有高度的盒子中,那么这个浮动就不会影响后面的浮动元素。所以就是清除浮动带来的影响了。

  1. clear 属性

在实际开发中,由于盒子的高度能够被内容撑开,所以很多时候我们不会设置高度。

那么这个时候又该如何清除浮动呢?

CSS 中有一个叫做 clear 的属性,该属性定义了元素的哪边上不允许出现浮动元素。

CSS1CSS2 中,这是通过自动为清除元素(即设置了 clear 属性的元素)增加上外边距实现的。

CSS2.1 中,会在元素上外边距之上增加清除空间,而外边距本身并不改变。不论哪一种改变,最终结果都一样,如果声明为左边或右边清除,会使元素的上外边框边界刚好在该边上浮动元素的下外边距边界之下。

clear 属性的取值如下:

image-20210918141612213

接下来我们来用 clear 属性清除浮动:

<ul>
  <li>导航1</li>
  <li>导航2</li>
  <li>导航3</li>
</ul>
<ul class="two">
  <li>游戏</li>
  <li>动漫</li>
  <li>音乐</li>
</ul>
.two{
  clear: left;
}
li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

效果:

image-20210918143310665

可以看到,浮动的副作用确实是清除了,但是这种方式有一个问题,那就是 margin 属性失效了。

例如我们在 two 的样式里面添加一个 margin-top,会发现该 margin 属性的设置并不起效果。

  1. 隔墙法

隔墙法的核心思想就是在两个浮动的元素之间添加一个空的 div 作为一堵“墙”,从而让后面的浮动元素,不去追前面的浮动元素。

例如:

<ul>
  <li>导航1</li>
  <li>导航2</li>
  <li>导航3</li>
</ul>
<div class="clearfix"></div>
<ul class="two">
  <li>游戏</li>
  <li>动漫</li>
  <li>音乐</li>
</ul>
.two {
  margin-top: 10px;
}

.clearfix {
  clear: both;
}

li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

效果:

image-20210918144154274

通过上面的示例我们可以看到,margin 已经恢复正常。

  1. 内墙法

通过隔墙法,后面又衍生出了内墙法。内墙法的出现,可以让浮动的元素也能撑开父元素的高。

正常情况下,没有高的父元素,里面的子元素一旦浮动,高度也就没有了,例如:

<div>
  <p></p>
</div>
div{
  background-color: green;
}
p{
  width: 100px;
  height: 100px;
  background-color: red;
}

当前效果:

image-20210918145912989

一旦我们设置 p 元素为浮动,由于脱离了标准流,所以父元素的高也就消失了。

此时就可以使用内墙法来给父元素撑起高,如下:

<div>
  <p></p>
  <div class="clearfix"></div>
</div>
div{
  background-color: green;
}
p{
  width: 100px;
  height: 100px;
  background-color: red;
  float: left;
}
.clearfix{
  clear: both;
}

效果:

image-20210918150838625

下面是使用内墙法清除浮动的示例:

<div>
  <ul>
    <li>导航1</li>
    <li>导航2</li>
    <li>导航3</li>
  </ul>
  <div class="clearfix"></div>
</div>
<ul class="two">
  <li>游戏</li>
  <li>动漫</li>
  <li>音乐</li>
</ul>
.two {
  margin-top: 10px;
}

.clearfix {
  clear: both;
}

li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

效果如下:

image-20210918151358700

在上面的代码中,我们使用内墙法清除了浮动,并且父元素的高度也被撑起来了,margin 也是正常的。

  1. overflow 属性

overflow 属性本来是用作处理溢出内容的显示方式的。

当给父元素添加 overflow:hidden 之后,父元素就会形成一个 BFC,一块独立的显示区域,不受外界影响,所以通过这种方式也能够去除浮动的副作用。

<ul>
  <li>导航1</li>
  <li>导航2</li>
  <li>导航3</li>
</ul>
<ul class="two">
  <li>游戏</li>
  <li>动漫</li>
  <li>音乐</li>
</ul>
.two {
  margin-top: 10px;
}

ul {
  overflow: hidden;
}

li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

在上面的代码中,我们设置两个父元素 ul 都为 overflow:hidden 之后,两个父元素形成了 BFC,我们可以看到父元素的高度也被撑开了,margin 也是正常的。

  1. 伪类清除法

最后要介绍的,是目前最流行的浮动清除方式,伪类清除法。

该方法的核心思想就是为父元素设置一个伪元素,其实就是无形的添加了一堵墙,然后在伪元素中设置一系列的属性。例如:

<ul class="one">
  <li>导航1</li>
  <li>导航2</li>
  <li>导航3</li>
</ul>
<ul class="two">
  <li>游戏</li>
  <li>动漫</li>
  <li>音乐</li>
</ul>
.two {
  margin-top: 10px;
}

.one::after {
  content: "";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
}

li {
  float: left;
  width: 100px;
  height: 20px;
  background-color: pink;
}

在上面的代码中,我们为第一个 ul 设置了 after 伪元素,并在伪元素中设置了诸如 clear:both、visibility: hidden 等一系列属性,这实际上就等同于在两个 ul 之间添加了一堵无形的墙。

浮动的现状

上面介绍了很多清除浮动的方法,一会儿外墙法、一会儿内墙法、一会儿 overflow,这些其实都是时代的眼泪。

目前来讲,除非要考虑古老的 IE6/IE7,否则布局压根儿就不会考虑浮动,有更好的弹性盒模型和网格布局供我们使用。

浮动目前仅仅也就在要制作文字环绕效果时,能发挥一席之地的作用。

然而,文字环绕这种 90 年代看着还不错的设计,现在又有几个设计师会这样设计网页呢?

真题解答

  • 清除浮动的方法

参考答案:

  • clear 清除浮动(添加空 div 法)在浮动元素下方添加空 div,并给该元素写 css 样式 {clear:both;height:0;overflow:hidden;}

  • 给浮动元素父级设置高度

  • 父级同时浮动(需要给父级同级元素添加浮动)

  • 父级设置成 inline-block,其 margin: 0 auto 居中方式失效

  • 给父级添加 overflow:hidden 清除浮动方法

  • 万能清除法 after 伪类清浮动(现在主流方法,推荐使用)

  • 以下选项能够清除浮动的是( B )

A. 空 div

B. hover 伪选择器

C. clear 属性

D. overflow 属性

-EOF-

定位总结

经典真题

  • 介绍下 positon 属性
  • position 有哪些值,各自的用法如何?
  • 相对定位、绝对定位、固定定位的区别

CSS 中的定位

经常有同学混淆定位与布局,两者傻傻分不清。

布局是针对整个页面来讲的,你采用什么布局,两栏布局、三栏布局,目标是整个页面。

而定位是针对某一个元素来讲的,把这个元素定位到什么位置。

目前在 CSS 中,有 5 种定位方案,分别是:

  • static 静态定位
  • relative 相对定位
  • absolute 绝对定位
  • fixed 固定定位
  • sticky 粘性定位

下面我们依次来介绍这几种定位。

static 静态定位

所谓静态定位,就是我们的标准流。

在标准流里面,块级元素独占一行,内嵌元素共享一行。静态定位是 HTML 元素的默认值,静态定位的元素不会受到 top,bottom,left,right 的影响。

relative 相对定位

所谓相对定位,就是相对自己原来的位置进行定位。相对定位的最大特点就是不脱离标准流,相对于自己原来的位置上进行一定的偏移。

来看一个示例:

<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
*{
  margin: 0;padding: 0;
}
div{
  width: 100px;
  height: 100px;
  outline: 1px solid;
  line-height: 100px;
  text-align: center;
}
.two{
  position: relative;
  left: 50px;
  top: 50px;
}

效果如下:

image-20210916102648561

可以看到,我们对 two 这个盒子设置了 left 值为 50pxtop 值为 50px,而由于是相对这个位置进行偏移,所以 two 这个盒子向右下进行了移动。

使用相对定位的作用主要有两个:

  • 微调元素
  • 做绝对定位的参考,子绝父相

absolute 绝对定位

所谓绝对定位,就是相对于离自己最近的,并且定了位的元素进行偏移。使用了绝对定位后的盒子,会脱离标准流,如果设置了 margin 的值为 auto,则会失效。

下面是一个绝对定位的示例:

<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
*{
  margin: 0;padding: 0;
}
div{
  width: 100px;
  height: 100px;
  outline: 1px solid;
  line-height: 100px;
  text-align: center;
}
.two{
  position: absolute;
  left: 50px;
  top: 50px;
}

效果如下:

image-20210916102923743

在浏览器中可以看到,第 3div 往上面移动了,从而证明了绝对定位是脱离标准流的。

绝对定位后的盒子,其 display 属性会变为 block,例如:

<a href="#">百度一下</a>
*{
  margin: 0;padding: 0;
}
a{
  outline: 1px solid;
  width: 100px;
  height: 100px;
  position: absolute;
  top: 50px;
  left: 50px;
}

在浏览器中的浏览效果如下:原本不能设置宽高的行内元素,在进行了绝对定位以后,display 属性变为了 block,所以可以设置宽高了。

image-20210916103159181

这里要重点强调一下绝对定位的参考点问题。默认情况下,绝对定位的参考点,如果用 top 来进行描述,那么定位参考点就是页面的左上角,而不是浏览器的左上角,如下图:

image-20210916103254157

如果是使用 bottom 来进行描述,那么就是浏览器首屏窗口尺寸,对应的页面左下角,如下图:

image-20210916103329049

下面是一道爱立信 2014 年的校园春招题目,该题目就是考察关于绝对定位默认参考点的相关知识,如下:

image-20210916103403155

该题目的答案如下:

image-20210916103442461

上面介绍的是绝对定位里参考点的默认情况,但是这种情况一般使用得非常的少。更多的则是使用接下来我们将要介绍的参照标准。

前面我们在介绍相对定位的时候,有提到子绝父相这个名字。事实上,当我们对一个元素设置绝对定位的时候,往往会将它的父级元素设置为相对定位。

这样的好处在于该元素的父级元素没有脱离标准流,该元素将会以这个相对定位了的父元素作为参考点,在父元素的范围内进行移动,方便我们对元素的位置进行掌控。如下图:

image-20210916103531326

在该图中,容器盒子设置为相对定位,红色盒子为绝对定位。红色盒子将无视父元素的 padding 区域,以父元素的 border 内侧作为自己定位的参考点。

需要大家记住的是当父级元素出现有定位时,绝对定位的参考点永远都是离自己最近的,并且定了位的祖先元素的左上角,下面我们来举例子进行说明,如下:

<div class="one">
  <div class="two">
    <div class="three"></div>
  </div>
</div>
*{
  margin: 0;padding: 0;
}
.one{
  width: 200px;
  height: 200px;
  outline: 1px solid;
  position: absolute;
  top: 100px;
  left: 100px;
}
.two{
  width: 100px;
  height: 100px;
  outline: 1px solid red;
  position: absolute;
  top: 50px;
  left: 50px;
}
.three{
  width: 50px;
  height: 50px;
  background-color: pink;
  position: absolute;
  top: 0;
  left: 0;
}

在浏览器中的浏览效果如下:这里 three 盒子就是以 two 盒子的左上角作为的参考点

image-20210916103730739

如果我们对代码稍作修改,取消 two 盒子的定位,那么 three 盒子就会以 one 盒子的左上角来作为参考点,如下:

.two{
  width: 100px;
  height: 100px;
  outline: 1px solid red;
  margin: 50px 0 0 50px; /* 使用margin来让该盒子进行一些偏离 */      
}

在浏览器中的浏览效果如下:

image-20210916103916507

fixed 固定定位

所谓固定定位,可以看作是一种特殊的绝对定位,所以自然而然固定定位也是会脱离标准流的。

固定定位的特点是相对于浏览器窗口进行定位的。

换句话说,对一个盒子进行固定定位以后,无论页面如何滚动,这个盒子的显示位置都是不会变化的。

固定定位在 PC 端中经常用于显示在页面中位置固定不变的页面 header,以及移动端中位置固定不变的 headerfooter

sticky 粘性定位

CSS3 中,新增了一种定位方式:sticky

sticky,中文的字面意思是“粘,粘贴”的意思,所以这种定位方式可以称之为粘性定位。

目前大部分浏览器都已经支持了这种定位方式。

image-20210916104626067

要设置一个元素的定位方式为粘性定位,首先需要将 position 属性设置为 sticky

position: sticky;   /* 设置定位方式为粘性定位 */

接下来有如下几个需要注意的点:

  • 父元素的 overflow 必须是 visible,不能是 hidden 或者 auto,因为父节点定位设置为 overflow:hidden 则父容器无法进行滚动。
  • 父元素的高度不能低于 sticky 元素的高度 。
  • 如果父元素没有设置定位(position:relative | absolute | fixed),则相对于 viewprot 进行定位,否则以定位的父元素为参考点。
  • 设置阀值:需要指定 toprightbottomleft 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。并且 topbottom 同时设置时,top 生效的优先级高;leftright 同时设置时,left 的优先级高。

下面是一个粘性定位的示例:

<h1>我是标题,题题,题,...</h1>
<nav>
  <h3>导航A</h3>
  <h3>导航B</h3>
  <h3>导航C</h3>
</nav>
<article>
  <p>今晚的爱奇艺尖叫之夜中,唐嫣上台领取年度戏剧女艺人奖,主持人朱丹希望她分享婚后甜蜜,可唐嫣已经下台,引发网友质疑场面尴尬。刚刚,朱丹发文回应,表示唐嫣没有不礼貌,自己也没有尴尬。随后,唐嫣也评论:“美丽的误会”
  </p>
  <p>韩寒:我的生活有两个节点,一个是出书,另一个就是写博客。出书让我有了收入,博客让我有了跟读者的连接。我从小就被贴过很多标签,每多一个标签就更接近真实的我。微博也一样,每一次更新都跟随着时代的风向,与时代同行。</p>
  <p>《游戏人生》作者榎宫祐 表示,近日有朋友想成为漫画家,过来找他商量。<br>
    他:“漫画家相当于无职啊,月收入又低,如果请助手花费更大。”(为了让朋友知道现实,又不否定梦想的小心翼翼的说法)<br>
    朋友:“可是我有一栋公寓用来收租唉......”<br>
    他:“那你想怎么活就怎么活吧!” ​​​​</p>
  <p>【湖北一小学三年级才教数学,校长回应争议:实验班的成绩远高于对比班】湖北赤壁一小学施行三年级才上数学课的教学设置,引起关注。该校校长表示,数学是一个抽象思维的功课,6岁的小孩是形象思维发展的最佳期,应该把数学往后移,按照知识发展规律。从三年级开始学数学,用3年时间学完原本5年的课程是可行的,并且经过3年的实验,实验班的成绩都要远高于对比班。
  </p>
  <p>刘国梁:暮然回首这一路走来⋯⋯感恩国家队30年的培养,把我从一个13岁的孩子,培养成大满贯、总教练、再到乒协主席🏓️[心]感谢这么多年跟我一起努力征战国际赛场的教练员和运动员,是你们辛勤的付出取得的荣耀造就了今天的自己[抱抱][心]感动的是亿万国人和球迷粉丝,这么多年不离不弃的支持,才有了今日国乒的新辉煌。赢不狂.输不慌.陪国乒.战东京!
  </p>
</article>
body {
  height: 5000px;
  /* 为了让页面可以滑动 */
}

nav {
  display: flex;
  justify-content: start;
  width: 100%;
  position: sticky;
  /* 设置定位方式为粘性定位 */
  top: 20px;
  /* 设置阀值,滚动到 top 值为 20px 的时候不再能够滚动*/
}

nav h3 {
  outline: 1px solid #fff;
  background-color: #333;
  color: #fff;
  text-align: center;
  padding: 10px;
}

真题解答

  • position 有哪些值,各自的用法如何?

参考答案:

目前在 CSS 中,有 5 种定位方案,分别是:

  1. static:该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。

  2. relative:相对定位的元素是在文档中的正常位置偏移给定的值,但是不影响其他元素的偏移。

  3. absolute:相对定位的元素并未脱离文档流,而绝对定位的元素则脱离了文档流。在布置文档流中其它元素时,绝对定位元素不占据空间。绝对定位元素相对于最近的非 static 祖先元素定位。

  4. fixed:固定定位与绝对定位相似,但元素的包含块为 viewport 视口。该定位方式常用于创建在滚动屏幕时仍固定在相同位置的元素。

  5. sticky:粘性定位可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。

-EOF-

BFC

经典真题

  • 介绍下 BFC 及其应用
  • 介绍下 BFC、IFC、GFCFFC

搞懂各种 FC

一看到 BFC、IFC、GFCFFC,大家可能会想到 KFC

image-20210913134223247

然而这里所说的 xFCKFC 没有任何关系。

那么这些 FC 究竟是啥呢?

不着急,我们先搞懂一个,后面的陆陆续续也就融会贯通了。

我们首先就来看这个 BFC,英语全称 Block formatting contexts,翻译成中文就是“块级格式化上下文”。

简单来说,就是页面中的一块渲染区域,并且有一套属于自己的渲染规则,它决定了元素如何对齐内容进行布局,以及与其他元素的关系和相互作用。 当涉及到可视化布局的时候,BFC 提供了一个环境,HTML 元素在这个环境中按照一定规则进行布局。

再简短一点,那就是:BFC 是一个独立的布局环境,BFC 内部的元素布局与外部互不影响

这就好比你在你自己家里面,你想怎么摆放你的家具都可以,你家的家具布局并不会影响邻居家的家具布局。

当然,虽然说 BFC 是一个独立的布局环境,里外不影响,但也不是意味着布局没有章法,基本的规矩还是要有的。

例如,BFC 的布局规则有如下几条:

  1. 内部的 Box 会在垂直方向一个接着一个地放置。
  2. Box 垂直方向上的距离由 margin 决定。属于同一个 BFC 的两个相邻的 Boxmargin 会发生重叠。
  3. 每个盒子的左外边框紧挨着包含块的左边框,即使浮动元素也是如此。
  4. BFC 的区域不会与浮动 Box 重叠。
  5. BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然。
  6. 计算 BFC 的高度时,浮动子元素也参与计算。

诶??

这好像在我们的 body 元素里面,盒子天然就是这样的布局规则呀?

没错,实际上在一个标准流中 body 元素就是一个天然的 BFC

那么如果其他区域,我想单独设置成一个 BFC,该怎么办呢?这里记录了一些常见的方式:

元素或属性属性值
根元素
floatleft、right
postionabsolute、fixed
overflowauto、scroll、hidden
displayinline-block、table-cell

上面只记录了一些常见的方式,完整的 BFC 触发方式可以参阅:https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context

那么块级格式化上下文有啥具体的用处呢?我们来看几个场景

  1. 解决浮动元素令父元素高度坍塌的问题
<div class="father">
   <div class="son"></div>
</div>
.father{
  border: 5px solid;
}
.son{
  width: 100px;
  height: 100px;
  background-color: blue;
  float: left;
}

在上面的代码中,父元素的高度是靠子元素撑起来的,但是一旦我们给子元素设置了浮动,那么父元素的高度就塌陷了。如下:

image-20210913140809007

此时我们就可以将父元素设置成一个 BFC,例如:

.father{
  border: 5px solid;
  overflow: hidden; 
  /* 将父元素设置为一个 BFC */
}
.son{
  width: 100px;
  height: 100px;
  background-color: blue;
  float: left;
}

效果:可以看到由于父元素变成 BFC,高度并没有产生塌陷了,其原因是在计算 BFC 的高度时,浮动子元素也参与计算

image-20210913140948390
  1. 非浮动元素被浮动元素覆盖
<div class="box1"></div>
<div class="box2"></div>
.box1{
  width: 100px;
  height: 50px;
  background-color: red;
  float: left;
}
.box2{
  width: 50px;
  height: 50px;
  background-color: blue;
}

在上面的代码中,由于 box1 设置了浮动效果,所以会脱离标准流,自然而然 box2 会往上面跑,结果就被高度和自己一样的 box1 给挡住了。

image-20210913141555490

接下来我们设置 box2BFC,如下:

.box1{
  width: 100px;
  height: 50px;
  background-color: red;
  float: left;
}
.box2{
  width: 50px;
  height: 50px;
  background-color: blue;
  overflow: hidden;
}

效果:由于 BFC 的区域不会与浮动 box 重叠,所以即使 box1 因为浮动脱离了标准流,box2 也不会被 box1 遮挡

image-20210913141805543

基于此特点,我们就可以制作两栏自适应布局,方法就是给固定栏设置固定宽度,给不固定栏开启 BFC

<div class="left">导航栏</div>
<div class="right">这是右侧</div>
*{
  margin: 0;
  padding: 0;
}
.left {
  width: 200px;
  height: 100vh;
  background-color: skyblue;
  float: left;
}

.right {
  width: calc(100% - 200px); 
  height: 100vh;
  background-color: yellowgreen;
}

效果:在上面的代码中,我们要设置两栏布局,左边栏宽度固定,右边栏自适应。结果我们发现右侧出现了空白

究其原因就是右侧区域与浮动盒子重叠了

image-20210913143033581

修改 .right 部分的代码,添加 overflow:hidden 使其成为一个 BFC

.right {
  width: calc(100% - 200px); 
  height: 100vh;
  background-color: yellowgreen;
  overflow: hidden;
}

效果:因为 BFC 的区域不会与浮动 Box 重叠,所以右侧空白没有了

image-20210913143330616
  1. 外边距垂直方向重合的问题

BFC 还能够解决 margin 折叠的问题,例如:

<div class="box1"></div>
<div class="box2"></div>
* {
  margin: 0;
  padding: 0;
}

.box1{
  width: 100px;
  height: 100px;
  background-color: red;
  margin-bottom: 10px;
}
.box2{
  width: 100px;
  height: 100px;
  background-color: blue;
  margin-top: 10px;
}

效果:

image-20210913143849932

此时我们可以在 box2 外部再包含一个 div,并且将这个 div 设置为 BFC,如下:

<div class="box1"></div>
<div class="container">
  <div class="box2"></div>
</div>
* {
  margin: 0;
  padding: 0;
}

.box1{
  width: 100px;
  height: 100px;
  background-color: red;
  margin-bottom: 10px;
}
.box2{
  width: 100px;
  height: 100px;
  background-color: blue;
  margin-top: 10px;
}
.container{
  overflow: hidden;
}

效果:

image-20210913144106258

OK,到这里你应该明白什么是 BFC 以及 BFC 的触发规则和其使用场景了。

明白了 BFC,那么其他的 IFC、GFCFFC 也就大同小异了。

  • IFCInline formatting context):翻译成中文就是“行内格式化上下文”,也就是一块区域以行内元素的形式来格式化
  • GFCGrideLayout formatting contexts):翻译成中文就是“网格布局格式化上下文”,将一块区域以 grid 网格的形式来格式化
  • FFCFlex formatting contexts):翻译成中文就是“弹性格式化上下文“,将一块区域以弹性盒的形式来格式化

更多关于格式化上下文的内容,可以参阅 MDN

BFChttps://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context

IFChttps://developer.mozilla.org/zh-CN/docs/Web/CSS/Inline_formatting_context

真题解答

  • 介绍下 BFC 及其应用

参考答案:

所谓 BFC,指的是一个独立的布局环境,BFC 内部的元素布局与外部互不影响。

触发 BFC 的方式有很多,常见的有:

  • 设置浮动
  • overflow 设置为 auto、scroll、hidden
  • positon 设置为 absolute、fixed

常见的 BFC 应用有:

  • 解决浮动元素令父元素高度坍塌的问题
  • 解决非浮动元素被浮动元素覆盖问题
  • 解决外边距垂直方向重合的问题
  • 介绍下 BFC、IFC、GFCFFC

参考答案:

  • BFC:块级格式上下文,指的是一个独立的布局环境,BFC 内部的元素布局与外部互不影响。
  • IFC:行内格式化上下文,将一块区域以行内元素的形式来格式化。
  • GFC:网格布局格式化上下文,将一块区域以 grid 网格的形式来格式化
  • FFC:弹性格式化上下文,将一块区域以弹性盒的形式来格式化

-EOF-

CSS 属性的计算过程

经典真题

  • 请简述 CSS 中属性的计算过程是怎样的

CSS 属性的计算过程

首先,让我们从最简单的代码开始,例如:

<p>this is a test</p>
p{
  color : red;
}

上面是一段很简单的代码,就一个段落,然后设置了一个颜色属性为红色。

那么,我们的这个段落真的就只有一个属性值 color 么?

no、no、no,真实的情况是这个元素所有的属性都拥有,只不过有一组默认的属性值。例如:

image-20210916145853445

当我们打开浏览器控制台,来到 Elements > Computed 面板,我们就会发现就算这么一个小小的 p,虽然我们只设置了一个 color 属性,但是其实它一个属性都没落下,每个属性都是有默认值。

所以这里我们要讨论一下这个属性值的计算过程是什么样子的。

总的来讲,属性值的计算方法有下面 4 种,这也是属性值的计算顺序:

  • 确定声明值
  • 层叠冲突
  • 使用继承
  • 使用默认值

确定声明值

当我们在样式表中对某一个元素书写样式声明时,这个声明就会被当作 CSS 的属性值。

举个例子:

<h1>test</h1>

在上面的代码中,我们没有书写任何的 CSS 样式,所以这个时候就采用浏览器的默认样式

font-size: 32px;
font-weight: 700

假设现在我们为这个 h1 设置一个样式:

font-size: 20px

这就是我们的作者样式,当作者样式和浏览器默认样式中的声明值有冲突时,会优先把作者样式中的声明值当作 CSS 的属性值。

font-weight 并没有和作者样式冲突,所以不受影响。

层叠冲突

当样式表声明值有冲突时,就会使用层叠规则来确定 CSS 的属性值

例如:

<div class="test">
  <h1>test</h1>
</div>
.test h1{
  font-size: 50px;
}

h1 {
  font-size: 20px;
}

在上面的代码中,两个选择器都选中了 h1,并且都设置了 font-size 属性值,同属于作者样式,这显然就属于层叠冲突了。

当发送层叠冲突时,这时就要根据选择器的权重值来计算究竟运用哪一条作者样式。

落败的作者样式在 Elements>Styles 中会被划掉

image-20210916151546500

使用继承

如果该条属性作者并没有设置,那么还不会着急去使用默认值,而是会去看一下能否继承到该属性值。例如:

<div class="test">
  <p>this is a test</p>
</div>
.test{
  color:red
}

在上面的代码中,我们虽然没有在 p 段落上书写 color 属性,但是该属性能够从 div 上面继承而来,所以最终计算出来的值就是 red

使用默认值

最终,如果没有作者样式,该属性值也无法继承而来,则会使用浏览器的默认样式。

真题解答

  • 请简述 CSS 中属性的计算过程是怎样的

参考答案:

1.确定声明值:参考样式表中没有冲突的声明,作为 CSS 属性值

2.层叠冲突:对样式表有冲突的声明使用层叠规则,确定 CSS 属性值

3.使用继承:对仍然没有值的属性,若可以继承则继承父元素的值

4.使用默认值:对仍然没有值得属性,全部使用默认属性值

-EOF-

CSS 层叠继承规则总结

经典真题

  • 请简述一下 CSS 中的层叠规则

CSS 中的层叠继承规则

在前面《CSS属性的计算过程》中,我们介绍了每一个元素都有都有所有的属性,每一个属性都会通过一系列的计算过程得到最终的值。

这里来回顾一下计算过程,大致有以下几个步骤:

  • 确定声明值
  • 层叠冲突
  • 使用继承
  • 使用默认值

其中的第二步和第三步层叠和继承会有一些需要注意的知识点,这里我们一起来看一下。

层叠规则

CSSCascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。

在最基本的层面上,它表明 CSS 规则的顺序很重要,但它比那更复杂。

什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的,前面的的一种会否决后一种):

  • 重要性(Importance
  • 专用性(Specificity
  • 源代码次序(Source order

重要性

CSS 中,有一个特别的语法可以让一条规则总是优先于其他规则: !important

知道 !important 存在是很有用的,这样当你在别人的代码中遇到它时,你就知道它是什么了。

但是!建议你千万不要使用它,除非你绝对必须使用它。您可能不得不使用它的一种情况是,当您在修改某个组件样式时,你不能编辑该组件核心的 CSS 模块,又或者你确实想要重写一种不能以其他方式覆盖的样式。

但是,如果你能避免的话,不要使用它。由于 !important 改变了层叠正常工作的方式,因此调试 CSS 问题,尤其是在大型样式表中,会变得非常困难。

专用性

专用性基本上是衡量选择器的具体程度的一种方法,主要是指它能匹配多少元素。

元素选择器具有很低的专用性。类选择器具有更高的专用性,所以将战胜元素选择器。ID 选择器有甚至更高的专用性, 所以将战胜类选择器,战胜 ID 选择器的方法则是 style 中的样式或者 !important

一个选择器具有的专用性的量可以用四种不同的值(或组件)来衡量的,它们可以被认为是千位,百位,十位和个位,在四个列中的四个简单数字:

  • 千位:如果声明是在 style 属性中该列加 1 分(这样的声明没有选择器,所以它们的专用性总是 1000)否则为 0
  • 百位:在整个选择器中每包含一个 ID 选择器就在该列中加 1 分。
  • 十位:在整个选择器中每包含一个类选择器、属性选择器、或者伪类就在该列中加 1 分。
  • 个位:在整个选择器中每包含一个元素选择器或伪元素就在该列中加 1 分。

注:通用选择器(*), 复合选择器(+、>、~、空格)和否定伪类(:not)在专用性中无影响。

举个例子:

选择器千位百位十位个位合计值
h100010001
#indentifier01000100
h1 + p::first-letter00030003
li > a[href*=” zh-CN”] > .inline-warning00220022
没有选择器, 规则在一个元素的 style 属性里10001000

源代码次序

如果多个相互竞争的选择器具有相同的重要性和专用性,那么第三个因素将帮助决定哪一个规则获胜,也就是说,选择哪一个选择器取决于源码顺序。

例如:

p {
    color: red;
}


p {
    color: blue;
}

不过有一点大家需要注意的是,当多个 CSS 规则匹配相同的元素时,它们都被应用到该元素中。只不过后面因为层叠规则被层叠掉了而已。打开 Elements > Styles 我们就能看到:

image-20210918094021662

继承规则

所谓继承,就是应用于某个元素的一些属性值将由该元素的子元素继承,而有些则不会。

究竟哪些属性能够被子元素继承,可以参阅:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference

CSS 为处理继承提供了四种特殊的通用属性值:

  • inherit:该值将应用到选定元素的属性值设置为与其父元素一样。
  • initial:该值将应用到选定元素的属性值设置为与浏览器默认样式表中该元素设置的值一样。如果浏览器默认样式表中没有设置值,并且该属性是自然继承的,那么该属性值就被设置为 inherit
  • unset:该值将属性重置为其自然值,即如果属性是自然继承的,那么它就表现得像 inherit,否则就是表现得像 initial
  • revert:如果当前的节点没有应用任何样式,则将该属性恢复到它所拥有的值。换句话说,属性值被设置成自定义样式所定义的属性(如果被设置), 否则属性值被设置成用户代理的默认样式。

注: initialunset 不被 IE 支持。

继承的就近原则

由于属性值是由继承而来,所以属性值会继承离自己近的那个元素的属性。例如:

<div class="one">
  <div class="two">
    <p>Lorem ipsum dolor sit amet.</p>
  </div>
</div>
.two {
  color: blue;
}

.one {
  color: red;
}

在上面的示例中,twoone 更加接近 p,所以最终采用的是 twocolor 值。段落呈现蓝色。

真题解答

  • 请简述一下 CSS 中的层叠规则

参考答案:

CSS 中当属性值发生冲突时,通过层叠规则来计算出最终的属性值,层叠规则可以分为 3 块:

  • 重要性(Importance):!important 设置该条属性值最重要,但是一般不推荐使用。
  • 专用性(Specificity):专用性主要是指它能匹配多少元素,匹配得越少专用性越高。
  • 源代码次序(Source order):在重要性和专用性都一致的情况下,属性值取决于源代码的先后顺序。

-EOF-

import 指令

经典真题

  • CSS 引用的方式有哪些?link@import 的区别?

来看看 import 指令是啥

import 指令是用来导入 CSS 样式的。

什么?导入样式不是已经有 link 标签了么?

没错,link 标签可以导入外部 CSS 样式,import 仍然可以导入外部 CSS 样式。

我们首先来看一下 import 的基本用法

  1. HTML 文件中导入外部样式
<style>
  @import url('./index.css');
</style>

要在 HTML 源代码直接应用 @import 引入外部 CSS 文件,须要将 @import 放入 style 标签

  1. CSS 文件中引入另一个 CSS 文件
@import url('./index.css');
/* 后面书写其他样式 */

除了 HTML 源代码中使用 style 标签来运用 @import,在 CSS 文件代码中依旧可以或许使用 @import,这个时候就不须要 style 标签,而是直接应用 @import 就可,这样便可实现一个(多个)CSS 文件中引入套入别的一个(多个)CSS 文件。

  1. @import 规则还支持媒体查询,因此可以允许依赖媒体的导入
@import "printstyle.css" print;
/* 只在媒体为 print 时导入 "printstyle.css" 样式表 */
@import "mobstyle.css" screen and (max-width: 768px);
/* 只在媒体为 screen 且视口最大宽度 768 像素时导入 "mobstyle.css" 样式表 */

看完了 @import 的基本使用后,接下来我们来看一下它和 link 的区别:

  1. link 属于 HTML 标签,而 @import 完全是 CSS 提供的一种方式。

    link 标签除了可以加载 CSS 外,还可以做很多其它的事情,比如定义 RSS,定义 rel 连接属性等,@import 就只能加载 CSS 了。

  2. 加载顺序的差别。

    比如,在 a.css 中使用 import 引用 b.css,只有当使用当使用 import 命令的宿主 css 文件 a.css 被下载、解析之后,浏览器才会知道还有另外一个 b.css 需要下载,这时才去下载,然后下载后开始解析、构建 render tree 等一系列操作.

  3. 兼容性的差别。

    由于 @importCSS2.1 提出的所以老的浏览器不支持,@import 只有在 IE5 以上的才能识别,而 link 标签无此问题。

  4. 当使用 JS 控制 DOM 去改变样式的时候,只能使用 link 标签,因为 @import 不是 DOM 可以控制的

    对于可换皮肤的网站而言,可以通过改变 link 标签这两个的 href 值来改变应用不用的外部样式表,但是对于 import 是无法操作的,毕竟不是标签。

另外,从性能优化的角度来讲,尽量要避免使用 @import

使用 @import 引入 CSS 会影响浏览器的并行下载。使用 @import 引用的 CSS 文件只有在引用它的那个 CSS 文件被下载、解析之后,浏览器才会知道还有另外一个 CSS 需要下载,这时才去下载,然后下载后开始解析、构建 Render Tree 等一系列操作。

多个 @import 会导致下载顺序紊乱。在 IE 中,@import 会引发资源文件的下载顺序被打乱,即排列在 @import 后面的 JS 文件先于 @import 下载,并且打乱甚至破坏 @import 自身的并行下载。

真题解答

  • CSS 引用的方式有哪些?link@import 的区别?

参考答案:

CSS 引用的方式有:

  • 外联,通过 link 标签外部链接样式表
  • 内联,在 head 标记中使用 style 标记定义样式
  • 嵌入,在元素的开始标记里通过 style 属性定义样式

link@import 的区别:

  1. link 属于 HTML 标签,而 @import 完全是 CSS 提供的一种方式。

    link 标签除了可以加载 CSS 外,还可以做很多其它的事情,比如定义 RSS,定义 rel 连接属性等,@import 就只能加载 CSS 了。

  2. 加载顺序的差别。

    比如,在 a.css 中使用 import 引用 b.css,只有当使用当使用 import 命令的宿主 css 文件 a.css 被下载、解析之后,浏览器才会知道还有另外一个 b.css 需要下载,这时才去下载,然后下载后开始解析、构建 render tree 等一系列操作.

  3. 兼容性的差别。

    由于 @importCSS2.1 提出的所以老的浏览器不支持,@import 只有在 IE5 以上的才能识别,而 link 标签无此问题。

  4. 当使用 JS 控制 DOM 去改变样式的时候,只能使用 link 标签,因为 @import 不是 DOM 可以控制的

    对于可换皮肤的网站而言,可以通过改变 link 便签这两个的 href 值来改变应用不用的外部样式表,但是对于 import 是无法操作的,毕竟不是标签。

-EOF-

CSS3calc 函数

经典真题

  • CSS 的计算属性知道吗?

CSS3 中的 calc 函数

calc 是英文单词 calculate(计算)的缩写,是 CSS3 的一个新增的功能。

MDN 的解释为可以用在任何长度、数值、时间、角度、频率等处,语法如下:

/* property: calc(expression) */
width: calc(100% - 80px);

可以用常见的 + - * / 符号来进行运算,但需要注意的是 + 和 - 必须用空格隔开,原因很简单,如果 - 号和计算的数字挨在一起,则浏览器在解析时会认为这可能是一个负值。

例如:

width: calc(100% -8px); /* 这样会出错,结果为0 */
width: calc(100% - 8px); /* 当 + -  符号用空格隔开时,运算成功 */

接下来我们来看一下 calc 函数的具体使用示例,如下:

<div class="container">
  <div class="item"></div>
</div>
* {
  margin: 0;
  padding: 0;
}

.container{
  width: 500px;
  height: 250px;
  background-color: skyblue;
  margin: 10px;
  position: relative;
}
.item{
  width: 100px;
  height: 100px;
  background-color: pink;
  position: absolute;
  left: calc(50% - 50px);
  top: calc(50% - 50px);
}

效果:

image-20210914174033014

更多关于 calc 函数信息可以参阅:https://developer.mozilla.org/zh-CN/docs/Web/CSS/calc()

真题解答

  • CSS 的计算属性知道吗?

参考答案:

calc( ) 函数,主要用于指定元素的长度,支持所有 CSS 长度单位,运算符前后都需要保留一个空格。

比如: width: calc(100% - 50px);

-EOF-

CSS3 的媒介(media)查询

经典真题

  • 如何使用媒体查询实现视口宽度大于 320px 小于 640pxdiv 元素宽度变成 30%

媒体查询

媒体查询英文全称 Media Query,顾名思义就是会查询用户所使用的媒体或者媒介。

在现在,网页的浏览终端是越来越多了。用户可以通过不同的终端来浏览网页,例如:PC,平板电脑,手机,电视等。尽管我们无法保证一个网站在不同屏幕尺寸和不同设备上看起来一模一样,但是至少要让我们的Web页面能适配用户的终端。

CSS3 中的 Media Query (媒体查询)模块就是用来让一个页面适应不同的终端的。

Media Type 设备类型

首先我们来认识一下 CSS 中所支持的媒体类型。

CSS2 中常碰到的就是 all(全部)、screen(屏幕)和 print(页面打印或打印预览模式)。然而媒体的类型其实远不止这 3 种。

W3C 中共列出了 10 种媒体类型,如下表所示:

设备类型
All所有设备
Braille盲人用点字法触觉回馈设备
Embossed盲文打印机
Handheld便携设备
Print打印用纸或打印预览视图
Projection各种投影设备
Screen电脑显示器
Speech语音或音频合成器
Tv电视机类型设备
Tty使用固定密度字母栅格的媒介,比如电传打字机和终端

当然,虽然上面的表列出来了这么多,但是常用的也就是 all(全部)、screen(屏幕)和 print(页面打印或打印预览模式)这三种媒体类型。

媒体类型引用方法

引用媒体类型的方法有和很多,常见的媒体类型引用方法有:link 标签、xml 方式、@importCSS3 新增的 @media

  1. link 方法

link 方法引入媒体类型其实就是在 link 标签引用样式的时候,通过 link 标签中的 media 属性来指定不同的媒体类型,如下:

<link rel="stylesheet" href="index.css" media="screen" />
<link rel="stylesheet" href="print.css" media="print" />
  1. xml 方式

xml 方式和 link 方式比较相似,也是通过 media 属性来指定,如下:

<? xml-stylesheet rel="stylesheet" media="screen" href="style.css" ?>
  1. @import

@import 引入媒体类型主要有两种方式,一种是在 CSS 样式表中通过 @import 调用另一个样式文件,另外一种是在 style 标签中引入。

注意:IE6IE7 中不支持该方式

在样式文件中引入媒体类型:

@import url('./index.css') screen

style 标签中引入媒体类型:

<style>
  @import url('./index.css') screen
</style>
  1. @meida 的方式

@mediaCSS3 中新引进的一个特性,称为媒体查询。@media 引入媒体也有两种方式,如下:

在样式文件中引入媒体类型:

@media screen{
  /* 具体样式 */
}

style 标签中引入媒体类型:

<style>
  @media screen{
    /* 具体样式 */
  }
</style>

虽然上面介绍了 4 种引入方式,但是最常见的就是第 1 种和第 4 种。

媒体查询具体语法

接下来我们来看一下媒体查询的具体语法。

这里我们可以将 Media Query 看成一个公式:

Media Type(判断条件)+ CSS(符合条件的样式规则)

这里举例如下:

link 的方式

<link rel="stylesheet" media="screen and (max-width:600px)" href="style.css" />

@media 的方式

@meida screen and (max-width:600px){
  /* 具体样式 */
}

上面的两个例子中都是使用 width 来进行的样式判断,但是实际上还有很多特性都可以被用来当作样式判断的条件。

具体如下表:

image-20210916165039143

有了 Media Query,我们能在不同的条件下使用不同的样式,使页面在不同的终端设备下达到不同的渲染效果。

这里有一个具体的公式如下:

@media 媒体类型 and (媒体特性) {
	/* 具体样式 */
}

来看几个具体示例。

  1. 最大宽度 max-width

该特性是指媒体类型小于或等于指定宽度时,样式生效,例如:

@media screen and (max-width:480px) {
	/* 具体样式 */
}

当屏幕宽度小于或等于 480px 时,样式生效

  1. 最小宽度 min-width

该特性和上面相反,及媒体类型大于或等于指定宽度时,样式生效,例如:

@media screen and (min-width:480px) {
	/* 具体样式 */
}

当屏幕宽度大于或等于 480px 时,样式生效

  1. 多个媒体特性混合使用

当需要多个媒体特性时,使用 and 关键字将媒体特性结合在一起,例如:

@media screen and (min-width:480px) and (max-width:900px){
	/* 具体样式 */
}

当屏幕大于等于 480px 并且小于等于 900px 时,样式生效。

  1. 设备屏幕的输出宽度 Device Width

在智能设备上,例如 iphone、ipad 等,可以通过 min-device-widthmax-device-width 来设置媒体特性,例如:

@media screen and (max-device-height:480px) {
	/* 具体样式 */
}

在智能设备上,当屏幕小于等于 480px 时样式生效

  1. not 关键字

not 关键词可以用来排除某种制定的媒体特性,示例如下:

@media not print and (max-width:900px) {
	/* 具体样式 */
}

样式代码将被用于除了打印设备和屏幕宽度小于或等于 900px 的所有设备中。

  1. 未指明 Media Type

如果在媒体查询中没有明确的指定 Media Type,那么其默认值为 all

@media (max-width: 900px){
  /* 具体样式 */
}

上面的样式适用于屏幕尺寸小于或等于 900px 的所有设备。

更多关于媒体查询的内容可以参阅 MDNhttps://developer.mozilla.org/zh-CN/docs/Web/CSS/Media_Queries/Using_media_queries

真题解答

  • 如何使用媒体查询实现视口宽度大于 320px 小于 640pxdiv 元素宽度变成 30%

参考答案:

@media screen and (min-width: 320px) and (max-width: 640px){
	div{
   width: 30%;
 }
}

-EOF-

过渡和动画事件

经典真题

  • CSS3transitionanimation 的属性分别有哪些(哔哩哔哩)
  • CSS 动画如何实现?

CSS3 过渡

CSS3 新增了过渡属性,可以使用从一个状态变化到另一个状态时,变化更加的平滑。

CSS3 的过渡功能像是一种黄油,W3C 标准中是这样描述 transition 的:

CSS3transition 允许 CSS 的属性值在一定的时间区间内平滑的过渡。这种效果可以在鼠标单击,获得焦点,对元素任何改变中触发,并平滑地以动画效果改变 CSS 的属性值。

先看一个快速入门示例,如下:

<div></div>
div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
}
div:hover{
  height: 300px;
}

在上面的代码中,我们让 divhover 的时候,改变其高度,但是我们可以看到效果非常的生硬。

此时我们就可以添加一个 CSS3 新增的属性 transition,使其两个状态变化之间产生一个过渡效果。

div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  transition: all .5s;
  /* 添加过渡效果 */
}
div:hover{
  height: 300px;
}

上面就是一个快速入门示例,接下来我们来看一下 transition 的具体语法。

transition 属性是 transition-property,transition-duration,transition-timing-functiontransition-delay 的一个简写属性。

  • transition-property:指定过渡的 CSS 属性
  • transition-duration:指定过渡所需的完成时间
  • transition-timing-function:指定过渡函数
  • transition-delay:指定过渡的延迟时间

transition-property

该属性用来指定过渡动画 CSS 属性名称,该属性的语法如下:

transition-property: none | all | property

image-20210915094158901

需要特别说明的是,并不是所有的属性都可以进行过渡,只有属性是具有一个中点值的属性才能够进行过渡效果。因为这样才能通过不停的修改中间值从而实现过渡效果。例如 display:none|block 就没有中间值,所以无法应用过渡。

能够过渡的属性类型有颜色属性、具有长度值或百分比的属性、阴影、变形系列属性,具体支持过渡的属性可以参阅下表:

支持过渡的属性
background-colorbackground-positionborder-bottom-colorborder-bottom-width
border-left-colorborder-left-widthborder-right-colorborder-right-width
border-spacingborder-top-colorborder-top-widthbottom
clipcolorfont-sizefont-weight
heightleftletter-spacingline-height
margin-bottommargin-leftmargin-rightmargin-top
max-heightmax-widthmin-heightmin-width
opacityoutline-coloroutline-widthpadding-bottom
padding-leftpadding-rightpadding-topright
text-indenttext-shadowvertical-alignvisibility
widthword-spacingz-index

transition-duration

该属性主要用于设置一个属性过渡到另一个属性所需要的时间,单位为秒(s)或者毫秒(ms)。默认值为 0,代表变换是即时的。

transition-timing-function

该属性用于设置过渡的速度,有如下的取值:

image-20210915094104556

transition-delay

过渡延迟多久触发,单位为秒或者毫秒。但是值可以是正整数,负整数和 0

正整数和 0 都比较好理解,这里主要说一下负整数。负整数的计算会从整体过渡时间中去做减法运算,举个例子:

div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  transition: all 5s -2s;
  /* 设置为 -2s,相当于已经执行了 2s */
}
div:hover{
  height: 300px;
}

多个元素过渡

如果要对多个 CSS3 属性应用过渡效果,直接用逗号分离开即可,这种主要是针对每个属性过渡的时间不同的情况下。

例如下面的例子:背景颜色过渡时间为 2s,而宽度的过渡时间为 5s

div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  transition: background-color 2s, height 5s;
}
div:hover{
  height: 300px;
  background-color: pink;
}

当然,如果每个属性的过渡时间都一样的话,那么直接使用 all 会更简洁一些。

hover 时期不同的过渡设置

我们可以在 hover 时对状态的变化设置一个过渡效果,鼠标移开元素恢复时设置另一个过渡效果。例如:

div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  transition: all 5s
    /* 鼠标移走时的过渡 */
}
div:hover{
  height: 300px;
  background-color: pink;
  transition: all 2s;
  /* 鼠标 hover 时状态变化的过渡 */
}

过渡事件

有些时候,在 JS 中的某些操作需要过渡效果结束后再执行,此时事件类型中给我们提供了一个 transitionend 事件方便我们监听过渡效果是否结束,例如:

<div id="oDiv"></div>
div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  transition: all 3s
}
var div = document.getElementById("oDiv");
div.onclick = function(){
  div.style.height = "400px";
}
div.ontransitionend = function(){
  console.log("过渡结束后触发");
}

CSS3 动画

CSS3 中新增了一个 animation 模块,可以制作出类似于 flash 一样的动画出来。

我们首先还是来看一个快速入门示例,如下:

<div></div>
*{
  margin: 0;
  padding: 0;
}
div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  position: absolute;
  animation: test 5s;
}
@keyframes test{
  0% {
    left: 0;
    top: 0;
  }
  25% {
    left: 400px;
    top: 0;
  }
  40% {
    left: 400px;
    top: 200px;
  }
  65% {
    left: 0;
    top: 200px;
  }
  100% {
    left: 0;
    top: 0;
  }
}

在上面的代码示例中,我们声明了一个名为 test 的动画,然后在 div 中运用了这个动画,整个动画的播放时间为 5s

接下来我们来看一下 CSS3 中动画的具体细节。

使用 CSS3animation 制作动画包含两个部分:首先是用关键帧声明一个动画,其次是在 animation 调用关键帧声明的动画。

声明动画

CSS3 中,使用 @keyframes 来声明一个动画,语法为:

@keyframes animationname {keyframes-selector {css-styles;}}

属性对应的说明如下:

image-20210915101256811

在上面的示例中,我们声明动画的代码为:

@keyframes test{
  0% {
    left: 0;
    top: 0;
  }
  25% {
    left: 400px;
    top: 0;
  }
  40% {
    left: 400px;
    top: 200px;
  }
  65% {
    left: 0;
    top: 200px;
  }
  100% {
    left: 0;
    top: 0;
  }
}

这里我们就声明了一个名为 test 的动画,设置了 5 个时间段,分别是 0%、25%、40%、65%100%,每个时间段都有对应的不同 CSS 样式,当动画执行时,从一个时间段到另一个时间段会自动运用过渡效果,所以我们可以看到整个流程是非常平滑的。

使用动画

@keyframes 只是用来声明一个动画,如果一个声明的动画不被调用,那么这个动画是没有任何意义的。

CSS3 中通过 animation 属性来调用动画。

语法如下:

animation: name duration timing-function delay iteration-count direction fill-mode play-state;
  • animation-name:指定要绑定到选择器的关键帧的名称
  • animation-duration:动画指定需要多少秒或毫秒完成
  • animation-timing-function:设置动画将如何完成一个周期
  • animation-delay:设置动画在启动前的延迟间隔
  • animation-iteration-count:定义动画的播放次数
  • animation-direction:指定是否应该轮流反向播放动画
  • animation-fill-mode:规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式
  • animation-play-state:指定动画是否正在运行或已暂停

前面 4 个属性没什么好说,大体上和前面介绍的 transition 的属性很像,这里我们主要看一下后面几个属性。

animation-iteration-count

animation-iteration-count 属性定义动画应该播放多少次,如果想要一直播放,那么次数就是无限次,所以属性值为 infinite

animation-direction

正常情况下,动画播放完毕以后,会立刻回到起始的状态。例如:

@keyframes test{
  0% {
    left: 0;
    top: 0;
  }
  50% {
    left: 400px;
    top: 0;
  }
  100% {
    left: 400px;
    top: 200px;
  }
}

对上面快速入门的示例稍作修改,我们就会发现,动画播放完毕后立马就回到起始状态了。

那么 animation-direction 就可以设置动画是否要反向播放回去。该属性对应的可设置值有:

animation-direction: normal|reverse|alternate|alternate-reverse|initial|inherit;
image-20210915104829295

需要注意的是,如果动画被设置为只播放一次,该属性将不起作用。

另外,无论动画正向播放还是反向播放,都会算一次次数,例如:

div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  position: absolute;
  animation: test 5s 5 alternate;
}
@keyframes test{
  0% {
    left: 0;
    top: 0;
  }
  50% {
    left: 400px;
    top: 0;
  }
  100% {
    left: 400px;
    top: 200px;
  }
}

在上面的代码中,我们设置一共播放 5 次,那么整个动画就会正向播放 3 次,反向播放 2 次。

animation-fill-mode

animation-fill-mode 属性规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。

一般主要用于设置动画播放完毕后的状态。

animation-fill-mode: none|forwards|backwards|both|initial|inherit;

image-20210915105722895

用得最多的值就是 forwards,定义动画播放完后保持结束时候的样子。默认值为 none,表示动画将按预期进行和结束,在动画完成其最后一帧时,动画会反转到初始帧处。当取值为 backwards 时,会在动画结束时迅速应用动画的初始帧。

animation-play-state

animation-play-state 属性规定动画正在运行还是暂停,语法为:

animation-play-state: paused|running;

image-20210915110118784

该属性一般配合着 JS 一起使用,从而达到对动画播放状态的一个控制。例如:

<button id="playAnimate">播放动画</button>
<button id="pauseAnimate">暂停动画</button>
<div id="oDiv"></div>
*{
  margin: 0;
  padding: 0;
}
div {
  width: 100px;
  height: 100px;
  background-color: skyblue;
  position: absolute;
  animation: test 2s 5 alternate paused;
}
@keyframes test{
  0% {
    left: 0;
    top: 30px;
  }
  50% {
    left: 400px;
    top: 30px;
  }
  100% {
    left: 400px;
    top: 200px;
  }
}
var oDiv = document.getElementById("oDiv");
var playAnimate = document.getElementById("playAnimate");
var pauseAnimate = document.getElementById("pauseAnimate");
playAnimate.onclick = function(){
  oDiv.style.animationPlayState = "running"
}
pauseAnimate.onclick = function(){
  oDiv.style.animationPlayState = "paused"
}

在上面的示例中,我们就通过 JS 来控制 animation-play-state 从而切换动画播放与暂停这两个状态。

动画对应事件

同样,动画也有对应的事件,与过渡只提供有 transitionend 事件不同的是,在 CSS 动画播放时,会发生以下三个事件:

  • animationstartCSS 动画开始后触发
  • animationiterationCSS 动画重复播放时触发
  • animationendCSS 动画完成后触发

真题解答

  • CSS3transitionanimation 的属性分别有哪些(哔哩哔哩)

参考答案:

transition 过渡动画:

  • transition-property:指定过渡的 CSS 属性
  • transition-duration:指定过渡所需的完成时间
  • transition-timing-function:指定过渡函数
  • transition-delay:指定过渡的延迟时间

animation 关键帧动画:

  • animation-name:指定要绑定到选择器的关键帧的名称
  • animation-duration:动画指定需要多少秒或毫秒完成
  • animation-timing-function:设置动画将如何完成一个周期
  • animation-delay:设置动画在启动前的延迟间隔
  • animation-iteration-count:定义动画的播放次数
  • animation-direction:指定是否应该轮流反向播放动画
  • animation-fill-mode:规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式
  • animation-play-state:指定动画是否正在运行或已暂停
  • CSS 动画如何实现?

参考答案:

animation 属性,对元素某个或多个属性的变化进行控制,可以设置多个关键帧。属性包含了动画的名称、完成时间(以毫秒计算)、周期、间隔、播放次数、是否反复播放、不播放时应用的样式、动画暂停或运行。

它不需要触发任何事件就可以随着时间变化来改变元素的样式。

使用 CSS 做动画

  • @keyframes 规定动画。
  • animation 所有动画属性的简写属性。
  • animation-name 规定 @keyframes 动画的名称。
  • animation-duration 规定动画完成一个周期所花费的秒或毫秒。默认是 0。
  • animation-timing-function 规定动画的速度曲线。默认是 ease
  • animation-fill-mode 规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。
  • animation-delay 规定动画何时开始。默认是 0
  • animation-iteration-count 规定动画被播放的次数。默认是 1
  • animation-direction 规定动画是否在下一周期逆向地播放。默认是 normal
  • animation-play-state 规定动画是否正在运行或暂停。默认是 running

-EOF-

渐进增强和优雅降级

经典真题

  • 说说渐进增强和优雅降级?
  • 你能描述一下渐进增强和优雅降级之间的不同吗?

渐进增强和优雅降级

渐进增强,英语全称 progressive enhancement,指的是针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级,英语全称 graceful degradation,一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

这两个概念其实并不是一个新的概念,就是以前提到的"向上兼容"和"向下兼容"。渐进增强相当于向上兼容,优雅降级相当于向下兼容。向下兼容指的是高版本支持低版本,或者说后期开发的版本能兼容早期开发的版本。

在确定用户群体的前提下,渐进增强:针对低版本浏览器进行页面构建,保证基本功能,再针对高级浏览器进行效果、交互等改进和追加功能,达到更好的用户体验。

优雅降级:一开始就构建完整的功能,再针对低版本浏览器进行兼容。

区别:优雅降级是从复杂的现状开始并试图减少用户体验的供给,而渐进增强则是从一个基础的、能够起到作用的版本开始再不断扩充,以适应未来环境的需要。

例如看下面这两段代码的书写顺序,看上去只是书写顺序的不同,实则表示了我们开发的着重点:

.transition { /*渐进增强写法*/
  -webkit-transition: all .5s;
     -moz-transition: all .5s;
       -o-transition: all .5s;
          transition: all .5s;
}
.transition { /*优雅降级写法*/
          transition: all .5s;
       -o-transition: all .5s;
     -moz-transition: all .5s;
  -webkit-transition: all .5s;
}

前缀 CSS3(-webkit-、-moz-、-o-)和正常 CSS3 在浏览器中的支持情况是这样的:

  1. 很久以前:浏览器前缀 CSS3 和正常 CSS3 都不支持
  2. 不久之前:浏览器只支持前缀 CSS3不支持正常 CSS3
  3. 现在:浏览器既支持前缀 CSS3又支持正常 CSS3
  4. 未来:浏览器不支持前缀 CSS3仅支持正常 CSS3

渐进增强的写法,优先考虑老版本浏览器的可用性,最后才考虑新版本的可用性。在时期 3 前缀 CSS3 和正常 CSS3 都可用的情况下,正常 CSS3 会覆盖前缀 CSS3

优雅降级的写法,优先考虑新版本浏览器的可用性,最后才考虑老版本的可用性。在时期 3 前缀 CSS3 和正常 CSS3 都可用的情况下,前缀 CSS3 会覆盖正常的 CSS3

绝大多少的大公司都是采用渐进增强的方式,因为业务优先,提升用户体验永远不会排在最前面。

  • 例如新浪微博网站这样亿级用户的网站,前端的更新绝不可能追求某个特效而不考虑低版本用户是否可用。一定是确保低版本到高版本的可访问性再渐进增强。

  • 如果开发的是一面面向青少面的软件或网站,你明确这个群体的人总是喜欢尝试新鲜事物,喜欢炫酷的特效,喜欢把软件更新至最新版本,这种情况再考虑优雅降级。

真题解答

  • 说说渐进增强和优雅降级?

参考答案:

渐进增强,英语全称 progressive enhancement,指的是针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级,英语全称 graceful degradation,一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

-EOF-

CSS3 变形

经典真题

  • 请简述一下 CSS3 中新增的变形如何使用?

CSS3 变形相关知识

变形介绍

CSS2.1 中的页面都是静态的,多年来,Web 设计师依赖于图片、Flash 或者 JavaScript 才能完成修改页面的外观。CSS3 改变了设计师这种思维,借助 CSS3 可以轻松的倾斜、缩放、移动以及翻转元素。

20129 月,W3C 组织发布了 CSS3 变形工作草案。允许 CSS 把元素变成 2D 或者 3D 空间,这其实就是 CSS32D 变形和 3D 变形。

CSS3 变形是一些效果的集合,比如平移、旋转、缩放和倾斜效果,每个效果通过变形函数(transform function)来实现。在此之前,要想实现这些效果,必须依赖图片、Flash 或者 JavaScript 才能完成,而现在仅仅使用纯 CSS 就能够实现,大大的提高了开发效率以及页面的执行效率。

变形效果要通过变形函数来实现,语法如下:

transform: none|transform-functions;

那么 CSS3 中为我们提供了哪些变形函数呢?

这里我们整体可以划分出 3 大类:

  • 具有 X/Y 的函数:translateX、translateY、sclaeX、scaleY、skewX、skewY
  • 2D 变形函数:translate、sclae、rotate、skew、matrix
  • 3D 变形函数:rotateX、rotateY、rotate3d、translateZ、translate3d、scaleZ、scale3d、matrix3d

此时,你可能已经做好了逐一击破每个变形函数的思想准备了。

别急,在介绍每个变形函数之前,我们先来了解一下变形相关的属性。

变形属性

  1. transform 属性

第一个首当其冲的就是 transform 属性,该属性所对应的属性值就是一系列的变形函数,例如:

transform: scale(1.5)

上面的代码中,我们设置了 transform 属性,属性值为 scale 变形函数。

  1. transform-origin 属性

接下来第二个是 transform-origin 属性,该属性用于设置元素的中心点位置。该属性语法如下:

transform-origin: x-axis y-axis z-axis;
image-20210919160036555

为了演示此属性的作用,我们先透支一点后面的知识。

这里我们以 rotate 为例。rotate 是变形函数中的一个,作用是旋转元素,其语法如下:

rotate(angle)

定义 2D 旋转,在参数中规定角度。

来看一个例子:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 200px;
  transition: all 1s;
}
div:hover{
  transform: rotate(45deg);
}

效果如下:

2021-09-19 16.06.26

在上面的示例中,我们设置 div 鼠标 hover 的时候进行变形,旋转 45 度,为了更加平滑,我们加入了 transition 过渡效果。

我们观察整个元素的旋转中心点,是在元素的最中央。

接下来我们可以使用 transform-origin 来修改这个中心点的位置。例如:

div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 200px;
  transition: all 1s;
  transform-origin: bottom left;
  /* 修改元素的中心点位置 */
}
div:hover{
  transform: rotate(45deg);
}

效果如下:

2021-09-19 16.09.46

在上面的代码中,我们修改了元素的中心点位置为 bottom、left,也就是左下角。可以看到因为元素的中心点位置发生了变化,旋转的方式也随之发生了改变。

transform-origin 的属性值除了像上面一样设置关键词以外,也可以是百分比、em、px 等具体的值。

transform-origin 的第三个参数是定义 Z 轴的距离,这在后面介绍 3D 变形时再来介绍。

  1. transform-style 属性

transform-style 属性是 3D 空间一个重要属性,指定了嵌套元素如何在 3D 空间中呈现。语法如下:

transform-style: flat | preserve-3d;
image-20210919171722656

其中 flat 为默认值。

需要注意的是该属性需要设置在父元素上面,使其变成一个真正的 3D 图形。

当然光看属性说明是非常模糊的,一点都不直观,我们直接来看一个例子。

<div class="box">
  <div class="up"></div>
  <div class="down"></div>
  <div class="left"></div>
  <div class="right"></div>
  <div class="forword"></div>
  <div class="back"></div>
</div>
.box {
  width: 250px;
  height: 250px;
  border: 1px dashed red;
  margin: 100px auto;
  position: relative;
  border-radius: 50%;
  transform-style: preserve-3d;
  animation: gun 8s linear infinite;
}

.box>div {
  width: 100%;
  height: 100%;
  position: absolute;
  text-align: center;
  line-height: 250px;
  font-size: 60px;
  color: #daa520;
}

.left {
  background-color: rgba(255, 0, 0, 0.3);
  transform-origin: left;
  transform: rotateY(90deg) translateX(-125px);
}

.right {
  background: rgba(0, 0, 255, 0.3);
  transform-origin: right;
  /* 变换*/
  transform: rotateY(90deg) translateX(125px);
}
.forward {
  background: rgba(255, 255, 0, 0.3);
  transform: translateZ(125px);
}
.back {
  background: rgba(0, 255, 255, 0.3);
  transform: translateZ(-125px);
}
.up {
  background: rgba(255, 0, 255, 0.3);
  transform: rotateX(90deg) translateZ(125px);
}
.down {
  background: rgba(99, 66, 33, 0.3);
  transform: rotateX(-90deg) translateZ(125px);
}
@keyframes gun {
  0% {
    transform: rotateX(0deg) rotateY(0deg);
  }

  100% {
    transform: rotateX(360deg) rotateY(360deg);
  }
}

效果如下:

2021-09-19 17.20.08

上面的 CSS 代码不用具体去关心,我们只看在 box 元素上面添加了一句 transform-style: preserve-3d,表示 box 里面的子元素都以 3D 的形式呈现。如果我们把这行代码去除掉或者值修改为 flat,效果如下:

2021-09-19 17.23.06

怎么样?是不是非常直观,一下子就知道 transform-style 属性的作用是什么了。该属性就是指定子元素是在 3D 空间还是 2D 平面中显示。

  1. perspective 属性

perspective 属性用于设置查看者的位置,可以将可视内容映射到一个视锥上,继而投到一个 2D 视平面上。如果不指定该属性,则 Z 轴空间中所有点将平铺到同一个 2D 视平面中,并且在变换结果中将不存在景深概念。

简单理解,就是视距,用来设置用户和元素 3D 空间 Z 平面之间的距离。而其效应由他的值来决定,值越小,用户与 3D 空间 Z 平面距离越近,视觉效果更令人印象深刻;反之,值越大,用户与 3D 空间 Z 平面距离越远,视觉效果就很小。

image-20210919174151244

注意当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。

我们还是来看一个直观的例子来了解这个属性的作用。例如:

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 500px;
  height: 500px;
  border: 1px solid;
  margin: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.item{
  width: 150px;
  height: 150px;
  background-color: red;
  animation: rotateAnimation 5s infinite;
}
@keyframes rotateAnimation {
  0%{
    transform: rotateY(0deg);
  }
  100%{
    transform: rotateY(360deg);
  }
}

效果:

2021-09-19 17.51.16

在上面的代码中,我们虽然设置了 div.item 沿着 Y 轴进行旋转,但是由于没有设置 perspective 视距,所以看上去就像是 div 盒子在宽度伸缩一样,3D 效果并不明显。

此时我们可以给父元素 div.container 设置 perspective 视距,例如:

.container{
  ...
  perspective: 1200px;
}

效果如下:

2021-09-19 17.54.08

很明显,加入 perspective 视距后,3D 旋转效果更佳的真实。

关于 perspective 的取值,接受一个长度单位大于 0,其单位不能为百分比的值。大致能够分为如下 3 种情况:

  • none 或者不设置:没有 3D 空间。
  • 取值越小:3D 效果越明显,也就是眼睛越靠近真 3D
  • 取值无穷大或者为 0:与取值为 none 的效果一样。
  1. perspective-origin 属性

如果理解了上面的 perspective 属性,那么这个 perspective-origin 就非常好理解了,该属性用来决定 perspective 属性的源点角度。

其语法如下:

perspective-origin: x-axis y-axis;
image-20210919204301259

举个例子:

.container{
  ...
  perspective: 600px;
  perspective-origin: top;
}

效果如下:

2021-09-19 20.45.00

由于我们设置的 perspective-origin 的值为 top,所以会呈现一种俯视的效果。如果将其值修改为 bottom,则会是仰视的即视感,如下:

2021-09-19 20.46.34
  1. backface-visibility 属性

backface-visibility 属性决定元素旋转背面是否可见。对于未旋转的元素,该元素的正面面向观看者。当其旋转 180 度时会导致元素的背面面向观众。

该属性是设置在旋转的元素上面,语法如下:

backface-visibility: visible|hidden;

image-20210919205231265

来看一个具体的例子:

.item{
  ...
  backface-visibility: hidden;
}

效果:

2021-09-19 21.38.25

在上面的代码中,我们在子元素 div.item 上设置了 backface-visibility: hidden,当此元素旋转 180 度到背面时,我们可以发现此时是无法看到背面的。

2D 变形

介绍完 CSS3 中变形的相关属性后,接下来我们就该来看一下具体的变形函数了。

整个 CSS3 为我们提供了相当丰富的变形函数,有 2D 的,有 3D 的。这里我们先来看 2D 的变形函数。

2D 位移

2D 位移对应有 3 个变形函数,分别是 translate、translateX、translateY

用法也非常简单,translate 方法从其当前位置移动元素(根据为 X 轴和 Y 轴指定的参数)。

div {
  transform: translate(50px, 100px);
}

上面的例子把 div 元素从其当前位置向右移动 50 个像素,并向下移动 100 个像素:效果如下:

Translate

2D 缩放

2D 缩放对应的也有 3 个变形函数,分别是 sclae、sclaeX、sclaeY

该方法能够按照倍数放大或缩小元素的大小(根据给定的宽度和高度参数)。默认值为 1,小于这个值就是缩小,大于这个值就是放大。

div {
  transform: scale(2, 3);
}

上面的例子把 div 元素增大为其原始宽度的两倍和其原始高度的三倍,效果如下:

Scale

2D 旋转

2D 旋转对应的只有 1 个变形函数 rotate,这个我们在前面也已经用过了。

该变形函数只接受一个值代表旋转的角度值,取值可正可负,正值代表顺时针旋转,负值代表逆时针旋转。

div {
  transform: rotate(20deg);
}

上面的例子把 div 元素顺时针旋转 20 度,效果如下:

Rotate

2D 倾斜

2D 倾斜对应的变形函数也是 3 个,分别是 skew、skewX、skewY

语法如下:

skew(ax, ay)
  • ax:指定元素水平方向(X 轴方向)倾斜角度
  • ay:指定元素垂直方向(Y 轴方向)倾斜角度
<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  transform: skew(20deg);
}

效果如下:

2021-09-19 22.02.15

2D 矩阵

虽然 CSS3 为我们提供了上述的变形函数方便我们进行元素的变形操作,但是毕竟函数个数有限,有些效果是没有提供的,例如镜像翻转的效果。此时就轮到 2D 矩阵函数 matrix 登场了。

matrix 有六个参数:

matrix(a,b,c,d,e,f)

六个参数对应的矩阵:

image-20210919221131755

这六个参数组成的矩阵与原坐标矩阵相乘计算坐标。计算方式如下:

image-20210919221104828

什么意思呢 ?xy 是元素中每一个像素的初始原点的坐标,而 x’y’ 是通过矩阵变化后得到的新原点坐标。通过中间 3 x 3 变换矩阵,对原先的坐标施加变换,从而得到新的坐标。

x’ = ax+cy+e,表示变换后的水平坐标

y’ = bx+dy+f,表示变换后的垂直位置

CSS3 中,上面我们所介绍的所有 2D 变形函数都能够通过这个 matrix 矩阵函数来替代。

矩阵实现偏移

我们首先来看通过矩阵实现偏移效果。

偏移效果前后 x、yx’、y’ 所对应的坐标公式为:

x' = x + 偏移量
y' = y + 偏移量

套用上面的公式那么各个参数的取值就应该是:

a = 1; b = 0;
c = 0; d = 1;
e = x 偏移量; f = y 偏移量
x' = ax+cy+e = 1x + 0y + x 偏移量 = x + x 偏移量
y' = bx+dy+f = 0x + 1y + y 偏移量 = y + y 偏移量

所以换成 matrix 函数就应该是:

matrix(1, 0, 0, 1, x 偏移量, y 偏移量)

下面来做一个测试:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: translate(100px, 200px); */
  transform: matrix(1, 0, 0, 1, 100, 200);
}

在上面的示例中,使用 translatematrix 两个变形函数的效果一致。

矩阵实现缩放

缩放之后 x、yx’、y’ 所对应的坐标公式为:

x' = x * x 缩放倍数
y’ = y * y 缩放倍数

套用上面的公式那就是:

a = x缩放倍数; b = 0;
c = 0; d = y 缩放倍数;
e = 0; f = 0;
x' = ax+cy+e = x缩放倍数 * x + 0y + 0 = x缩放倍数 * x
y' = bx+dy+f = 0x + y 缩放倍数 * y + 0 = y 缩放倍数 * y

所以换成 matrix 函数就应该是:

matrix(x 缩放倍数, 0, 0, y 缩放倍数, 0, 0);

例如:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: scale(2, 2); */
  transform: matrix(2, 0, 0, 2, 0, 0);
}

上面的代码我们分别使用 scale 和矩阵实现了相同的缩放效果。

矩阵实现旋转

旋转需要实现

水平倾斜角度 =  - 垂直倾斜角度

旋转我们用到的变形函数是 rotate(θ),其中 θ 为旋转的角度。套用上面的公式:

x' = xcosθ - ysinθ + 0 = xcosθ - ysinθ;
y' = xsinθ + ycosθ + 0 = xsinθ + ycosθ

转换为 matrix 的代码为:

matrix(cos(θ), sin(θ), -sin(θ), cos(θ), 0, 0)

例如:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: rotate(45deg); */
  transform: matrix(0.7, 0.7, -0.7, 0.7, 0, 0);
}

上面的代码使用了 rotatematrix 来实现旋转 45 度的效果。其中 sin45cos45 的值都为 0.7

矩阵实现倾斜

skew(θx, θy) 将一个元素按指定的角度在 X 轴和 Y 轴上倾斜。

倾斜对应的公式为:

x' = x + ytan(θx) + 0 = x + ytan(θx)
y' = xtan(θy) + y + 0 = xtan(θy) + y

转换为 matrix 的代码为:

matrix(1,tan(θy),tan(θx),1,0,0)

例如:

<div></div>
div {
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}

div:hover {
  /* transform: skew(20deg); */
  transform: matrix(1, 0, 0.4, 1, 0, 0);
}

上面的示例中分别使用 skew 和矩阵 matrix 实现了一致的倾斜效果。

矩阵实现镜像变形

前面介绍的效果,CSS3 中都提供了对应的变形函数,但是矩阵真正发挥威力是在没有对应的变形函数时,例如这里要讲的镜像变形。

我们先来看一下各种镜像变化 x、yx’、y’ 所对应的关系:

水平镜像,就是 y 坐标不变,x 坐标变负

x' = -x;
y' = y;

所以:

a = -1; b = 0; 
c = 0; d = 1; 
e = 0; f = 0;

具体示例如下:

<div></div>
div {
  width: 300px;
  height: 200px;
  margin: 150px;
  transition: all 1s;
  background: url('./ok.png') no-repeat;
  background-position: center;
  background-size: contain;
}

div:hover {
  transform: matrix(-1, 0, 0, 1, 0, 0);
}

效果:

2021-09-20 09.16.38

垂直镜像,就是 x 坐标不变,y 坐标变负

x' = x;
y' = -y;

所以:

a = 1; b = 0; 
c = 0; d = -1; 
e = 0; f = 0;

例如:

...
div:hover {
  transform: matrix(1, 0, 0, -1, 0, 0);
}

效果:

2021-09-20 09.19.11

水平镜像 + 倒立就是 y 坐标变负,x 坐标变负

x' = -x;
y' = -y;

所以:

a = -1; b = 0; 
c = 0; d = -1; 
e = 0; f = 0;

例如:

...
div:hover {
  transform: matrix(-1, 0, 0, -1, 0, 0);
}

效果:

2021-09-20 09.29.45

90 度旋转 + 镜像就是:

x' = y;
y' = x;

所以:

a = 0; b = 1; 
c = 1; d = 0; 
e = 0; f = 0;

例如:

...
div:hover {
  transform: matrix(0, 1, 1, 0, 0, 0);
}

效果:

2021-09-20 09.31.24

-90 度旋转 + 镜像就是:

x' = -y;
y' = -x;

所以:

a = 0; b = -1; 
c = -1; d = -0; 
e = 0; f = 0;

例如:

...
div:hover {
  transform: matrix(0, -1, -1, 0, 0, 0);
}

效果:

2021-09-20 09.32.47

通过上面一系列的示例,我们可以发现,使用矩阵 matrix 函数确实更佳灵活,能够写出各种变形效果。

3D 变形

使用二维变形能够改变元素在水平和垂直轴线,然而还有一个轴沿着它,可以改变元素。使用三维变形,可以改变元素在 Z 轴位置。

image-20210920104407743

三维变换使用基于二维变换的相同属性,如果熟悉二维变换就会发现,3D 变形的功能和 2D 变换的功能类似。CSS3 中的 3D 变换只要包含以下几类:

  • 3D 位移:包括 translateZtranslate3d 两个变形函数。
  • 3D 旋转:包括 rotateX、rotateY、rotateZrotate3d 这四个变形函数。
  • 3D 缩放:包括 scaleZsclae3d 两个变形函数。
  • 3D 矩阵:和 2D 变形一样,也有一个 3D 矩阵功能函数 matrix3d
3D 位移

我们直接来看合成变形函数 translate3d,其语法如下:

translate3d(tx, ty, tz)
  • tx:在 X 轴的位移距离。
  • ty:在 Y 轴的位移距离。
  • tz:在 Z 轴的位移距离。值越大,元素离观察者越近,值越小,元素离观察者越远

来看一个具体的示例:

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 400px;
  height: 400px;
  border: 1px solid;
  margin: 150px;
  display: flex;
  justify-content: center;
  align-items: center;
  perspective: 1000px;
}
.item {
  width: 300px;
  height: 200px;
  transition: all 1s;
  background: url('./ok.png') no-repeat;
  background-position: center;
  background-size: contain;
}

.item:hover {
  transform: translate3d(100px, 100px, -500px)
}

在上面的代码中,我们设置 div.itemhover 的时候进行 3D 位移,也就是 X、Y、Z 轴同时进行移动。注意这里要设置父元素的透视效果,也就是设置 perspective 值,否则看不出 Z 轴的移动效果。效果如下:

2021-09-20 10.40.24
3D 旋转

在三维变形中,可以让元素在任何轴旋转,对应的变形函数有 rotateX、rotateY、rotateZ 以及 rotate3d

其中 rotate3d 就是前面 3 个变形函数的复合函数。不过出了 x、y、z 这三条轴的参数以外,还接受第四个参数 a,表示旋转角度。

rotate3d(x, y, z, a)
  • x:可以是 01 之间的数值,表示旋转轴 X 坐标方向的矢量。
  • y:可以是 01 之间的数值,表示旋转轴 Y 坐标方向的矢量。
  • z:可以是 01 之间的数值,表示旋转轴 Z 坐标方向的矢量。
  • a:表示旋转角度。正的角度值表示顺时针旋转,负值表示逆时针旋转。

下面我们以 rotateX 变形函数为例:

<div class="container">
  <div class="item"></div>
</div>
.container{
  width: 400px;
  height: 400px;
  border: 1px solid;
  margin: 150px;
  display: flex;
  justify-content: center;
  align-items: center;
  perspective: 1000px;
}
.item {
  width: 150px;
  height: 150px;
  background-color: red;
  transition: all 1s;
}

.item:hover {
  transform: rotateX(45deg)
}

效果如下:

2021-09-21 21.23.14
3D 缩放

3D 缩放主要有 sclaeZscale3d,其中 scale3d 就是 scaleXscaleY 以及 scaleZ 的复合变形函数。其语法如下:

scale(sx, sy, sz)
  • sxX 轴上的缩放比例
  • syY 轴上的缩放比例
  • szZ 轴上的缩放比例

但是 scaleXscaleY 变形效果很明显,但是 scaleZ 却基本看不出有什么效果。原因很简单,scaleZZ 轴上面的缩放,也就是厚度上面的变化,所以如果不是立方体结构,基本上是看不出来 Z 轴上面的缩放效果的。

一般来讲,我们不会将 scaleZscale3d 单独使用,因为 scaleZscale3d 这两个变形函数在单独使用时没有任何效果,需要配合其他的变形函数一起使用时才会有效果。

这里我们以前面那个立方体为例,如下:

<div class="box">
  <div class="up"></div>
  <div class="down"></div>
  <div class="left"></div>
  <div class="right"></div>
  <div class="forword"></div>
  <div class="back"></div>
</div>
.box {
  width: 250px;
  height: 250px;
  border: 1px dashed red;
  margin: 100px auto;
  position: relative;
  border-radius: 50%;
  transform-style: preserve-3d;
  transition: all 1s;
  transform: rotateX(45deg) rotateY(45deg);
}

.box:hover{
  transform: rotateX(45deg) rotateY(45deg) scaleZ(.5);
}

.box>div {
  width: 100%;
  height: 100%;
  position: absolute;
  text-align: center;
  line-height: 250px;
  font-size: 60px;
  color: #daa520;
}

.left {
  background-color: rgba(255, 0, 0, 0.3);
  transform-origin: left;
  transform: rotateY(90deg) translateX(-125px);
}

.right {
  background: rgba(0, 0, 255, 0.3);
  transform-origin: right;
  /* 变换*/
  transform: rotateY(90deg) translateX(125px);
}

.forward {
  background: rgba(255, 255, 0, 0.3);
  transform: translateZ(125px);
}

.back {
  background: rgba(0, 255, 255, 0.3);
  transform: translateZ(-125px);
}

.up {
  background: rgba(255, 0, 255, 0.3);
  transform: rotateX(90deg) translateZ(125px);
}

.down {
  background: rgba(99, 66, 33, 0.3);
  transform: rotateX(-90deg) translateZ(125px);
}

效果如下:

2021-09-21 22.33.57

3D 矩阵

CSS3 中的 3D 矩阵比 2D 矩阵复杂,从二维到三维,在矩阵里 3*3 变成 4*4,即 916

对于 3D 矩阵而言,本质上很多东西与 2D 是一致的,只是复杂程度不一样而已。

对于 3D 缩放效果,其矩阵如下:

image-20210921225039133
matrix3d(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1)

倾斜是二维变形,不能在三维空间变形。元素可能会在 X 轴和 Y 轴倾斜,然后转化为三维,但它们不能在 Z 轴倾斜。

这里举几个 3D 矩阵的例子:

translate3d(tx,ty,tz) 等价于 matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,tx,ty,tz,1)

image-20210921225544059

scale3d(sx,sy,sz) 等价于 matrix3d(sx,0,0,0,0,sy,0,0,0,0,sz,0,0,0,0,1)

image-20210921225617731

rotate3d(x,y,z,a) 真是得搬出高中数学书好好复习一下了,第四个参数 alpha 用于 scsq

image-20210921225731310

等价于…你自己从上到下,从左到右依次将参数搬入 matrix3d 中吧。

当然除非是库函数需要,否则我严重怀疑是否会有人放着 rotate3d 不用,偏要去挑战用 matrix3d 模拟 rotate3d

真题解答

  • 请简述一下 CSS3 中新增的变形如何使用?

参考答案:

CSS3 中的变形分为 2D 变形和 3D 变形。

整体可以划分出 3 大类:

  • 具有 X/Y 的函数:translateX、translateY、sclaeX、scaleY、skewX、skewY
  • 2D 变形函数:translate、sclae、rotate、skew、matrix
  • 3D 变形函数:rotateX、rotateY、rotate3d、translateZ、translate3d、scaleZ、scale3d、matrix3d

另外,还有一些重要的变形属性,例如:

  • transform 属性
  • transform-origin 属性
  • transform-style 属性
  • perspective 属性
  • perspective-origin 属性
  • backface-visibility 属性

-EOF-

渐进式渲染

经典真题

  • 什么是渐进式渲染 ?

渐进式渲染

渐进式渲染,英文全称 progressive rendering,也被称之为惰性渲染,指的是为了提高用户感知的加载速度,以尽快的速度来呈现页面的技术。

在以前互联网带宽较小的时期,这种技术更为普遍。如今,移动终端的盛行,而移动网络往往不稳定,渐进式渲染在现代前端开发中仍然有用武之地。

有一点需要弄明白的是,这不是指的某一项技术,而是各种技术的一种集合。

例如:

骨架屏

在加载网络数据时,为了提升用户体验,通常会使用一个转圈圈的 loading 动画,或者使用 Skeleton Screen 占位。相比与 loading 动画,Skeleton Screen 的效果要更生动

image-20210913161720022

图片懒加载

所谓图片懒加载,顾名思义,就是先加载部分图片,剩余的图片等到需要的时候再加载。这在电商网站中尤其常见。

比如一个电商网站,首屏通常会有很多的数据,清晰度较高的 banner 或轮播。页面非首屏部分会员很多商品夹杂着大量的图片。这是时候选择懒加载以保证首屏的流畅十分重要。

图片占位符

在网页加载的时候,某些图片还在请求中或者还未请求,这个时候就先找一个临时代替的图像,放在最终图像的位置上,但是这只是临时替代的图形,当图片数据准备好以后,会重新渲染真正的图形数据。

拆分网页资源

大部分用户不会用到一个网站的所有页面,但我们通常的做法却是把所有的功能都打包进一个很大的文件里面。一个 bundle.js 文件的大小可能会有几 M,一个打包后的 style.css 会包含网站的一切样式,从 CSS 结构定义到网站在各个版本的样式:移动端、平板、桌面、打印版等等。

但用户并不是一开始就需要所有的资源,所有我们可以对资源进行拆分,首先加载那些关键的资源,其他的资源等到需要的时候再去加载它。

更多的关于渐进式渲染的内容,可以参阅 MDNhttps://developer.mozilla.org/zh-CN/docs/Web/Progressive_web_apps/Loading

真题解答

  • 什么是渐进式渲染 ?

参考答案:

渐进式渲染,英文全称 progressive rendering,也被称之为惰性渲染,指的是为了提高用户感知的加载速度,以尽快的速度来呈现页面的技术。但是这并不是某一项技术的特指,而是一系列技术的集合。

例如:

  • 骨架屏
  • 图片懒加载
  • 图片占位符
  • 资源拆分

-EOF-

CSS 渲染性能优化

经典真题

  • 总结一下如何提升或者优化 CSS 的渲染性能

CSS 渲染性能优化

很多人往往不重视性能优化这一块,觉得功能做出来就行了。

诚然,在软件开发过程中,功能确实是优先要考虑的,但是当功能完善后,接下来就需要考虑性能问题了。

我们可以从两个方面来看性能优化的意义:

  1. 用户角度
    网站优化能够让页面加载得更快,响应更加及时,极大提升用户体验。
  2. 服务商角度
    优化会减少页面资源请求数,减小请求资源所占带宽大小,从而节省可观的带宽资源。

网站优化的目标就是减少网站加载时间,提高响应速度。

那么网站加载速度和用户体验又有着怎样的关系呢?我们来看下面这张图:

image-20210916121117684

Google 和亚马逊的研究表明,Google 页面加载的时间从 0.4 秒提升到 0.9 秒导致丢失了 20% 流量和广告收入,对于亚马逊,页面加载时间每增加 100ms 就意味着 1% 的销售额损失。

可见,页面的加载速度对于用户有着至关重要的影响。

一个好的交互效果可能是这样的:

image-20210916121313325

当然,性能优化是来自方方面面的。

这里我们主要来看 CSS 方面能够进行哪些性能优化。

1.使用 id selector 非常的高效。在使用 id selector 的时候需要注意一点:因为 id 是唯一的,所以不需要既指定 id 又指定 tagName

/* Bad  */
p#id1 {color:red;}  

/* Good  */
#id1 {color:red;}

2.避免深层次的 node ,譬如:

/* Bad  */
div > div > div > p {color:red;} 
/* Good  */
p-class{color:red;}

3.不要使用 attribute selector,如:p[att1=”val1”]。这样的匹配非常慢。更不要这样写:p[id="id1"]。这样将 id selector 退化成 attribute selector

/* Bad  */
p[id="jartto"]{color:red;}  
p[class="blog"]{color:red;}  
/* Good  */
#jartto{color:red;}  
.blog{color:red;}

4.通常将浏览器前缀置于前面,将标准样式属性置于最后,类似:

.foo {
  -moz-border-radius: 5px;
  border-radius: 5px;
}

这里推荐参阅 CSS 规范-优化方案:http://nec.netease.com/standard/css-optimize.html

5.遵守 CSSLint 规则

font-faces                 不能使用超过5个web字体
import                    禁止使用@import
regex-selectors              禁止使用属性选择器中的正则表达式选择器
universal-selector           禁止使用通用选择器*
unqualified-attributes       禁止使用不规范的属性选择器
zero-units                  0后面不要加单位
overqualified-elements       使用相邻选择器时,不要使用不必要的选择器
shorthand                 简写样式属性
duplicate-background-images    相同的url在样式表中不超过一次

更多的 CSSLint 规则可以参阅:https://github.com/CSSLint/csslint

6.不要使用 @import

使用 @import 引入 CSS 会影响浏览器的并行下载。使用 @import 引用的 CSS 文件只有在引用它的那个 CSS 文件被下载、解析之后,浏览器才会知道还有另外一个 CSS 需要下载,这时才去下载,然后下载后开始解析、构建 Render Tree 等一系列操作。

多个 @import 会导致下载顺序紊乱。在 IE 中,@import 会引发资源文件的下载顺序被打乱,即排列在 @import 后面的 JS 文件先于 @import 下载,并且打乱甚至破坏 @import 自身的并行下载。

7.避免过分重排(Reflow
所谓重排就是浏览器重新计算布局位置与大小。常见的重排元素:

width 
height 
padding 
margin 
display 
border-width 
border 
top 
position 
font-size 
float 
text-align 
overflow-y 
font-weight 
overflow 
left 
font-family 
line-height 
vertical-align 
right 
clear 
white-space 
bottom 
min-height

8.依赖继承。如果某些属性可以继承,那么自然没有必要在写一遍。

真题解答

  • 总结一下如何提升或者优化 CSS 的渲染性能

参考答案:

CSS 渲染性能的优化来自方方面面,这里列举一些常见的方式:

  1. 使用 id 选择器非常高效,因为 id 是唯一的
  2. 避免深层次的选择器嵌套
  3. 尽量避免使用属性选择器,因为匹配速度慢
  4. 使用渐进增强的方案
  5. 遵守 CSSLint 规则
  6. 不要使用 @import
  7. 避免过分重排(Reflow
  8. 依赖继承
  9. 值缩写
  10. 避免耗性能的属性
  11. 背景图优化合并
  12. 文件压缩

-EOF-

层叠上下文

经典真题

  • 请简述什么是层叠上下文、什么是层叠等级、什么是层叠顺序

层叠上下文

在介绍层叠上下文之前,我们先来介绍一下 HTML 文档中的三维概念。

平时我们从设备终端看到的 HTML 文档都是一个平面的,事实上 HTML 文档中的元素却是存在于三个维度中。除了大家熟悉的平面画布中的 x 轴和 y 轴,还有控制第三维度的 z 轴。

image-20211229105842101

其中 x 轴通常用来表示水平位置,y 轴来表示垂直位置,z 轴表示屏幕内外方向上的位置。

对于 xy 轴我们很易于理解,一个向右,一个向下。但对于 z 轴,理解起来就较为费力。在 CSS 中要确定沿着 z 轴排列元素,表示的是用户与屏幕的这条看不见的垂直线:

image-20211229110052865

而这里我们要讨论的层叠上下文( stacking context ),就是 HTML 中的一个三维的概念。如果一个元素含有层叠上下文,我们可以理解为这个元素在 z 轴上就“高人一等”,最终表现就是它离屏幕观察者更近。

听上去好像很不错的样子,我想让一个元素更加靠前,我就给他创建一个层叠上下文。

那么具体的创建方法有哪些呢?

一般来讲有 3 种方法:

  • HTML 中的根元素 HTML 本身就具有层叠上下文,称为“根层叠上下文”。
  • 普通元素设置 position 属性为非 static 值并设置 z-index 属性为具体数值,会产生层叠上下文
  • CSS3 中的新属性也可以产生层叠上下文

赶紧试验一下:

<div class="one"></div>
<div class="two"></div>
div{
  width: 200px;
  height: 200px;
}
.one{
  background-color: red;
}
.two{
  background-color: blue;
  margin-top: -100px;
}

在上面的代码中,我们创建了两个 div,然后使其产生重叠,默认情况下后来居上,蓝色的会盖住红色的。

image-20211229110917880

下面我们给红色设置一个定位,如下:

...
.one{
  background-color: red;
  position: relative;
  z-index: 1;
}
...

由于设置了定位和 z-index 属性,所以红色的 div 就会创建一个层叠上下文,在 z 轴上就“高人一等”。

image-20211229111127835

OK,感觉很简单的样子,打完收工,撤退!

但是且慢少年,这才刚刚开始。

image-20211229112034560

层叠等级与层叠顺序

除了层叠上下文,我们还需要了解两个概念:

  • 层叠等级( stacking level
  • 层叠顺序( stacking order

这两个东西实际上都是用来表述:

在同一个层叠上下文中,元素在 z 轴上的显示顺序。

只不过前一个是概念,后一个是具体规则。

如果两个元素在同一个层叠上下文中,那么层叠等级越大的元素,就越靠前。

那么问题来了,我怎么知道该元素的层叠等级是高还是低?

所以层叠等级的高低规则是由层叠顺序来体现的。

CSS2.1 的年代(注意这里的前提),层叠顺序规则遵循下面这张图:

image-20210917111327410

那么如果两个元素不在同一个层叠下上文中呢?

那么此时就先比较他们所处的层叠上下文的层叠等级,也就是所谓的“从父”现象。

假设一个官员 A 是个省级领导,他下属有一个秘书 a-1,家里有一个保姆 a-2。另一个官员 B 是一个县级领导,他下属有一个秘书 b-1,家里有一个保姆 b-2

a-1b-1 虽然都是秘书,但是你想一个省级领导的秘书和一个县级领导的秘书之间有可比性么?甚至保姆 a-2 都要比秘书 b-1 的等级高得多。谁大谁小,谁高谁低一目了然,所以根本没有比较的意义。

因此只有在 A 下属的 a-1、a-2 以及 B 下属的 b-1、b-2 中相互比较大小高低才有意义。

实战案例

在开始实战案例之前,我们先对上面的知识进行一个总结。

  1. 首先先看要比较的两个元素是否处于同一个层叠上下文中:

    • 如果是,谁的层叠等级大,谁在上面(判断层叠等级大小参阅上面的“层叠顺序”图)

    • 如果两个元素不在同一层叠上下文中,请先比较他们所处的层叠上下文的层叠等级。

  2. 当两个元素层叠等级相同、层叠顺序相同时,在 DOM 结构中后面的元素层叠等级在前面元素之上。

接下来我们来通过几个实际的例子加深对上面概念的理解。

示例 1:

<div class="one">
  <div class="item" style="background-color: black; z-index: 99;"></div>
</div>
<div class="two">
  <div class="item" style="background-color: pink;top: 50px; z-index: 1;"></div>
</div>
div{
  width: 200px;
  height: 200px;
}
.one{
  background-color: red;
  position: relative;
  z-index: 1;
}
.two{
  background-color: blue;
  position: relative;
  z-index: 2;
}
.item{
  width: 100px;
  height: 100px;
  position: absolute;
  left: 200px;
  top: 200px;
}
image-20211229132843959

在上面的代码中,onetwo 分别有自己的层叠上下文,但是 two 的层叠等级要比 one 高,之后我们可以看到,无论 one 中的子元素的 z-index 设置有多高,它始终被 two 的子元素给覆盖,因为如果两个元素不在同一层叠上下文中,比较的是所在层叠上下文的等级。

示例 2:

<div class="box1">
  <div class="child1"></div>
</div>

<div class="box2">
  <div class="child2"></div>
</div>
.box1,
.box2 {
  position: relative;
}

.child1 {
  width: 200px;
  height: 100px;
  background: #168bf5;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
}

.child2 {
  width: 100px;
  height: 200px;
  background: #32c292;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
}
image-20210917112008034

在上面的示例中,.box1/.box2 虽然设置了 position: relative,但是在没有设置 z-index。所以 .box1/.box2 仍然是普通元素,所以 child1/.child2 属于 html 元素的“根层叠上下文”中,也就是处于同一个层叠上下文中,根据层叠顺序谁的 z-index 值大,谁在上面。

示例 3:

将上面案例中的 CSS 代码稍作修改,如下:

.box1,
.box2 {
  position: relative;
  z-index: 0;
}
image-20210917112806638

此时,我们发现,仅仅修改了 .box1/.box2z-index 属性值改为数值 0,最终结果完全相反。

这时 .child2 覆盖在了 .child1 上面。原因是什么呢?

很简单:因为设置 z-index: 0 后,.box1/.box2 产生了各自的层叠上下文,这时候要比较 .child1/.child2 的层叠关系属于不同的层叠上下文进行比较,此时由由各自所在的 .box1/.box2 的层叠等级来决定。

但是 .box1/.box2z-index 值都为 0,都是块级元素(所以它们的层叠等级,层叠顺序是相同的),这种情况下,在 DOM 结构中后面的覆盖前面的,所以 .child2 就在上面。

示例 4:

<div class="box">
  <img src="./ok.png" alt="" class="item">
</div>
.box{
  width: 200px;
  height: 200px;
  background: blue;
  position: absolute;
}
.item{
  position: absolute;
  width: 200px;
  left: 50px;
  top: 50px;
  z-index: -1;
}
image-20211229134234900

在上面的代码中,.box 虽然设置了定位,但是并没有设置 z-index 属性,所以并不会产生层叠上下文,仅仅是一个普通元素,此时 .item 图片属于 html 元素的“根层叠上下文”中,根据层叠顺序谁的 z-index 值大,谁在上面。

示例 5:

将上面的代码稍作修改,为 .box 添加一个 z-index 属性,并且给了一个很大的值

.box{
  width: 200px;
  height: 200px;
  background: blue;
  position: relative;
  z-index: 99;
}
image-20211229141342897

此时效果就完全不一样了,明明 .box 给了一个很大的值,但是图片却在上面,这是为什么呢?

因为 当 .box 设置了 z-index 后,就会产生一个层叠上下文,也就是说对 .item 图片而言,找到的层叠上下文是 .box 而不是 html 根元素。而根据层叠顺序,background 是处于最下层的,所以图片显示在了最上面。

示例 6:

<div class="parent">
  parent
  <div class="child1">child1</div>
  <div class="child2">
    child2
    <div class="child2-1">child2-1</div>
    <div class="child2-2">child2-2</div>
  </div>
</div>
.parent {
  width: 100px;
  height: 200px;
  background: #168bf5;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
}

.child1 {
  width: 100px;
  height: 200px;
  background: #32d19c;
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 1;
}

.child2 {
  width: 100px;
  height: 200px;
  background: #e4c950;
  position: absolute;
  top: 40px;
  left: 40px;
  z-index: -1;
}

.child2-1 {
  width: 100px;
  height: 200px;
  background: #e45050;
  position: absolute;
  top: 60px;
  left: 60px;
  z-index: 9999;
}

.child2-2 {
  width: 100px;
  height: 200px;
  background: #db68a7;
  position: absolute;
  top: 80px;
  left: 40px;
  z-index: -9999;
}
image-20210917115354011

在上面的代码中,对于 .child1.child2 来讲,他俩是处于同一个层叠上下文中,所以 .child1.child2 的上面(因为 .child1z-index 值更大),而对于 .child2-1.child2-2 来讲,他俩也是处于同一个层叠上下文 .child2 里面,所以无论 .child2z-index 值有多大,都一定在 .child2-1.child2-2 下面,而 .child2-1.child2-2 则根据 z-index 值的大小来决定谁覆盖谁。

CSS3 中属性对层叠上下文的影响

CSS3 中出现了很多新属性,其中一些属性对层叠上下文也产生了很大的影响。如下:

  • 父元素的 display 属性值为 flex|inline-flex,子元素 z-index 属性值不为 auto 的时候,子元素为层叠上下文元素
  • 元素的 opacity 属性值不是 1
  • 元素的 transform 属性值不是 none
  • 元素 mix-blend-mode 属性值不是 normal
  • 元素的 filter 属性值不是 none
  • 元素的 isolation 属性值是 isolate
  • will-change 指定的属性值为上面任意一个
  • 元素的 -webkit-overflow-scrolling 属性值设置为 touch

CSS3 中,元素属性满足以上条件之一,就会产生层叠上下文。我们用第 1 条来做一个简单的解释说明。

<div class="box">
  <div class="parent">
    parent
    <div class="child">child</div>
  </div>
</div>
.box {
}
.parent {
  width: 200px;
  height: 100px;
  background: #168bf5;
  /* 虽然设置了z-index,但是没有设置position,z-index 无效,.parent还是普通元素,没有产生层叠上下文 */
  z-index: 1;
}

.child {
  width: 100px;
  height: 200px;
  background: #32d19c;
  position: relative;
  z-index: -1;
}

效果:

image-20210917114513631

我们发现,.child.parent 覆盖了。按照之前的规则来分析一下:

虽然 .parent 设置了 z-index 属性值,但是没有设置 position 属性,z-index 无效,所以没有产生层叠上下文,仍然是一个普通的块级元素。 .child 的层叠上下文为 html 根元素,z-index 小于 0.child 会被普通的 block 块级元素 .parent 覆盖。

对于上面的例子,我们只修改 .box 的属性,设置 display: flex,其余属性和 DOM 结构不变。

.box {
  display: flex;
}

效果:

image-20210917114834856

在上面的示例中,当给 .box 设置 display: flex 时,.parent 也会变成一个弹性项目,成为一个层叠上下文元素。于是对于 .child 来讲找到的层叠上下文就是 .parent 了,而非 html 根元素。

根据层叠顺序规则,层叠上下文元素的 background/border 的层叠等级小于 z-index 值小于 0 的元素的层叠等级,所以 z-index 值为 -1 的*.child* 在 .parent 上面。

真题解答

  • 请简述什么是层叠上下文、什么是层叠等级、什么是层叠顺序

层叠上下文概念

CSS2.1 规范中,每个盒模型的位置是三维的,分别是平面画布上的 X 轴,Y 轴以及表示层叠的 Z 轴。

一般情况下,元素在页面上沿 XY 轴平铺,我们察觉不到它们在 Z 轴上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。

层叠上下文触发条件

  • HTML 中的根元素 HTML 本身就具有层叠上下文,称为“根层叠上下文”。
  • 普通元素设置 position 属性为非 static 值并设置 z-index 属性为具体数值,产生层叠上下文
  • CSS3 中的新属性也可以产生层叠上下文

层叠等级

如果两个元素在同一个层叠上下文中,那么层叠等级越大的元素,就越靠前。层叠等级是一个概念,层叠等级的大小可以根据层叠顺序来进行判断。

层叠顺序

层叠顺序表示元素发生层叠时按照特定的顺序规则在 Z 轴上垂直显示。

说简单一点就是当元素处于同一层叠上下文内时如何进行层叠判断。

image-20210917111327410

-EOF-

CSS3 遮罩

本文主要包含以下内容:

  • CSS3 遮罩介绍
  • 遮罩各属性介绍

CSS3 遮罩介绍

CSS mask 遮罩属性的历史非常久远了,远到比 CSS3 border-radius 等属性还要久远,最早是出现在 Safari 浏览器上的,差不多可以追溯到 2009 年。

不过那个时候,遮罩只能作为实验性的属性,做一些特效使用。毕竟那个年代还是 IE 浏览器的时代,属性虽好,但价值有限。

但是如今情况却大有变化,除了 IE 浏览器不支持,Firefox、Chrome、Edge 以及移动端等都已经全线支持,其实际应用价值已不可同日而语。

尤其 Firefox 浏览器,从版本 53 开始,已经全面支持了 CSS3 mask 属性。并且 mask 属性规范已经进入候选推荐规范之列,会说以后进入既定规范标准已经是板上钉钉的事情,大家可以放心学习,将来必有用处。

image-20211025225724975

(图为 caniuse 上各浏览器对 CSS mask 的支持情况)

快速入门示例

下面,我们来看一个 CSS mask 的快速入门示例。

首先需要准备两张图片,图片素材如下:

一张 jpg 图片:zelda.jpg

image-20211025231154694

一张 png 图片:mask.png,该 png 图片背景为透明(这里划重点)

image-20211025231236440

接下来准备我们的测试目录:

image-20211025231518012

index.html 代码如下:

<div class="mask"></div>
* {
  margin: 0;
  padding: 0;
}

div {
  width: 1200px;
  height: 600px;
  outline: 1px solid;
  margin: 50px auto;
  background: url('./zelda.jpg') no-repeat center/cover;
}

/*  
  虽然 .mask 和 div 都是选择中的相同的元素
  这里为了单独观察 mask 相关设置,
  和 mask 不相关的属性设置放入到了 div 选择器中 
*/
.mask {
  -webkit-mask-image: url('./mask.png');
}

在上面的代码中,我们为 div 设置了一个铺满整个盒子的背景图,然后为该盒子设置了遮罩效果。由于 mask.png 无法占满整个盒子,所以出现了重复的效果,mask.png 遮罩图片透明的部分不会显示底部图片的信息,而非透明部分则会显示底层图片信息

效果如下:

image-20211025231804573

除了设置透明的 png 图片,还可以设置透明的渐变。例如:

.mask {
  -webkit-mask-image: linear-gradient(transparent 10%, white);
}

在上面的代码中,我们设置了一个从上到下的线性透明渐变,效果如下:

image-20211026093708467

可以看到,无论是设置图片还是渐变,一定要有透明的部分,否则无法起到遮罩的效果,例如:

.mask {
  -webkit-mask-image: linear-gradient(red,blue);
}

上面的代码中,我们设置的是一个红到蓝的渐变,没有任何的透明部分,所以遮罩层不会起作用,底图会原封不动的显示出来。

遮罩各属性介绍

在上面的快速入门示例中,我们用到的是 mask-image 属性,但是除了该属性外,CSS mask 还有很多其他的属性,如下:

  • mask-image
  • mask-mode
  • mask-repeat
  • mask-position
  • mask-clip
  • mask-origin
  • mask-size
  • mask-type
  • mask-composite

下面我们来针对每个属性进行介绍。

mask-image

该属性在上面的快速入门示例中我们已经体验过了,默认值为 none,表示没有遮罩图片。

可以设置的值为透明图片,或透明渐变。

mask-repeat

表示遮罩层是否允许重复,默认值为 repeat 允许重复,可选值与 background-repeat 相同。

.mask {
  -webkit-mask-image: url('./mask.png');
  -webkit-mask-repeat: no-repeat;
}

上面的代码中,我们设置遮罩层的重复行为是 x、y 轴都不重复,效果如下:

image-20211026095112536

(红框是为了表示整张图片的大小,并非浏览器实际显示情况)

mask-position

该属性用于设置遮罩层的位置,默认值为0 0 在最左上角,可选值与 background-position 相同。

.mask {
  -webkit-mask-image: url('./mask.png');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
}

效果如下:

image-20211026095730053

(红框是为了表示整张图片的大小,并非浏览器实际显示情况)

mask-size

该属性用于设置遮罩层的大小,默认值为 auto,可选值与 background-size 相同,如下表:

image-20211026101622232

例如:

.mask {
  -webkit-mask-image: url('./mask.png');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
}

效果如下:

image-20211026101900926

(红框是为了表示整张图片的大小,并非浏览器实际显示情况)

mask-origin

默认值为 border-box,可选值与 background-origin 相同,可以设置如下的属性值:

image-20211026100114147

下面为了显示其效果,我们需要稍微对其他样式做一些改变,如下:

div {
  width: 1200px;
  height: 600px;
  border: 100px solid;
  margin: 50px auto;
  background: url('./zelda.jpg') no-repeat center/cover;
}

/*  
虽然 .mask 和 div 都是选择中的相同的元素
这里为了单独观察 mask 相关设置,
和 mask 不相关的属性设置放入到了 div 选择器中 
*/
.mask {
  -webkit-mask-image: url('./mask.png');
  -webkit-mask-repeat: no-repeat;
}

在上面的代码中,我们为该 div 设置了一个宽度为 100pxborder,由于 mask-origin 的默认值为 border-box,所以我们可以看到如下的效果:

image-20211026100927087

(红框是为了表示整张图片的大小,并非浏览器实际显示情况)

此时如果设置 mask-origin 的值为 centent-box,遮罩层图像就会相对于内容框来定位。

.mask {
  -webkit-mask-image: url('./mask.png');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-origin: content-box;
}

效果如下:

image-20211026101238881

(外层的黑框表示该 divborder,红框表示该 div 的内容区域,并非浏览器实际显示情况)

mask-clip

默认值为 border-box,可选值与 background-clip 相同,可以设置如下属性值:

image-20211026105259969

我们同样为 div 设置一个宽度为 100pxborder,由于默认值为 border-box,所以我们看到的效果如下:

image-20211026100927087

(红框是为了表示整张图片的大小,并非浏览器实际显示情况)

接下来设置 mask-clipcontent-box

.mask {
  -webkit-mask-image: url('./mask.png');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-clip: content-box;
}

由于 mask-origin 默认值为 border-box,所以遮罩层以边框盒来定位,之后我们设置了 mask-clipcontent-box,表示以内容框来进行裁剪。效果如下:

image-20211026105532851

(外层的黑框表示该 divborder,红框表示该 div 的内容区域,并非浏览器实际显示情况)

mask-mode

mask-mode 属性默认值为 match-source,作用是根据资源的类型自动采用合适的遮罩模式。

例如,如果遮罩效果使用的是 SVG 中的 <mask> 元素,则此时的 mask-mode 属性的值为 luminance,表示基于亮度来判断是否要进行遮罩。

如果是其他场景,则计算值是 alpha,表示基于透明度判断是否要进行遮罩。

因此 mask-mode 可选值为 alpha、luminance、match-source

使用搜索引擎搜索遮罩素材的时候,往往搜索的结果都是白底的 JPG 图片,因此使用默认的遮罩模式是没有预期的遮罩效果的。此时就非常适合设置遮罩模式为 luminance

另外,目前仅 Firefox 浏览器支持 mask-mode 属性,Chrome 浏览器并不提供支持,但是可以使用非标准的 mask-source-type 属性来进行替代(没有私有前缀)。

下面来看一个简单的示例。首先我们需要扩充我们的遮罩素材,准备了一张 mask2.jpg 的遮罩图片,该素材首先是 jpg 格式的,其次并没有透明区域,仅有一些白底区域。

image-20211026112617175

接下来设置如下的代码:

.mask {
  -webkit-mask-image: url('./mask2.jpg');
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-mode: luminance;
}

在上面的代码中,我们设置 mask-mode 的值为 luminance,表示基于亮度来判断是否进行遮罩。

Firefox 浏览器中的效果如下:

image-20211026112915034

(红框是为了表示整张图片的大小,并非浏览器实际显示情况)

mask-type

mask-type 属性的功能和 mask-mode 属性类似,都是设置不同的遮罩模式,但还是有一个很大的区别,就是 mask-type 属性只能作用于 SVG 元素上,因为其本质上是由 SVG 属性演变而来的,Chrome 等浏览器也都支持该属性。而 mask-mode 是一个针对所有元素类型的 CSS 属性,Chrome 等浏览器并不支持该属性,目前仅只有 Firefox 浏览器对其提供支持。

由于 mask-type 属性只能作用于 SVG 元素上,因此默认值表现为 SVG 元素默认遮罩模式,也就是默认值是 luminance 亮度遮罩模式。如果需要支持透明度遮罩模式,可以这么设置:

mask-type: alpha;
mask-composite

mask-composite 属性表示同时使用多张图片进行遮罩时的合成方式。默认值为 add,可选值为 add、subtract、intersect、exclude

  • mask-composite: add:表示遮罩累加,这是默认值
  • mask-composite: subtract:表示遮罩相减,也就是遮罩图片重合的区域不显示,这就意味着,遮罩层图片越多,遮罩区域越小。
  • mask-composite: intersect:表示遮罩相交,也就是遮罩图片重合的区域才显示遮罩。
  • mask-composite: exclude:表示遮罩排除,也就是遮罩图片重合的区域会被当作透明。

-EOF-

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狡辉两门

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值