说说css盒模型

浏览器在渲染html元素的时候,会把所有元素表示为一个一个矩形的盒子。

盒模型组成

  • content

    即实际内容,显示文本和图像

  • padding

    即内边距,内边距是透明的,取值不能为负,背景图片可以扩展到padding。

  • border

    即边框,由粗细、样式、颜色三部分组成。例如border:1px solid black

  • margin

    即外边距,在元素外创建额外的空白,空白通常指不能放其他元素的区域。

盒模型分类

w3c标准盒模型(content-box)

width/height的范围只包括content,虽说是标准盒模型,怎么感觉没有ie盒模型好用捏。

ie盒模型(border-box),也叫做怪异盒模型

width/height的范围包括content, border, padding

1
box-sizing: content-box|border-box|inherit;//指定元素使用哪种盒模型来渲染,inherit表示继承父元素盒模型

说说em/px/rem/vh/vw区别

em

是一个相对单位,和rem相同的是,相对的都是字体的大小,只不过em相对的是父元素字体的大小,rem相对的是根元素html中字体的大小。

px

1px即1个css像素,是绝对单位。

rem

是一个相对单位,相对的是根元素**html的字体大小**。

如果想要简化font-size的转化,我们可以修改html的字体大小。

1
html { font-size: 10px  }

vw/vh

视口的宽高划分为100等份,1vw表示视口宽度的1/100,1vh表示视口高度的1/100,是一个相对单位,相对的是视口的宽/高,而百分比布局相对的是父元素的宽/高。

这里的视口,在PC端指的就是浏览器窗口,在移动端指的就是布局视口,一般就是设备屏幕

1
<meta name="viewport" content="width=device-width, initial-scale=1.0"> #指定布局视口宽度为设备宽度

vmax/vmin:1vmax指的是1vw和1vh中较大的那个,反之1vmin指的是较小的那个。

设备像素、css像素、设备独立像素、dpr、ppi 之间的区别

css像素

css代码中的像素,一般1px就是一个css像素

设备像素

设备像素(device pixels),又称为物理像素,指设备能控制显示的最小物理单位,就是显示屏上的一个一个像素点,是固定不变的。

屏幕的分辨率通常为a × b的格式,分别指的是宽,高上的物理像素点的个数

设备独立像素

设备独立像素指的是与设备无关的逻辑像素,通过程序控制使用的虚拟像素,一个设备独立像素可能会对应多个设备像素。

在屏幕未缩放情况下(100%),1css像素=1设备独立像素所以一般情况我们认为,css像素就是设备独立像素

我们也可以推断出缩放屏幕,其实就是在改变css像素与设备独立像素的比例关系

dpr

dpr = 设备像素/设备独立像素,在PC端,dpr = 1,在移动端,dpr>=1

我们通常讨论的是不缩放的情况下,也就是1css像素就是1设备独立像素,因此dpr又可以被认等于设备像素/css像素

当设备像素比为1:1时,使用1(1×1)个设备像素显示1个CSS像素

当设备像素比为2:1时,使用4(2×2)个设备像素显示1个CSS像素

当设备像素比为3:1时,使用9(3×3)个设备像素显示1个CSS像素

PPI

pixel per inch每英寸像素点的个数,这个PPI越大,说明物理像素点的密度更大,像素点一般也更多,像素点大小也越小,能更细致的展现图像。

比如,iPhone 3GS 和 iPhone 4/4s 的尺寸都是 3.5 寸,但 iPhone 3GS 的分辨率是 320x480,iPhone 4/4s 的分辨率是 640x960

这意味着,iPhone 3GS 在上有320个物理像素,iPhone 4/4s 在上有 640 个物理像素,很明显,在屏幕大小相同的情况下iPhone 4/4s有更多的像素,也就是说iPhone 4/4s的PPI更大

空白问题

如果我们按照真实的物理像素进行布局,比如说我们按照 320 物理像素进行布局,到了 640 物理像素的手机上就会有一半的空白,为了避免这种问题,就出现了设备逻辑像素

我们统一 iPhone 3GS 和 iPhone 4/4s 都是 320 个虚拟像素,只是在 iPhone 3GS 上,最终 1 个虚拟像素换算成 1 个物理像素,在 iphone 4s 中,**1 个虚拟像素最终换算成 2 个物理像素(DPR=2)**。

模糊问题

我们思考一下,为什么原本能用1个物理像素表示的,为了解决空白问题,就硬要用2个物理像素表示呢,就非得让屏幕中的所有像素点参与展示吗,这样不就等同于放大图片吗,放大图片不是会变模糊吗,因为图片本身没有这么多细节(分辨率<实际用来渲染的像素数目)。所以对于PPI更高的设备,我们要准备分辨率更高的图片,才能完美的解决空白问题(一般来说,分辨率越高的图片,占用的物理像素点越多,文件大小越大,和屏幕分辨率是一个概念)

举个例子,我们有50x50分辨率的图片,我们通过css把它的大小设置为宽高都为50px:

  • 放到iPhone 3GS上和PC端上(DPR=1),会占用50x50像素(物理像素),刚好等于图片的分辨率,所以不会模糊;
  • 放到iPhone4/4s上(DPR=2),会占用100*100像素(物理像素),因为图片分辨率 < 实际参与渲染的物理像素,所以会变模糊

如果我们不指定这张图片的大小,它在任何设备上都会占用实际的50*50个物理像素,但是由于不同设备的像素密度不同,所以图片看起来的大小也不同,所以会出现空白的问题。

如何实现元素隐藏

display:none

  • 能实现元素隐藏,而且元素不再占有原来的位置
  • 会触发页面的重排与重绘
  • 元素对应的dom对象仍然存在,无法再响应点击事件

visibility:hidden

  • 能实现元素隐藏,而且元素占有原来的位置
  • 只会触发页面的重绘
  • 元素对应的dom对象仍然存在,无法再响应点击事件

opacity:0

  • 能实现元素隐藏,而且元素占有原来的位置
  • 元素对应的dom对象仍然存在,且能响应点击事件
  • 一般情况下也会引发重绘

总结

这三种方法都能实现元素隐藏,display:none会让元素不再占有原来的位置,而其他两种则会保留原来的位置。

添加了display:nonevisibility:hidden的元素都无法再响应点击事件,而添加了opacity:0的元素可以。

谈谈你对BFC的理解

什么是BFC

  • 也叫块级格式化上下文,可以理解为css中的一种属性,开启了bfc的盒子,被视为一块独立的渲染区域

  • BFC盒子内部的元素不会影响外部元素的布局,外部元素也不会影响内部元素的布局,这意味着在一个BFC中的元素,不会与该BFC之外的浮动元素重叠,并且它们之间的外边距也不会折叠。

如何开启BFC

  • html标签默认开启了BFC
  • overflow的值不为visible(默认值)的元素,比如我们经常使用overflow:hidden来清除浮动,本质就是开启了BFC。
  • 添加了绝对定位,固定定位的元素
  • 开启了浮动的元素
  • 开启了flex布局或者grid布局的元素,这2种布局的内部元素布局方式确实独特,可以理解为开启了一块独立的渲染区域。

开启了BFC有什么作用

可以用来清除浮动

BFC盒子内部的浮动元素,也参与BFC盒子高度的计算,或者说BFC盒子会完全包裹内部的所有元素,包括浮动元素

所以浮动元素,绝对定位元素,固定定位元素,不需要担心其内部的浮动元素不参与自身高度的计算 。

防止被浮动元素压住

这一点体现了布局互不影响的特点,比如浮动元素不会被浮动元素压住。

可以用来解决边距塌陷问题

如果两个相邻的盒子存在边距塌陷问题,只要让其中一个盒子包裹一个开启了BFC的盒子,就能解决边距塌陷问题。

举例说明:

1
2
3
4
<div class="box">
<div class="A"></div>
<div class="B"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
.box {
width: 300px;
height: 100px;
border: 1px solid;
}
.box .A {
background-color: red;
height: 30px;
}
.box .B {
background-color: blue;
height: 30px;
}

此时显示的图像如下:

当给A盒子添加浮动,我们期望A盒子会压住B盒子,所以应该只有红色,但是由于添加了浮动的盒子的宽度,宽度不再默认扩展至父元素宽度,所以A盒子的宽度为0,我们只能看到B盒子(蓝色)

如是我们给A盒子添加宽度100px,就出现了如下效果:

通过开发者工具检查发现,B盒子的宽度是300px,占满了父盒子,A盒子确实压住了B盒子

前面介绍到开启BFC的盒子不会被浮动的元素压住,所以我们给B盒子添加overflow:hidden,但是发现效果没有任何改变,B盒子看起来还是被A盒子压住了,但是当我们打开开发者工具,我们可以发现,B盒子的宽度变为了200px,并没有被A盒子压住,因为我们没有指定B盒子的宽度,所以B盒子为了不被A盒子压住,就减少了自己的宽度

为了让效果明显,我们设定B盒子的宽度为100px,就可以发现,B盒子未开启BFC时,会被A盒子压住,开启了则不会。

介绍一下flex弹性布局

开启Flex布局的元素(display:flex),称为flex容器container,其实也开启了BFC,它的所有子元素自动成为容器成员,称为flex项目item

容器属性

包括flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content

flex-direction

的方向决定了项目的排列方向

1
2
3
.container {   
flex-direction: row | row-reverse | column | column-reverse;
}
  • row(默认值):主轴为水平方向,起点在左端,从左到右摆放
  • row-reverse:主轴为水平方向,起点在右端,从右到左摆放
  • column:主轴为垂直方向,起点在上沿。从上到下摆放
  • column-reverse:主轴为垂直方向,起点在下沿,从下到上摆放

既然主轴的方向可以通过flex-direction来控制,哪侧轴方向呢?貌似没有哪个属性用来指定侧轴的方向,其实我们可以认为,主轴的方向确定了,侧轴的方向也确定了,且默认是从左到右或者从上到下

flex-wrap

用来决定子元素一行放不下了是否换行

1
2
3
.container {  
flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap(默认值):默认不换行
  • wrap:换行,第一行在下方
  • wrap-reverse:换行,第一行在上方,有点逆天了。

flex-flow

flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

1
2
3
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content

定义了项目(子元素)在主轴上的对齐方式

1
2
3
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
  • flex-start(默认值):向开始处(start)对齐

  • flex-end:向结束处(end)对齐

  • center:居中对齐

  • space-between:两端对齐,项目之间的间隔都相等

  • space-around:两个项目两侧间隔相等

1
2
3
4
5
<div class="box">
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</div>

align-items

定义子元素如何在侧轴上对齐(垂直于主轴),只适用于只有一根主轴线的时候(如果主轴为row,就是只有一行)

1
2
3
.box {
align-items: flex-start | flex-end | center | stretch;
}
  • flex-start:交叉轴的起点对齐
  • flex-end:交叉轴的终点对齐
  • center:交叉轴的中点对齐, 就是居中对齐
  • stretch(默认值,拉伸):如果项目未设置高度或设为auto,将占满整个容器的高度。

align-content

定义多根主轴的对齐方式。如果项目只有一根主轴线(比如主轴是row的时候,只有一行子元素),该属性不起作用,所以说align-items属性和align-content属性不能同时使用。

1
2
3
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
  • flex-start:与交叉轴的起点对齐
  • flex-end:与交叉轴的终点对齐
  • center:与交叉轴的中点对齐
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
  • stretch(默认值):轴线占满整个侧轴,align-contentalign-items的默认值竟然都是stretch

可以看到,这些属性值和justify-contentalign-items的属性值是几乎一样的,如果主轴有多根,可以把每根主轴当作侧轴上的一个元素

容器成员属性

order

定义项目的排列顺序。数值越小,排列越靠前,默认为0,不指定order属性,那就是order:0

默认情况,子元素的排列顺序是在html文档中的书写顺序,而指定order能改变这个顺序。

1
2
3
.item {
order: <integer>;
}

flex-grow

定义了子元素的放大比例,默认为0,当容器设为flex-wrap: nowrap(默认值);即不换行的时候,如果一行没有占满:

  • flow-grow的值为0,如果一行没有占满,也不放大。
  • 子元素flex-grow属性都为1,则它们将等分剩余空间。

flex-shrink

定义了子元素的缩小比例(容器宽度<子元素总宽度,且不换行时如何收缩),默认为1

如果所有子元素的flex-shrink属性都为1,当空间不足时,都将等比例缩小

如果一个子元素的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.box {
width: 250px;
height: 400px;
display: flex;
background-color: antiquewhite;
}
.a {
width: 100px;
height: 100px;
background-color: aqua;
}
.b {
width: 100px;
height: 100px;
background-color: red;
}
.c {
width: 100px;
height: 100px;
background-color: gold;
}

可以看到即便子元素指定了宽度,如果一行放不下,也会等比例缩小。我们可以通过修改flex-shrink属性来修改具体的缩小规则。

flex-basis

设置的是元素在主轴上的初始尺寸,所谓的初始尺寸,就是元素在flex-growflex-shrink生效前的尺寸。

  • auto: 默认值,这意味着项目将根据其内容,确定其初始大小,如设置了width/height则元素尺寸由width/height决定
  • 固定值:你可以指定一个具体的长度单位,如像素 (px)、百分比 (%) 等。这会设置项目的初始大小,不考虑内容的自然尺寸。
  • 0:完全依赖flex-grow 来分配多余的空间。这种方式常用于创建等分布局,如果令一个元素的flex-basis:0,由于flex-grow默认为0,此时无论是否指定宽度,在主轴上的宽度都为0

flex

flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto,也是比较难懂的一个复合属性。

我们通常的书写方式flex:1修改的是flex-grow的值,即规定了分割剩余空间时的权重或者份数。

align-self

允许侧轴上的单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性,但是不能覆盖align-content的,

默认值为auto,表示继承父元素的align-items属性。

1
2
3
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

介绍一下grid网格布局

通过display:grid/inline-grid就能开启网格布局

1
2
3
4
5
6
7
<div class="container">
<div class="item item-1">
<p class="sub-item"></p>
</div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>

上述代码实例中,.container元素就是网格布局容器,.item元素就是网格的项目,由于网格元素只能是容器的顶层子元素,所以p元素并不是网格元素

同样,Grid 布局属性可以分为两大类:

  • 容器属性
  • 项目属性

容器属性

display

display:grid 则该容器是一个块级元素

display: inline-grid 则容器元素为行内元素

grid-template-columns/grid-template-rows

grid-template-columns 属性设置列宽,grid-template-rows 属性设置行高

1
2
3
4
5
6
7
8
.wrapper {
display: grid;
/* 声明了三列,宽度分别为 200px 200px 200px */
grid-template-columns: 200px 200px 200px;
grid-gap: 5px;
/* 声明了两行,行高分别为 50px 50px */
grid-template-rows: 50px 50px;
}

以上表示固定列宽为 200px,行高为 50px

上述代码可以看到重复写单元格宽高,通过使用repeat()函数,可以简写重复的值,第一个参数是重复的次数,第二个参数是重复的值

所以上述代码可以简写成

1
2
3
4
5
6
.wrapper {
display: grid;
grid-template-columns: repeat(3,200px);
grid-gap: 5px;
grid-template-rows:repeat(2,50px);
}

除了上述的repeat关键字,还有:

auto-fill:示自动填充,让一行(或者一列)中尽可能的容纳更多的单元格,只能在repeat函数中使用用来替代具体的重复次数,而不是宽度或者高度

1
2
//表示列宽是 200 px,但列的数量是不固定的,只要浏览器能够容纳得下,就可以放置更多的列
grid-template-columns: repeat(auto-fill, 200px)

fr:片段,为了方便表示比例关系,非常类似flex布局中的份数,用份数来替代具体的宽高。要注意的是1fr不可写成fr,否则会出错。

1
2
//表示第一个列宽设置为 200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/32/3
grid-template-columns: 200px 1fr 2fr

minmax:产生一个长度范围,表示长度就在这个范围之中都可以应用到网格项目中。第一个参数就是最小值,第二个参数就是最大值,用一个范围来替代具体的宽高。

minmax(100px, 1fr)表示列宽不小于(>=)100px,不大于(<=)1fr

1
grid-template-columns:repeat(auto-fill, minmax(260px,1fr))

auto:由浏览器自己决定长度

1
2
//表示第一第三列为 100px,中间由浏览器决定长度
grid-template-columns: 100px auto 100px

gap:定义宫格之间的间隔,还可指定row-gap和column-gap

容器成员属性

指定一个子元素占多少行多少列

1
2
3
4
5
.carousel {
//让轮播图占宫格布局中的22
grid-column: span 2;
grid-row: span 2;
}

CSS如何画一个三角形

可以通过指定边框(border)样式实现。

1
2
3
4
5
6
.border {
width: 50px;
height: 50px;
border: 50px solid;
border-color: #96ceb4 #ffeead #d9534f #ffad60;
}

这样一个盒子的样式如下:

当盒子的宽高不断减小,那每个边框是不是就会变成一个三角形呢?

这样会得到四个三角形,但是我们只要一个,我们可以把其他边框的颜色变透明,但是这样隐藏的部分仍然占据部分高度,

比如我们只要下面的三角形,那我们就可以让上边框的的宽度变为0,效果就是这样。

然后再让左右边框变为透明的就好了。

1
2
3
4
5
6
7
.border {
width: 0;
height: 0;
border-style: solid;
border-width: 0 50px 50px 50px;
border-color: transparent transparent #d9534f transparent;
}

如何实现元素水平居中,垂直居中

水平居中

行内元素/行内块元素

给父元素添加text-align:center

给父元素添加flex布局

1
2
display: flex; 
justify-content: center;

给自身添加绝对定位

1
2
3
position: absolute;
left: 50%;
transform: translateX(-50%);

块级元素

添加margin: 0 auto,要求块级元素的宽度确定

给父元素添加flex布局

1
2
display: flex; 
justify-content: center;

给自身添加绝对定位

1
2
3
position: absolute;
left: 50%;
transform: translateX(-50%);

垂直居中

行内元素

指定行内元素的行高line-height为父元素高度。

给父元素添加flex布局

1
2
display: flex; 
align-items: center;

给自身添加绝对定位

1
2
3
position: absolute;
top: 50%;
transform: translateY(-50%);

行内块元素/块级元素

给父元素添加flex布局

1
2
display: flex; 
align-items: center;

给自身添加绝对定位

1
2
3
position: absolute;
top: 50%;
transform: translateY(-50%);

总结

绝对定位和flex布局是万能的。margin:0 autotext-align:centerline-height:父元素高度,是一些特殊情况。

说说对CSS预处理语言的理解?有哪些区别?

背景

CSS代码看起来是没有逻辑性的,不方便维护及扩展,不利于复用。css预处理语言在css的基础上,添加了变量,混入,嵌套等功能,让css代码看起来更有逻辑性,更容易维护和复用。

css预处理语言包括一套自定义的语法和一个解析器,解析器会把用自定义语法编写的代码转化成css代码

常见的css预编译语言

sass

2007 年诞生,最早也是最成熟的 Css预处理器,目前受 LESS 影响,已经进化到了全面兼容 CssScss

sass和scss的区别与联系

是同一种css预处理语言(sass)的两种不同语法形式,它们都扩展了标准的 CSS,虽然有不同的自定义语法,但是使用同一个解析器来处理。sass使用缩进来表示代码块,不使用大括号 {} 和分号 ;更接近 Python 的风格

scss与 CSS 的语法几乎完全相同,所以更容易被现有开发者接受和使用

less

2009年出现,受SASS的影响较大,但又使用 Css 的语法,让大部分开发者和设计师更容易上手。

常用特性

嵌套

二者的嵌套语法都是一致的,甚至连引用父级选择器的标记 & 也相同

1
2
3
4
5
.a {
&.b {
color: red;
}
}

变量

变量的出现有效的提高了css代码复用性,减少了不必要的硬编码。

less声明的变量必须以@开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:分隔开

1
2
3
4
@red: #c00;
strong {
color: @red;
}

sass声明的变量跟less十分的相似,只是变量名前面使用$开头

1
2
3
4
5
$red: #c00;

strong {
color: $red;
}

作用域

在css预处理语言中,变量是具有作用域的。

sass中所有定义的变量都在全局作用域中,没有局部作用域。

1
2
3
4
5
6
7
8
$color: black;
.scoped {
$color: white; //重复定义
color: $color;
}
.unscoped {
color:$color;
}

编译后

1
2
3
4
5
6
.scoped {
color:white;/*是白色*/
}
.unscoped {
color:white;/*白色(无全局变量概念)*/
}

所以,在sass中最好不要定义相同的变量名,无论定义在哪个地方,后面定义的会覆盖前面定义的

less的变量作用域跟javascript十分的相似,有局部变量和全局变量之分。

1
2
3
4
5
6
7
8
@color: black;
.scoped {
@color: white;
color: @color;
}
.unscoped {
color:@color;
}

编译后:

1
2
3
4
5
6
.scoped {
color:white;/*白色(调用了局部变量)*/
}
.unscoped {
color:black;/*黑色(调用了全局变量)*/
}

混入

Mixins可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用,可以说是css预处理语言的精髓所在。

less中的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.alert {
font-weight: 700;
}
//这不是在定义函数吗
.highlight(@color: red) {
font-size: 1.2em;
color: @color;
}

.heads-up {
.alert;
//函数调用?
.highlight(red);
}

编译后

1
2
3
4
5
6
7
8
.alert {
font-weight: 700;
}
.heads-up {
font-weight: 700;
font-size: 1.2em;
color: red;
}

Sass声明mixins时需要使用@mixin,后面紧跟mixin的名,也可以设置参数,参数名为变量$声明的形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}

.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}

代码模块化

模块化就是将复杂的Css代码按某种规则划分为一个个文件,每个文件就是一个模块,模块可以通过@import引入

scssless二者的使用方法都如下所示。

1
2
3
4
@import './common';
@import './github-markdown';
@import './mixin';
@import './variables';

在原生css代码中,也能使用@import关键字导入其他css文件(无论是在css文件中还是在style标签中);url()是可加可不加的,要注意的是,结尾都要加上分号

1
@import url('./common');

如何实现单行/多行文本溢出的省略样式?

单行文本溢出显示

多行文本溢出显示

属性作用
display: -webkit-box;将元素设为弹性盒子(旧版 WebKit Flexbox),是 -webkit-line-clamp 的前提
-webkit-box-orient: vertical(垂直);设置盒子的子元素垂直排列(这里是文本行)
-webkit-line-clamp: 2;⭐ 关键!限制最多显示 2 行,超出则截断
overflow: hidden;隐藏被截断的内容(否则会溢出)
text-overflow: ellipsis;超出部分用 ... 省略号表示
line-break: anywhere;允许在任意位置断行(避免长单词溢出)
word-break: break-word; / break-all;控制单词断行方式(辅助换行)

如何从CSS入手提高页面性能

浏览器有一个固定的渲染流程——只有在布局(layout)完成后,才能绘制(paint)页面,而布局的前提是要生成渲染树(render tree),而渲染树的生成则需要 DOM树 和 CSSOM 树的配合。

如果先让用户看到一个没有样式的页面,等 CSS 样式解析完后再重绘(repaint),这样的体验会很差。所以,浏览器会等到DOM树构建完毕,且首屏需要的CSS加载解析完毕的时后,才开始渲染。

内联首屏关键css

将提取出的关键 CSS ,直接嵌入到 HTML 文件的 <head> 部分,使用 <style> 标签包裹。

内联css代码将成为html文件的一部分,会随着html文件的下载而被下载,能够使浏览器在下载完html后就能立刻渲染

而如果使用link标签引用css代码,在解析html结构过程中,遇到link标签,才会开始下载css代码,再解析,再渲染。

所以,内联CSS省去了加载css文件的时间,从而提高了首屏加载速度。

虽然内联关键 CSS 可以加速首屏渲染,但过大的内联样式可能会增加 HTML 文件的大小,反而影响加载速度。因此,应该尽量保持内联 CSS 的精简。

注意:内联的css样式解析完毕后会立即渲染(如果DOM也构建完毕的话),不管是否存在link标签引入的其他css文件,所以可能存在样式闪烁问题。

资源压缩

css代码进行压缩,使文件变小,大大降低了浏览器的加载时间,这一点应该是比较好理解的。

合理使用css选择器

css匹配的规则是从右往左开始匹配,例如#markdown .content h3匹配规则如下:

  • 先找到h3标签元素
  • 然后去除祖先不是.content的元素
  • 最后去除祖先不是#markdown的元素

如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高。

所以最好不要嵌套使用过多复杂选择器。

不使用@import

css样式文件有两种引入方式,一种是link元素,另一种是@import

使用 @import 规则引入的 CSS 文件是串行加载的,打开开发者工具->网络,即可观察到这一现象。

1
2
3
4
5
6
/* styles.css */
@import url('reset.css');
@import url('layout.css');
@import url('theme.css');

body { /* ... */ }

在这个例子中,reset.csslayout.csstheme.css 是按顺序加载的,只有当前一个文件加载完成后才会开始加载下一个。如果这些文件都是渲染首屏需要的,那么这样导入css文件将会减缓首屏渲染速度。

1
2
3
4
5
<head>
<link rel="stylesheet" href="reset.css">
<link rel="stylesheet" href="layout.css">
<link rel="stylesheet" href="theme.css">
</head>

尽管 <link> 标签默认会阻塞页面渲染,但它允许浏览器并行加载多个 CSS 文件。这意味着虽然整个页面的渲染仍然会被延迟,但单个文件的加载,不会影响其他文件的下载直到所有这些文件都解析完毕

说说css的层叠顺序

层叠上下文

有层叠上下文的元素,一般比普通元素(未开启定位的元素)层级高

如何产生层叠上下文

  • html元素默认有层叠上下文,称为“根层叠上下文”
  • 普通元素设置position属性为非static值,并设置z-index属性为具体数值(不为auto),产生层叠上下文。

如何查找

从父元素开始向上查找,直至查找到一个有层叠上下文的元素。

z-index

静态布局元素(postion:static)的z-index属性不会生效,只对定位元素有效。

默认值为auto,不会产生层叠上下文。

父元素的z-index权重可以理解为比子元素高(老爸比不过对面的,自己也就比不过),我们一般只在同一个层叠上下文中比较层叠优先级。

层叠顺序

父背景 < 负 z-index 子上下文 < 块级非定位 < 浮动 < 行内非定位 < 定位 (auto/0) < 正 z-index 子上下文

由此可知,浮动盒子的层叠优先级低于行内/行内块元素,但高于块级元素,所以浮动盒子不会压住后面的行内/行内块元素,会压住后面的块级元素。

开启了定位的元素(相对定位,绝对定位,固定定位)的,即便不指定z-index,层叠优先级也比行内/行内块元素高,当然也就比浮动元素高。如果指定了z-index为负值,优先级反而变的比它们低了。

怎么理解回流跟重绘?什么场景下会触发?

是什么

HTML中,每个元素都会被表示成一个盒子,在浏览器解析过程中,会涉及到回流与重绘

  • 回流:布局引擎会根据各种样式,计算每个盒子在页面上的大小与位置,简单的来说,回流的作用就是布局元素,即确定元素的位置和大小
  • 重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制,简单的来说,就是更为细致的渲染盒子

具体的浏览器解析渲染机制如下所示:

  • 解析HTML,生成DOM树,解析CSS,生成CSSOM树
  • DOM树CSSOM树结合,生成渲染树(Render Tree),生成了渲染树才能确定每个元素的大小和布局方式,才能进行布局(layout)
  • Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
  • Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  • Display:将像素发送给GPU,展示在页面上

在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变

当我们对 DOM 的修改引发了 DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来,这里就发生了回流

当我们对 DOM的修改导致了样式的变化(colorbackground-color),却并未影响其几何属性时,浏览器直接为该元素绘制新的样式,这里就仅仅触发了重绘。

如何触发回流

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的大小发生变化
  • 页面初次渲染时(这避免不了)
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的,这个依据变了,就难免要重新计算)
  • 获取元素以client,scroll,offset开头的布局属性,这些属性有一个共性,就是需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流。

如何触发重绘

触发回流一定会触发重绘,除此之外还有一些其他引起重绘行为:颜色的修改,文本方向的修改,阴影的修改

总的来说,如果修改了css样式,没触发回流,那就只会触发重绘。

浏览器的优化机制

由于每次回流都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化回流过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。

当你获取布局信息的操作的时候,会强制队列刷新,包括前面讲到的offsetTop等方法都会返回最新的数据,因此浏览器不得不立即清空队列,触发回流重绘来返回正确的值。

编码过程中该如何优化

离线操作

通过设置元素属性display: none,将其从页面上去掉(完全从渲染树中移除),然后再进行后续操作,这些后续操作也不会触发回流与重绘,当设置display:block时,浏览器会重新计算所有累积的样式修改,触发全局回流和重绘。

避免多次访问布局属性

因为访问布局属性会强制触发回流

css选择器有哪些?优先级?哪些属性可以继承?

选择器

CSS选择器是CSS规则的第一部分。就是选择符合匹配规则的元素,给它们应用相应的样式规则。

关于css属性选择器常用的有:

  • id选择器(#box),选择id为box的元素,id选择器选择唯一的元素,每个元素的id应该是唯一的。

  • 类选择器(.one),选择类名为one的所有元素

  • 标签选择器(div),选择标签为div的所有元素

  • 属性选择器:

    1
    2
    [attribute] 选择带有attribute属性的元素
    [attribute=value] 选择所有使用attribute=value的元素
  • 复合选择器

    • 后代选择器(#box div),选择id为box元素内部所有的div元素,只要是box后代div元素就行。

      1
      a.className a 

      这是一个有效的选择器。它会选择带有类名className的a标签之下的另一个a标签。但是从html角度考虑,a标签不能套接a标签,而且它的权重比.className a要高。

    • 子元素选择器(.one > .one_1),选择父元素为.one的所有.one_1的元素

    • 群组选择器(div,p),选择div、p的所有元素,这两类元素使用相同的css规则。

还有一些使用频率相对没那么多的选择器:

  • 伪类选择器:最经典的是标志就是只有一个冒号

    1
    2
    3
    4
    5
    :link :选择未被访问的链接,常见的使用场景是和a标签绑定的,即a:link
    :visited:选取已被访问的链接,常见的使用场景是和a标签绑定的,即a:visited
    :active:选择活动链接,就是点击a标签不松手时的样式。常见的使用场景是和a标签绑定的,即a:active
    :hover :鼠标指针浮动在上面的元素
    :focus :选择具有焦点的

    注意:上述与a标签有关的书写顺序应该是,a:link->a:hover->a:visited->a:active,书写顺序越靠后,优先级越高,这样书写才能保证相应的样式会如期生效。

    1
    :nth-child(n)、:first-child:last-child 等结构伪类选择器(也是伪类选择器):基于元素在其父级中的位置选择元素。

    :nth-child(n)和:nth-of-type(n)的区别

    :nth-child(n)是先根据顺序查找元素,再匹配类型。:nth-of-type(n)是先根据元素类型筛选元素,再根据顺序查找元素。

    简单的来说一个是先查找再匹配,一个是先筛选再查找。

    1
    2
    3
    4
    5
    6
    7
    <div class="container">
    <h2>标题</h2>
    <p>段落一。</p>
    <p>段落二。</p>
    <h2>另一个标题</h2>
    <p>段落三。</p>
    </div>
    1
    2
    3
    .container :nth-child(3) {//前面不加标签就代表选择第三个子元素,且不限制标签类型
    background-color: yellow;
    }选中的是 <p>段落二。</p>这个元素
    1
    2
    3
    .container p:nth-child(4) {//前面加上了一个p标签,就代表选择第四个元素,且必须是p标签
    background-color: yellow;
    }选中的是第四个元素,且要求它的类型是p,但是第四个元素类型是h2,所以这个css规则不会生效
    1
    2
    3
    .container p:nth-of-type(3) {//:nth-of-type前面必须加标签,限制类型
    background-color: lightblue;
    }//选中的是内部所有的p元素中的第三个,也就是第五个元素<p>段落三。</p>
  • 伪元素选择器

    伪元素通常以双冒号 :: 开头,这是为了区分伪类选择器(以单冒号开头),但在一些较老的浏览器中,单冒号 : 也被支持。

    1
    2
    ::before : 选择器在 被选元素的内容 前面插入内容
    ::after : 选择器在 被选元素的内容 后面插入内容

    伪元素的好处就是可以在不改变页面结构的前提下,往页面中插入内容

    伪元素选择器还可以用来清除浮动

    1
    2
    3
    4
    5
    .clearfix::after {
    content: "";//指定要插入的具体的内容
    display: block; //指定插入的伪元素的类型,设置为block让其独占一行
    clear: both; //确保左右两边没有浮动元素,可以用用来清除浮动
    }

    clear属性的解释:指明某个元素周围不能出现浮动元素,通常借助伪元素来清除浮动,属性值为 none | left | right | both所以说,周围最多是指的左右两边(both)。

优先级

单个选择器的优先级排序:内联 > ID选择器 > 类选择器(包括伪类,结构伪类)= 属性选择器 > 标签选择器 = 伪元素选择器

那复合选择器的优先级怎么比较呢?先比较复合选择器中包含的优先级最高的选择器,如果优先级相同,则比较优先级最高的选择器的数量,如果数量也相同,则比较次高优先级的选择器,依此类推。

经过上面的优先级计算规则,我们知道内联样式的优先级最高,如果外部样式需要覆盖内联样式,就需要使用!important

1
2
3
.box{
font-size:12px !important /*这个样式的优先级最高*/
}

继承属性

css中,继承是指的是给父元素设置一些属性,后代元素会自动拥有这些属性

关于可继承的属性,可以分成:

字体系列属性

简单来说,就是font开头的属性,所有字体属性。

1
2
3
4
5
6
font:组合字体
font-family:规定元素的字体系列
font-weight:设置字体的粗细
font-size:设置字体的尺寸
font-style:定义字体的风格
font-variant:偏大或偏小的字体

文本系列属性

1
2
3
4
5
6
7
8
text-indent:文本缩进
text-align:文本水平对齐
line-height:行高
word-spacing:增加或减少单词间的空白
letter-spacing:增加或减少字符间的空白
text-transform:控制文本大小写
direction:规定文本的书写方向
color:文本颜色

元素可见性visibility

这就意味着,给一个父元素添加visibility:hidden,他的子元素也都会被隐藏。

1
quotes:设置嵌套引用的引号类型

光标属性

1
2
cursor:箭头可以变成需要的形状
cursor: url("/img/ania_link.cur"),default;/*如果第一个资源不可用,就使用默认样式*/

继承中比较特殊的几点:

  • a 标签的字体颜色不会继承父元素的字体颜色,它有默认的颜色
  • h1-h6标签字体的大小也不会继承父元素的字体大小

无继承的属性

  • display
  • 文本属性:vertical-align、text-decoration
  • 盒子模型的属性:宽度、高度、内外边距、边框等
  • 背景属性:背景图片、颜色、位置等
  • 定位属性:浮动、清除浮动、定位position等
  • 生成内容属性:content、counter-reset、counter-increment
  • 轮廓样式属性:outline-style、outline-width、outline-color、outline
  • 页面样式属性:size、page-break-before、page-break-after

CSS3新增了那些特性

边框border-radius:创建圆角边框

值可以是绝对单位px也可以是百分比单位。

如果是绝对单位,比如为10px,则从盒模型每个角的顶点开始,往两条边的方向分别延伸10px,然后在这两个点的位置做一条垂直的边,确定交点,然后再以这个焦点为圆心做一个圆,然后在舍去这个圆截取的部分 ,就得到了圆角模型。

如果单位是百分比,则先转化为绝对单位,相对的是每个角对应的两条边。

1
2
3
4
5
6
.box {
width: 300px;
height: 50px;
border-radius: 10px;
background-color: pink;
}

图中圆的半径为10px

1
2
3
4
5
6
.box {
width: 300px;
height: 50px;
border-radius: 50%;
background-color: pink;
}

图中的红线只是辅助线,可以看到当令 border-radius: 50%时就能得到一个椭圆,如果盒子的宽高相等就是一个圆形。

50%border-radius能取得的最大值,再增加也不会有效果。

box-shadow:为元素添加阴影

设置属性如下:

  • 水平阴影(x轴)
  • 垂直阴影(y轴)
  • 模糊距离(z轴)
  • 阴影尺寸(影子大小)
  • 阴影颜色
  • 内/外阴影
1
box-shadow: 3px 3px 4px;

如果第一个属性值(x)为正数,则阴影就会出现在盒模型的右边 ,值越大右边阴影越,反之则出现在盒模型的左边

如果第二个属性值(y)为正数,则阴影就会出现在盒模型的下边 ,值越大下边阴影越,反之则出现在盒模型的上边

如果第三个属性值(z)表示盒模型距离视口的距离,一般为正值,这个值增大可以看到盒模型仿佛在贴近屏幕,阴影就变越来越模糊了。

第四个值为阴影的尺寸,其实修改第一,二个属性的值就能控制阴影的大小了,这个值存在的意义就是在原有的大小上再添加

transition过渡

transition属性可以为指定的一个或多个CSS属性添加过渡效果,让样式改变看起来更自然,多个属性之间用逗号进行分隔,必须规定两项内容:css属性持续时间

1
2
transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)
transition: all 0.4s #给所有样式添加过渡 花费0.4s

详细介绍见下文

transform转换

transform属性允许你平移缩放旋转指定元素

详细介绍见下文

animation 动画

详细介绍见下文

渐变

linear-gradient:线性渐变

线性渐变创建了一条沿直线前进的颜色带,这条直线的方向,角度是可以自定义的。

基础线性渐变

1
2
3
4
.simple-linear {
// 注意是background属性,不能是background-color,也可以是background-image
background: linear-gradient(blue, pink);
}

改变渐变方向

默认情况下,线性渐变的方向是从上到下,你可以指定一个值来改变渐变的方向,我们把这个值放到第一个参数的位置,值的类型可以是关键字,也可以是具体的角度。

1
2
3
.horizontal-gradient {
background: linear-gradient(to right, blue, pink);
}
1
2
3
.diagonal-gradient {
background: linear-gradient(to bottom right, blue, pink);
}

设置渐变角度

在使用角度的时候,0deg 代表渐变方向为从下到上90deg 代表渐变方向为从左到右,诸如此类正角度都属于顺时针方向。而负角度意味着逆时针方向。

1
2
3
.angled-gradient {
background: linear-gradient(45deg, blue, pink);
}

控制渐变的进程

默认情况下,渐变在两个相邻的色标之间都是均匀推进的,两个色标之间的中点是颜色值的中点,也可以控制在哪个位置才开始均匀推进。

1
2
3
4
5
.box{
width: 100px;
height: 100px;
background: linear-gradient(blue 50px, pink);//可以是px,也可以是相对单位。
}

如图所示,50px的部分的颜色都是blue

堆叠渐变

你可以将渐变与其他的渐变堆叠起来。只要顶部的渐变不是完全不透明的,那么下面的渐变就会依然可见。

顶部的渐变就是最先声明的渐变,就是书写位置最靠前的渐变。

1
2
3
4
5
6
7
.a {
width: 100px;
height: 100px;
//渐变的声明顺序不能乱。
background: linear-gradient(to bottom, transparent 10px, #fff),
linear-gradient(to right, blue, pink);
}

其实多个背景图片也是按照这种规则来堆叠的,毕竟渐变色也属于background-image

1
2
3
4
5
.box {
width: 400px;
height: 400px;
background: url('../images/w3logo.png') center/contain no-repeat, url('../images/0.png') center/contain no-repeat;
}

效果如图:

radial-gradient:径向渐变

径向渐变类似于线性渐变,除了是从一个中心点向外辐射的。你可以指定中心点的位置。你还可以使其为圆形或者是椭圆形

更多内容参考:使用 CSS 渐变 - CSS:层叠样式表 | MDN

flex布局与grid布局

有文章介绍,不赘述。

CSS3新增动画

css实现动画的方式,有如下几种,都是css3新增的

  • transition:实现渐变动画
  • transform:转变动画
  • animation:实现自定义动画

transition

transition的属性如下:

  • property:填写需要变化的css属性,我们一般直接填写all
  • duration:完成过渡效果需要的时间单位(s或者ms)
  • timing-function:完成效果的速度曲线
  • delay:动画效果的延迟触发时间

time-function的所有值如下

注意:虽然为了方便,我们经常使用all,表示给所有属性添加过渡,但并不是所有的属性都能使用过渡的,如display:none<->display:block,而visibility:hidden<->visibility:visible却可以,所以不是显示与隐藏的问题,就是display:none<->display:block不能。

transform

一般配合transition过渡使用,不影响其他盒子的位置。元素会在视觉上发生位置变化,但实际位置没变,这一点和相对定位相同。

注意的是,transform不支持inline元素(因为无法指定宽高(也无法指定垂直外边距)),使用前把它变成block

包含四个常用的功能:

translate:位移

1
transform:translate(15px,15px) //向右向下平移15px

传入的单位也可以是百分比,相对的是元素自身的宽/高

rotate:旋转

1
transform:rotate(45deg)

正值表示为顺时针旋转45度

1
transform-origin: x y

设置平面转换中心点,默认是元素中心,x y可以是像素(px),也可以是百分比,相对的也是元素自身的宽高,比如transform-origin: 50% 50%;指定的转换中心点就是盒子中点。也可以是方位名词,所有组合方式只能表示9个点。

scale:缩放

1
transform:scale(x,y) 

里面的数字不跟单位,就是倍数的意思,分别表示宽高缩放为原来的多少倍。

skew:倾斜

transform-origin

transform-origin 是 CSS 中的一个属性,用于定义应用变换(如旋转、缩放、倾斜等)的原点位置。默认情况下,变换的中心点是元素的中心(即 50% 50%

值的数量

transform-origin 可以接受一到三个值。

如果指定一个值,就是在指定x轴的位置,Y 轴默认为 50%

如果指定两个值,分别指定 X 轴和 Y 轴的位置。在支持 3D 转换的情况下,可以指定 X 轴、Y 轴和 Z 轴的位置。

可能的值

百分比:例如 0%, 50%, 100% 等。0% 0% 表示左上角,100% 100% 表示右下角。

关键字

  • 水平方向:left, center, right
  • 垂直方向:top, center, bottom

长度单位:如 px, em, cm 等具体数值。

animation

先通过@keyframes定义动画,再通过animation属性使用动画

定义动画

CSS 动画只需要定义一些关键的帧,而其余的帧,浏览器会根据计时函数插值计算出来

通过 @keyframes 来定义关键帧

比如,如果我们想要让元素旋转一圈,只需要定义开始和结束两帧即可:

1
2
3
4
5
6
7
8
9
10
11
@keyframes rotate{
//开始样式
from{
//在大括号内具体描述每个时刻对应的样式
transform: rotate(0deg);
}
//结束样式
to{
transform: rotate(360deg);
}
}

from 表示最开始的那一帧,to 表示结束时的那一帧。rotate表示自定义的动画名。

也可以使用百分比刻画生命周期:

1
2
3
4
5
6
7
8
9
10
11
12
@keyframes rotate{
0%{
//在大括号内具体描述每个时刻对应的样式
transform: rotate(0deg);
}
50%{
transform: rotate(180deg);
}
100%{
transform: rotate(360deg);
}
}

使用动画

定义好动画,我们就可以直接使用了,使用动画涉及到了许多属性,记忆起来较为困难。

animation是其他8个属性的简写,当使用 animation 简写属性时,按顺序来书写值是很重要的。如果你省略了某些中间的属性,必须确保后续属性仍然按照正确的顺序给出。参考下面书写的顺序。

属性描述属性值
animation-name指定 @keyframes 动画的名称
animation-duration指定动画完成一个周期所需要时间,单位秒(s)或毫秒(ms),默认是 0
animation-timing-function指定动画计时函数,即动画的速度曲线,默认是 “ease”linear、ease、ease-in、ease-out、ease-in-out
animation-delay指定动画延迟时间,即动画何时开始,默认是 0
animation-iteration-count指定动画播放的次数,默认是 1具体次数,infinite(无限多次)
animation-direction 指定动画播放的方向默认是 normalnormal、reverse、alternate、alternate-reverse
animation-fill-mode定义动画在播放之前或之后如何影响元素的样式。默认是 noneforwards、backwards、both
animation-play-state指定动画播放状态,正在运行或暂停。默认是 runningrunning、pauser
1
2
3
.spinner {
animation: rotate 1s linear infinite;
}

什么是响应式设计?响应式设计的基本原理是什么?

是什么

响应式设计的作用就是,让同一套前端代码,能根据设备屏幕的尺寸,主动调整布局和样式

如何实现

方法一:添加一个meta标签

移动端实现响应式,必须添加一个name=viewportmeta标签,让布局视口等于设备宽度

1
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no”>
  • width=device-width:布局视口的宽度等于设备宽度。
  • maximum-scale:是缩放比例的最大值
  • inital-scale:是缩放的初始化
  • user-scalable:值为布尔值,决定用户是否可以进行缩放操作。

方法二:像素单位使用相对单位

  • 百分比

    heightwidth属性的百分比依托于父元素的宽高,但是其他属性则不完全依赖父元素。比如,子元素的top/leftbottom/right如果设置百分比,则相对于最近的定位元素的宽高(补充一下,dom元素的offsetTop和offsetLeft属性相对的也是最近的定位元素)

    子元素的内外边距(padding和margin)如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父元素的width,而与父元素的height无关。如果 padding-top: 10% 相对于父元素高度,而父元素高度又由子元素内容撑开(比如子元素有 padding-top),就会形成“鸡生蛋还是蛋生鸡”的死循环。而宽度通常由父容器明确设定(或视口决定),作为基准更稳定

  • vw/vh:已介绍,不赘述

  • rem:已介绍,不赘述

方法三:使用flex布局,grid布局

方法四:媒体查询

媒体查询是css3中引入的功能,作用类似js中的if-else语句通过媒体查询,可以通过给不同分辨率的设备,编写不同的样式来实现响应式的布局。即便我们使用了相对单位,也只能解决同一类型设备的响应式问题,比如在PC端设计的网页,即便使用了相对单位,在移动端展示的效果也是宽大于高的矩形,展示效果不佳,此时就需要借助媒体查询来解决这个问题。

基本语法

1
2
3
@media [not|only] media-type and (media-feature) {
/* CSS样式规则 */
}
  • @media:用于定义一个媒体查询。
  • [not|only]:可选关键字,not排除特定条件,only用来指定仅在满足条件时应用样式。
  • media-type:指定媒体类型,例如screen(屏幕)、print(打印机)等。如果省略,则默认为all,即适用于所有类型的媒体。
  • and:逻辑运算符,用来连接多个媒体特性条件
  • (media-feature):媒体特性条件表达式,例如(max-width: 600px),注意不要写成(max-width=600px)

示例

根据屏幕大小确定字体大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 当屏幕宽度小于等于600px时 */
@media screen and (max-width: 600px) {
body {
font-size: 18px;
}
//后续还可以写更多选择器
}
/* 当屏幕宽度大于等于768px且小于1200px时 */
@media screen and (min-width: 768px) and (max-width: 1199px) {
body {
font-size: 20px;
}
}
/* 当屏幕宽度大于等于1200px时 */
@media screen and (min-width: 1200px) {
body {
font-size: 24px;
}
}

媒体查询不仅可以使用在css代码中,还能在link标签中使用,比如下面的代码可转化成:

1
2
3
4
5
6
7
// 这段代码无论写在哪里,max-width指的都是视口的宽度
@media screen and (max-width: 600px) {
body {
font-size: 18px;
}
//后续还可以写更多选择器
}
1
2
//其中的max-width指的是视口的宽度,或者说可见区域的宽度
<link rel="stylesheet" media="screen and (max-width: 600px)" href="test.css"/>
1
2
3
4
//test.css
body {
font-size: 18px;
}

这样就能实现在不同尺寸的设备上,使用不同的样式表,.而实现响应式布局的效果。