CSS高频面试题总结
前言
整篇都是对面试过程中遇到过的CSS题目汇总,答案来自于网上各文档,亦或是看文档后的理解,若有不对的地方请指出,后续遇到新的题目也会持续补充。
1. 盒模型
页面中的每个元素都可以视为一个盒子,每个盒子由margin(外边距)、border(边框)、padding(内间距)、content(内容) 组成。如下图:
盒模型包括标准盒模型、IE(怪异)盒模型两种,区别是它们对于content宽(高)度的计算方式的不同。具体如下:
.box {
width: 100px;
height: 100px;
padding: 10px;
border: 1px solid #eee;
margin: 10px;
}
- 标准盒模型中,content宽(高)度 = width的值,即100px;
- IE盒模型中,content宽(高)度的值 = width - padding -border,所以content的实际宽度为100 - 10 * 2 - 1 * 2 = 78px ;
标准盒模型设置box-sizing: border-box;
转为IE盒模型,IE盒模型设置box-sizing: cotent-box;
转为标准盒模型。
2. display: inline-block 为什么会有间隙?
因为HTML
代码中的换行符、空格会被转成一个空白符,在字体不为0
的情况下,空白符占据一定宽度,所以就出现了空隙。
解决方法
- 设置
font-size: 0
; - 移除换行和空格;
3. 文档流
标准文档流指块级元素一个一行地从上向下排列,行内元素从左往右排列的流程。脱离文档流指不遵循标准文档流的排列方式,即脱离文档流的元素不和标准文档流的元素在同一个层级(可以将每个层级理解为一个面)进行排列,而是将元素放在了一个新的层级,且不同层级内部的元素排列不会受到其它层级的影响。
- 脱离文档流元素存在时的布局方式?
- 使用float时,其它盒子会无视这个元素,但其它盒子内的文本依然会为这个元素让出位置,围绕在浮动元素周围;
- 其他盒子在定位的时候,会当作脱离流的元素不存在而进行布局;
4. BFC 块级格式化上下文
Block Formatting Context。元素类型分为块元素、行元素、行内块元素,块级格式化上下文就是一个只有块元素参与的独立的渲染区域,这个区域规定了内部元素如何布局,与区域外元素毫不相关。
BFC区域内布局规则
- 内部元素会在竖直方向依次排列;
- bfc区域不会与浮动元素区域重叠;
- 计算bfc元素的高度时,浮动元素也参与计算;
- 同一个bfc内的垂直方向两个元素之间的距离由margin决定,且两个相邻元素的margin会发生重叠;
- BFC是一个独立的容器,容器内部元素的排列不会影响到外部元素;
使用场景
- 自适应两栏布局(bfc区域不会与浮动元素区域重叠);
- 清除浮动(计算bfc元素的高度时,浮动元素也参与计算);
- 解决margin重叠(同一个bfc内的垂直方向两个元素之间的距离由margin决定,且两个相邻元素的margin会发生重叠);
如何创建BFC
- body根元素;
- overflow的值不为visible;
- position的值不为static和relative;
- display的值为flex、inline-flex、inline-block;
关于margin重叠
margin重叠表现为当给两个相邻元素设置上下margin后,它们呈现出来的距离并不是两个元素的间距之和。通过下面例子来看:
给el1
元素设置margin-bottom: 30px;
,给el2
元素设置margin-top: 20px;
,正常情况下el1
和el2
之间的距离应该是30px + 20px = 50px
,但实际却是30px,这就是因为发生了margin重叠。
<div class="wrap">
<div class="el1">1</div>
<div class="el2">2</div>
</div>
.wrap {
overflow: hidden;
}
.el1 {
width: 100px;
height: 100px;
background: red;
margin-bottom: 30px;
}
.el2 {
width: 200px;
height: 200px;
margin-top: 20px;
background-color: aquamarine;
}
这是因为在bfc区域内,对于这种情况有自己的计算规则,具体如下:
- 都为正数,取两者中值大的;
- 一正一负,取
正 - 负
; - 都为负数,取两者中绝对值较大的那个值;
5. position定位
position用于设置元素在文档流中的位置,可通过top/bottom/left/right
来改变元素的位置。
定位类型介绍
定位类型 | 描述 |
---|---|
static | 1. 无定位, 元素按照标准文档流排列;2. 设置z-index/top/left 等属性不生效; |
relative | 1. 绝对定位,元素按照标准文档流排列; 2. 设置top/left 等属性是根据元素原来的位置进行定位; |
absolute | 1. 绝对定位,元素脱离标准文档流; 2. 设置top/left 等属性是根据最近的具有position属性且值不为static的祖先元素进行定位; |
fixed | 1. 固定定位,元素脱离标准文档流; 2. 设置top/left 等属性是根据浏览器视口进行定位; 3. 页面滚动时,元素不会跟随页面滚动; |
sticky | 1. 粘性定位,基于用户滚动的位置进行定位; 2. 设置top/left 等属性是根据页面滚动高度进行定位。如position: sticky; top: 90px; 表现为当页面滚动高度小于90时,元素表现为relative 定位,滚动高度超过90时表现为fixed 定位; |
给定位元素同时设置left和right(top/bottom)是什么效果?
给定位元素同时设置left和right后,呈现效果要根据元素是否设置宽度来判断:
- 设置了
width
属性,则right
属性会被忽略; - 未设置
width
属性,则会拉伸这个元素去满足left
和right
的值。如设置了left: 0; right: 0;
就相当于width: 100%;
的效果;
给元素同时设置top和bottom同理,不过决定的是元素高度。根据这个特点可实现将一个定位元素设置为全屏:
.div {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
6. float 浮动
float
最早是用于实现文字围绕图片排列功能。取值可为left、right、none
, 分别代表向左浮动、向右浮动、不浮动。
浮动元素特性
当给元素设置float
不为none
时,浮动元素:
- 允许文本或者内联元素围绕,碰到父元素边框或其它浮动元素后停留;
- 脱离标准文档流,造成父元素高度塌陷;
使用场景
- 文本或者内联元素围绕着图片;
- 两栏布局(代码见下文实现两栏布局部分);
清除浮动方式
- 在浮动元素后面添加一个空元素如
<div class="clear"></div>
,并设置.clear{ clear: both; }
; - 给浮动元素的父元素设置
overflow: hidden
(利用BFC元素不和浮动元素重合特性); - 为浮动元素添加
::after
伪元素并添加clear
属性,具体代码如下:
div::after {
content: '';
display: block;
clear: both;
}
- clear属性清除浮动的原理 使用clear并不是清除浮动,而是清除浮动所造成的影响。
div::after {
content: '';
display: block;
clear: both;
}
以伪元素为例,设置了clear: both;
后,伪元素不再允许周围有浮动的元素产生,所以浮动元素相对于伪元素也就失去了浮动的效果,浮动元素div对于伪元素来说也就有了高度,伪元素就会位于浮动元素的下面,伪元素的位置也就撑起了父级元素的高度,解决了高度坍塌的问题。
7. flex 弹性布局
该布局方式的主要思想是让父元素能够调整子元素的宽度、高度、排列方式,从而更好的适应可用的布局空间。当给元素设置display: flex
后,这个元素就成为了一个flex容器,它所有子元素都会成为它的项目。flex容器默认有两条轴,一条是主轴,一条是与主轴垂直的交叉轴;
注意:设置了flex的元素,其内部元素的float、vertical-alignd都将失效。
flex容器常用属性
flex-direction
:设置主轴的方向,决定了容器内项目的排列方式,默认是水平方向。- 可选值为
<column | column-reverse | row | row-reverse>
。
- 可选值为
flex-wrap
:设置容器内项目是否允许换行,默认不允许换行。- 可选值
nowrap | wrap | wrap-reverse
。
- 可选值
justify-content
:设置项目在主轴上的对齐方式。- 可选值
flex-start | flex-end | center | space-between | space-around
。
- 可选值
align-items
:设置项目在交叉轴上的对齐方式。- 可选值
flex-start | flex-end | center | baseline | stretch
。
- 可选值
align-content
:设置多根轴线时的对齐方式,一般应用在容器内的项目不止一行的场景中。- 可选值
flex-start | flex-end | center | baseline | stretch
。
- 可选值
项目常用属性
align-self
:设置某一个项目在交叉轴上的对齐方式。flex-shrink
:设置是否允许该项目缩小。flex-grow
:设置是否允许该项目放大。flex-basis
:设置项目占据主轴的空间的大小。浏览器会按照该属性来判断容器是否有剩余空间,从而决定放大或缩小项目。flex
:是flex-grow
、flex-shrink
和flex-basis
的简写,默认值0 1 auto
。
flex-basis 详解
特性
- 当主轴为水平时,该属性的值代表每个项目的宽度;主轴为竖轴时,该属性的值代表每个项目的高度,这也是它跟width和height不一样的地方。
- 当给一个元素同时设置了flex-basis和width时,flex-basis的优先级更高。
- 浏览器会根据该属性来判断flex容器是否有剩余空间,从而决定放大或缩小项目。
取值说明
该属性取值可为<auto | 0% | length>
。
flex: auto
:长度等于项目(设置的width/height)的长度。如果项目未指定长度(未设置width或height属性),则长度就是元素内容撑开的长度。flex: 0%
:不代表项目的最终宽度为0,而是代表会忽略元素设置的width或 height属性。当flex容器有剩余空间时,会根据剩余空间和flex-grow属性的值为该元素分配宽度。flex-basis: 100px
:即直接设置项目的宽度为100px。
flex: 1
指什么?
flex是flex-grow
、flex-shrink
和flex-basis
的缩写。三者之间的关系如下:
- 首先根据
flex-basis
的值来计算flex容器是否有剩余空间; - 当flex容器有剩余空间时,则根据
flex-grow
来放大项目; - 若无剩余空间且空间不能排列所有的项目时,则根据
flex-shrink
来缩小项目。
.parent {
display: flex;
width: 600px;
}
.parent > div {
height: 100px;
}
.item-1 {
width: 140px;
flex: 1 1 0%;
background: blue;
}
.item-2 {
width: 100px;
flex: 2 1 auto;
background: darkblue;
}
.item-3 {
flex: 1 1 200px;
background: lightblue;
}
<div class="parent">
<div class="item-1"></div>
<div class="item-2"></div>
<div class="item-3"></div>
</div>
主轴上flex容器总尺寸为600px。所有子项目的总基准值是:0% + auto + 200px = 300px,其中
0%
即 0 宽度;auto
对应取原尺寸即100px
;
故剩余空间为600px - 300px = 300px
,伸缩放大系数之和为1 + 2 + 1 = 4
。剩余空间分配如下:
item-1
和item-3
各分配 1/4,各得 75pxitem-2
分配 2/4,得 150px
各项目最终宽度为:
item-1 = 0% + 75px = 75px item-2 = auto + 150px = 250px item-3 = 200px + 75px = 275px
8. CSS层叠上下文、层叠等级、层叠顺序
层叠上下文(stacking context)
首先要知道我们浏览的一个网页不只是由一层构成的。如下图中的情况,a和c、d两个元素发生了重叠,为了呈现a盖住c、d的效果,所以需要先绘制c和d再绘制a。因此浏览器在绘制之前将会对这三个元素进行分层,a在一个层级,c和d属于同一个层级。分完后会先绘制b所在的层级的所有元素,再绘制a所在的层级的所有元素,这样就实现了a盖住c、d的效果。分层的另外一个好处就是如果发生重绘,则只会重绘元素所在的层级,不会影响到其它图层。那么浏览器是根据什么对元素进行分层呢?就是层叠上下文。
层叠上下文是html中的一个三维概念,即每个盒模型的位置是三维的,分别是平面画布上的X轴
,Y轴
以及表示层叠的Z轴
。元素在页面上沿X、Y轴
平铺,层叠上下文按照既定规则在Z轴排列。如果一个元素含有层叠上下文,表现为它离屏幕观察者更近。
如何产生层叠上下文
- html根元素就是一个默认的层叠上下文,称为“根层叠上下文”;
- 设置了position值不为static,且具有z-index的值为数值;
- CSS3中的一些新属性:
- 父元素的display属性值为
flex|inline-flex
,子元素z-index
属性值不为auto
的时候,子元素为层叠上下文元素; - 元素的
opacity
属性值不是1
; - 元素的
transform
属性值不是none
; - 元素的
filter
属性值不是none
; - 元素的
isolation
属性值是isolate
; will-change
指定的属性值为上面任意一个;- 元素的
-webkit-overflow-scrolling
属性值设置为touch
。
- 父元素的display属性值为
层叠等级
- 在同一个层叠上下文中,它定义了该上下文中的层叠上下文元素在
Z轴
的上下顺序。例:
<style>
div {
position: relative;
width: 100px;
height: 100px;
}
p {
position: absolute;
font-size: 20px;
width: 100px;
height: 100px;
}
.a {
background-color: blue;
z-index: 1;
}
.b {
background-color: green;
z-index: 2;
top: 20px;
left: 20px;
}
.c {
background-color: red;
z-index: 3;
top: -20px;
left: 40px;
}
</style>
<body>
<div>
<p class="a">a</p>
<p class="b">b</p>
</div>
<div>
<p class="c">c</p>
</div>
</body>
因为p.a、p.b、p.c
三个的父元素div都没有设置z-index
,所以不会产生层叠上下文,所以.a、.b、.c都处于由<html></html>
标签产生的“根层叠上下文”中,属于同一个层叠上下文,此时谁的z-index
值大,谁在上面。
- 层叠等级的比较只有在当前层叠上下文元素中才有意义。不同层叠上下文中比较层叠等级是没有意义的。例:
<style>
div {
position: relative;
width: 100px;
height: 100px;
}
.box1 {
z-index: 2;
}
.box2 {
z-index: 1;
}
p {
position: absolute;
font-size: 20px;
width: 100px;
height: 100px;
}
.a {
background-color: blue;
z-index: 2;
}
.c {
background-color: red;
z-index: 999;
top: -20px;
left: 40px;
}
</style>
<body>
<div class="box1">
<p class="a">a</p>
</div>
<div class="box2">
<p class="c">c</p>
</div>
</body>
分别给
box1 box2
设置了z-index
,因此a、c
分别属于box1、box2层叠上下文。从图可以看出虽然a元素的z-index值小于c元素的z-index的值,但a元素仍然在c元素的上面。这就是因为a所在的层叠上下文box1的层级 高于 c所在的层叠上下文box2的层级,所以比较a和c的层级没有意义。
- 在普通元素中,它描述的是普通元素在
Z轴
的上下顺序。普通元素的层叠等级优先由其所在的层叠上下文决定。
层叠顺序(stacking order)
层叠顺序是指在同一个层叠上下文中,元素在Z轴
上显示的顺序。具体层叠顺序如下图:
为什么
inline/inline-block
元素的层叠顺序要高于block
/float
元素? 因为像border/background
属于装饰元素的属性,浮动和块级元素一般用来页面布局,而网页设计之初最重要的就是文字内容,所以在发生层叠时会优先显示文字内容,保证其不被覆盖。
层叠元素后排列规则总结
首先比较的两个元素是否处于同一个层叠上下文:
- 如果属于同一层叠上下文,谁的层叠等级大,谁在上面(根据“层叠顺序”图来判断);
- 如果不属于同一层叠上下文,则比较它们所处的层叠上下文的层叠等级;
- 当两个元素层叠等级相同、层叠顺序相同时,在DOM结构中后面的元素层叠等级在前面元素之上。
9. 伪类和伪元素
- 伪类:是一种选择器,选择处于特定状态的元素;以
:
开头;如鼠标hover
; - 伪元素:是一个虚拟元素,但不存在dom中;以
::
开头;常用::after、::before
来实现清除浮动、绘制三角形等功能;
10. 隐藏元素的方式
visibility: hidden
:元素视觉上不可见,但占用页面空间,可以进行交互;display: none
: 元素会不可见,并且从文档流中消失,不再占用页面空间;opacity: 0
:将元素的透明度设置为0
,占据空间且可以进行交互;position: absolute
:通过设置left/top在页面外,使元素位置在可见区域之外;transform: scale(0)
: 将一个元素设置为缩放0,元素将不可见,元素原来所在的位置将被保留,不可交互;height: 0
11. 移动端适配方案
- rem:以html根元素的font-size大小来进行适配。
<script>
function setRem() {
// 当前页面宽度相对于 750 宽的缩放比例
const scale = document.documentElement.clientWidth / 750;
document.documentElement.style.fontSize = scale + 'px';
}
setRem();
</script>
- vw/vh
- 百分比布局
- 通过媒体查询,针对不同的屏幕大小单独设置
- px 为主,搭配 vw/vh、媒体查询与 flex 进行布局
12. 如何解决移动端边框1px问题?
屏幕分辨率:屏幕在纵横向上的像素点数。相同屏幕尺寸,分辨率越大越清晰。
解决方式
- 直接给border的宽度设置为0.5,缺点是安卓系统不能使用且ios8不兼容;
- 用图片代替边框,缺点是无法实现圆角;
border: 1px solid transparent;
border-image: url('xxx.jpg') 2 repeat;
- 伪元素先放大,在使用scale缩放;
.div {
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
height: 1px;
width: 100%;
transform: scaleY(0.5);
transform-origin: left top;
background-color: red;
}
}
- box-shadow模拟边框实现;
box-shadow: inset 0px -1px 1px -1px #c8c7cc;
代码实现
1. 实现两栏布局
两栏布局指左边宽度固定,右边元素宽度自适应。有以下4种方式:
- 方式1: 左元素(200px)浮动,右元素通过
margin-left: 200px;
来让右边元素偏移200px;
<div class="parent">
<div class="left"></div>
<div class="right"></div>
</div>
.parent {
height: 100px;
position: relative;
}
.left {
float: left;
width: 200px;
height: 100px;
}
.right {
width: 200px;
height: 100px;
// 偏移左边200px
margin-left: 200px;
}
- 方式2: 左元素absolute脱离文档流,右元素不设置宽度,设置
left: 200px; right: 0
,原理见上文position同时设置left和right原理:
.parent {
height: 100px;
position: relative;
}
.left {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 100px;
}
.right {
position: relative;
left: 200px;
right: 0;
}
- 方式3: 左元素浮动,右元素设置为BFC元素,利用BFC元素不和浮动元素重叠特性:
.parent {
height: 100px;
}
.left {
float: left;
width: 200px;
height: 100px;
background: red;
}
.right {
height: 100%;
background: blue;
overflow: hidden;
}
- 方式4: flex布局利用
flex: 1
:
.parent {
height: 100px;
display: flex;
}
.left {
width: 200px;
height: 100px;
background: red;
}
.right {
flex: 1;
height: 100%;
background: blue;
}
2. 实现三栏布局
三栏布局指左右两栏宽度固定,中间宽度自适应。
- 方式1: 左元素左浮动,中间元素设置为BFC元素,右元素右浮动:
这种情况下要注意right元素放在center元素前面,这样right元素才能浮动。
// right 要放center元素前面,不然center元素会挡住right元素浮动
<div class="parent">
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</div>
.left {
float: left;
width: 200px;
height: 100px;
background: red;
}
.center {
height: 100%;
background: blue;
overflow: hidden;
}
.right {
float: right;
width: 200px;
height: 100px;
background: green;
}
- 方式2: 左右元素都absolute,中间元素设置左右margin为左右元素的宽度(right元素也要放在center元素前面):
<div class="parent">
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</div>
.left {
position: absolute;
left: 0;
width: 200px;
height: 100px;
background: red;
}
.center {
margin-left: 200px;
margin-right: 200px;
height: 100%;
background: blue;
}
.right {
position: absolute;
right: 0;
width: 200px;
height: 100px;
background: green;
}
- 方式3: 利用flex,同两栏布局一样。
3. 实现如下布局
思路:利用flex布局,且为每个元素单独设置align-self属性,改变其对齐方式。
<div class="box1">
<div class="a">a</div>
<div class="b"></div>
<div class="c"></div>
</div>
.box1 {
display: flex;
flex-direction: column;
}
.a, .b, .c {
width: 200px;
height: 50px;
margin-bottom: 20px;
background: red;
}
.b {
align-self: center;
}
.c {
align-self: flex-end;
}
4. 用动画实现将一个div从左边移动到右边
@keyframes toRight {
0% {
margin-left: 0px;
}
100% {
margin-left: 600px;
}
}
.parent {
width: 100px;
height: 100px;
background: red;
animation: toRight 1s infinite;
}
5. 使用css实现三角形
原理:border是由三角形组成的;给一个元素不设置宽高只设置border的时候,表现如下:
.parent {
width: 100px;
height: 100px;
border: 1px solid black;
position: relative;
}
.parent::before {
content: '';
display: block;
width: 0;
height: 0;
position: absolute;
border-left: 50px solid red;
border-top: 50px solid red;
border-bottom: 50px solid transparent;
border-right: 50px solid transparent;
}
6. 实现等边三角形
思路: 假定等边三角形的高度为40,再根据等边三角形的每个角都为60度,则有
sin(60) = 高度(40) / 边长
,可以计算出来边长为23左右。再使用border绘制三角形即可。
.parent {
width: 0px;
height: 0px;
border-left: 23px solid transparent;
border-right: 23px solid transparent;
border-bottom: 40px solid red;
}
7. 实现一个扇形
思路: 一边的border + border-radius 50%
.parent {
width: 0;
height: 0;
border: 100px solid transparent;
border-top-color: red;
border-radius: 50%;
}
8. 实现一个梯形
思路:元素本身一个宽度实现矩形区域 + border实现三角形;
.parent {
width: 100px;
height: 0;
border-bottom: 100px solid red;
border-right: 40px solid transparent;
}
9. 实现文字多行打点展示
.parent{
width: 200px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
10. 实现一个元素满屏展示
思路:见上文给一个元素同时设置top/bottom和left/top。
.parent {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: pink;
}
11. CSS实现元素固定宽高比
- 方式1: aspect-ratio
/* 宽/高 */
aspect-ratio: 16 / 9;
- 方式2: padding-bottom
原理: 垂直方向上的内外边距为百分比时,是按父元素的宽度进行计算。
.wrap {
width: 800px;
}
.child {
width: 400px;
height: 0;
/* 元素显示出来的高度为800 * 10% = 80 */
padding-bottom: 10%;
}
参考文章:
转载自:https://juejin.cn/post/7275262092297601058