在前端开发这块儿,CSS那可是核心技术之一,重要性怎么强调都不为过。不管是打造好看的用户界面,还是搞定复杂的页面布局,CSS都起着关键作用。今天呢,咱们就好好唠唠CSS面试里常见的几个重点问题,希望能帮大家更好地应付面试,提升自己的CSS本事。讲解的时候,我会结合具体的代码例子,再讲讲页面呈现出来的效果,让大家能更直观地理解这些知识点。
1. 说说你对 CSS 盒子模型的理解
一般我们被问到对xxx的理解,应该从三点出发:是什么?有什么特点?应用场景?
是什么
当浏览器渲染一个容器时,会将其渲染成 4 个区域,即 content(内容区)、padding(内边距)、border(边框)、margin(外边距)。这 4 个区域共同构成了我们所说的盒子模型。
它就像是一个装东西的盒子,内容在盒子内部,内边距是盒子内部与内容的间隔,边框围绕着内容和内边距,外边距则是盒子与其他元素之间的间隔。
从浏览器的检查页面截取的盒子模型,是这样子的,大家可以去自己的浏览器看一下:
有什么特点
1. 标准盒子模型:在标准盒子模型中,元素的width仅等于content的宽度。例如对于上述代码中的.box元素,它设置了width: 200px,那么在标准盒子模型下,其内容区宽度就是 200px。如果给它添加padding、border和margin,比如:
.box {
width: 200px;
padding: 20px;
border: 10px solid black;
margin: 30px;
}
此时,盒子实际占据的宽度为 :
width + 2 * padding + 2 * border + 2 * margin = 200 + 2 * 20 + 2 * 10 + 2 * 30 = 340px。
从页面效果可以看到,.box元素因为这些属性的设置,整体占据的空间变大,且内容区始终保持 200px 宽度。
2. IE 盒子模型:IE 盒子模型中,元素的width等于content + padding + border的宽度。假设同样的.box元素在 IE 盒子模型下(在现代浏览器中可通过特定设置模拟),代码如下:
.box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 10px solid black;
margin: 30px;
}
这里通过box-sizing: border-box;
启用了类似 IE 盒子模型的计算方式。
此时,盒子实际占据的宽度为 :width + 2 * margin = 200 + 2 * 30 = 260px,
其中 200px 已经包含了content、padding和border的宽度。从页面效果能看到,与标准盒子模型不同,width所设定的值涵盖了内容区、内边距和边框的宽度,整体占据空间的计算方式发生了变化。
两张图对比看一下也能看出明显的区别。
2. 说说你对 CSS 选择器的理解
是什么
不熟悉的友友可以用这个代码测试一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#wrap {
width: 300px;
height: 300px;
border: 1px solid black;
}
div {
width: 200px;
height: 200px;
border: 1px solid red;
}
</style>
</head>
<body>
<div class="wrap" id="wrap" style="border-color: blue;">
<div class="box" id="box">
<h2>hello</h2>
</div>
</div>
<h2>world</h2>
<h2 abc="true">world2</h2>
</body>
</html>
1. id 选择器(#) :通过元素的id属性来选择特定的元素。
例如 #myDiv
,只能匹配 id 为 myDiv 的唯一元素。
2. 类名选择器(.) :根据元素的 class 属性来选择元素。
例如 .myClass
,可以匹配所有 class 为 myClass 的元素。代码中的 .box
就是类名选择器,所有 class 为 box 的元素都会应用其设置的样式。
3. 标签选择器(如 h2) :直接根据 HTML 标签名来选择元素。
例如 h2,会选中页面中所有的 <h2>
标签元素。在代码中,两个 <h2>
标签元素都会受到通用 h2 标签选择器样式的影响(如果有设置的话)。
4. 后代选择器(.wrap h2) :选择某个元素的所有后代元素。
例如.wrap h2
,会选中 class 为 wrap 的元素内部所有的<h2>
标签元素,无论层级多深。在代码中,#wrap
内部的 <h2>hello</h2>
会被 .wrap h2
这样的后代选择器选中(假设存在该选择器样式设置)。
5. 子代选择器(.wrap > h2) :只选择某个元素的直接子元素。
例如 .wrap > h2
,只会选中 class 为 wrap 的元素的直接子元素中的 <h2>
标签元素。由于 #wrap
的直接子元素是 .box
,而不是<h2>
,所以 .wrap > h2
在这段代码中不会选中任何元素。
6. 相邻兄弟选择器(.wrap + h2) :选择紧接在某个元素后的相邻兄弟元素。
例如 .wrap + h2
,会选中 class 为 wrap 的元素后面紧邻的 <h2>
标签元素。在代码中,<h2>world</h2>
紧跟在 #wrap
元素之后,所以如果有 .wrap + h2
的样式设置,该 <h2>
元素会被选中。
7. 兄弟选择器(.wrap ~ h2) :选择某个元素之后的所有兄弟元素。
例如 .wrap ~ h2
,会选中class 为 wrap 的元素之后的所有 <h2>
标签元素。在代码中,<h2>world</h2>
和 <h2 abc="true">world2</h2>
都在 #wrap 元素之后,都会被 .wrap ~ h2
选中(假设存在该选择器样式设置)。
8. 群组选择器(.wrap, h2) :将多个选择器组合在一起,选择多个元素。
例如 .wrap, h2
,会选中 class 为 wrap 的元素以及所有 <h2>
标签元素。在代码中,#wrap 元素以及两个 <h2>
元素都会被 .wrap, h2
选中。
9. 伪类选择器(如 a:hover、a:visited) :用于选择处于特定状态的元素。
例如 a:hover
表示鼠标悬停在链接上时的状态,a:visited
表示链接被访问过之后的状态。虽然代码中没有链接元素展示伪类选择器效果,但如果有 <a>
标签,就可以通过 a:hover
设置鼠标悬停时的样式,比如改变颜色等,从页面交互效果(截图展示鼠标悬停时的样式变化)能直观看到伪类选择器的作用。
10.伪元素选择器(如 a::after) :用于创建一些不在文档树中的元素,并为其添加样式。
例如 a::after
可以在链接元素的后面添加一些内容并设置样式。同样,代码中未展示,但如果有 <a>
标签,设置 a::after {content: ' - 点击后查看';}
,在页面上链接元素后面就会出现额外添加的内容。像这样:
11. 属性选择器(如 [type=text]) :根据元素的属性及属性值来选择元素,例如 [type=text]
会选中所有 type 属性值为 text 的元素,常见于表单元素。在代码中,<h2 abc="true">world2</h2>
,如果有 [abc="true"]
这样的属性选择器设置,该<h2>
元素会被选中。
有什么特点
选择器的优先级遵循 !important > 内联 > id > 类名 > 标签选择器 的规则。
例如:
/* 内联样式 */
<div style="color: red;">这是红色文字</div>
/* id选择器 */
#myDiv {
color: blue;
}
/* 类名选择器 */
.myClass {
color: green;
}
/* 标签选择器 */
div {
color: yellow;
}
如果一个元素同时满足多个选择器的条件,那么最终样式会按照上述优先级来确定。
如果给某个样式加上!important
,例如 color: purple!important;
,则该样式的优先级最高,会覆盖其他规则。
在上述代码中,#wrap 元素通过内联样式 style="border-color: blue;"
设置了边框颜色为蓝色,由于内联样式优先级高于 #wrap 选择器本身设置的 border: 1px solid black
中的黑色边框,所以最终#wrap元素的边框颜色为蓝色。
3. 说说 em/rem/vh/vw 的区别
1. em:相对于声明了 font-size 的父元素的字体大小。
例如,如果父元素的font-size为 16px,子元素设置font-size: 1.5em;,那么子元素的字体大小就是16px * 1.5 = 24px。在实际代码中,如果有如下结构:
<div style="font-size: 16px;">
<p style="font-size: 1.5em;">这是一段文字</p>
</div>
p元素的字体大小就会根据父元素的 font-size 计算得出 24px,从页面展示效果能看到这种相对计算的效果。
2. rem:相对于根元素(即<html>
标签)的字体大小。
假设在代码中,标签设置了font-size: 10px,有一个.box元素设置font-size: 2rem;,那么.box元素内的文字大小就会是 20px。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rem Unit Example</title>
<style>
html {
font-size: 10px;
}
.box {
font-size: 2rem;
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
3. vh:相对于视窗高度的百分比。
1vh 等于视窗高度的 1%。比如,视窗高度为 800px,那么 1vh 就是 800px * 0.01 = 8px。常用于创建自适应高度的布局,例如使某个元素的高度始终为视窗高度的一半,可以设置 height: 50vh;
。以如下代码为例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
height: 50vh;
background-color: red;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
无论视窗高度如何变化,.box元素的高度始终会保持为视窗高度的 50%,从不同视窗高度下的页面截图能清晰看到这种自适应效果。
4. vw:相对于视窗宽度的百分比。1vw 等于视窗宽度的 1%。假设视窗宽度为 1200px,那么 1vw 就是1200px * 0.01 = 12px。常用于创建自适应宽度的布局,比如使某个元素的宽度始终为视窗宽度的三分之一,可以设置width: 33.33vw;。例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 33.33vw;
height: 500px;
background-color: blue;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
随着视窗宽度的改变,.box元素的宽度会始终保持为视窗宽度的三分之一左右,通过不同视窗宽度下的页面截图可展示其自适应特性。
移动端适配方案
1. rem:通过设置根元素的 font-size 为不同屏幕宽度下的合适值,然后使用 rem 单位来设置元素的尺寸,从而实现移动端适配。
2. 媒体查询:通过 @media
规则,针对不同的屏幕尺寸范围设置不同的样式。例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 200px;
height: 200px;
background-color: red;
}
@media screen and (max-width: 1000px) {
.box{
width: 100px;
height: 100px;
background-color: blue;
}
}
</style>
</head>
<body>
<div class="box">
<div class="context">
<h2>hello</h2>
</div>
</div>
</body>
</html>
当屏幕宽度小于等于 1000px 时,.box元素的宽度、高度会变为 100px,背景颜色变为蓝色。通过在不同屏幕宽度下查看页面(截图展示不同宽度下的效果),能清晰看到媒体查询在移动端适配中的作用。
pc 端适配方案
1. % + 媒体查询:使用百分比单位设置元素的尺寸,使其相对于父元素进行自适应,再结合媒体查询针对不同屏幕宽度范围进行微调。例如,一个容器设置width: 50%;,会根据父容器的宽度自适应,同时可以通过媒体查询在不同屏幕宽度下调整其宽度比例。
2. rem:同样可以在 PC 端使用 rem 进行适配,原理与移动端类似,通过合理设置根元素的font-size,然后用 rem 单位来布局。
4. CSS 中有哪些方式可以隐藏元素?区别?
举个栗子,本来是这样的页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 10px;
height: 10px;
background-color: red;
/* overflow: hidden; */
/* display: none; */
/* opacity: 0; */
/* visibility: hidden; */
/* clip-path: polygon(0 100px, 50px 0, 100px 100px, 0 10px); */
/* clip-path: polygon(0 0,0 0,0 0,0 0); */
/* transform: scale(0); */
/* position: absolute; */
/* left: -9999px; */
}
</style>
</head>
<body>
<div class="box"></div>
<p>hello</p>
<script>
let box = document.querySelector('.box');
box.addEventListener('click', function() {
console.log('hello');
});
</script>
</body>
</html>
1. display: none; :元素完全不占据文档流,在页面中就像不存在一样,也不会触发任何事件。例如:
2. opacity: 0; :元素仍然占据文档流,只是透明度为 0,视觉上不可见,但可以触发事件。例如:
3. visibility: hidden; :元素占据文档流,只是不可见,也不会触发事件。与opacity: 0不同的是,visibility: hidden隐藏的元素虽然不可见,但仍然会影响页面的布局,例如会占据空间。例如:
4. clip-path: polygon(0 0,0 0,0 0,0 0); :通过裁剪路径将元素裁剪为一个点,从而使其不可见,但仍然占据文档流,不触发事件。例如:
5. position: absolute; :将元素设置为绝对定位,然后将其移出可视区域,例如left: -9999px;,元素虽然在文档流中,但不在可视范围内,不会触发事件。
6. width: 0;height: 0;overflow: hidden; :将元素的宽高设置为 0,并隐藏溢出内容,元素仍然占据文档流位置,但不可见,不触发事件。
7. transform: scale(0); :将元素缩放为 0,元素仍然占据文档流,不触发事件。例如:
5. 说说你对 BFC 的理解
是什么
BFC(Block Formatting Context)即块级格式化上下文,是浏览器渲染的一个特殊区域,有其独特的渲染规则。BFC 容器是一个独立的容器,容器里面的子元素不会影响到外面的元素,反之亦然。可以把它看作是一个隔离的 “小世界”,内部元素的布局和渲染不会干扰到外部。
有什么特点
1. bfc 容器在计算高度时,会把浮动元素也考虑进去:在普通文档流中,浮动元素可能会导致父元素高度塌陷,但如果父元素是一个 BFC 容器,那么在计算高度时会包含浮动子元素的高度。例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BFC 容器计算高度示例</title>
<style>
.parent {
border: 10px solid black;
/* overflow: hidden; 创建 BFC */
}
.float-child {
float: left;
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div class="parent">
<div class="float-child"></div>
</div>
</body>
</html>
此时,.parent元素的高度会正确包含.float-child元素的高度。
2. 子元素的盒模型不会影响到 bfc 外部的元素:BFC 内部元素的外边距等不会与外部元素发生重叠等干扰。例如,BFC 内部元素设置的 margin-top 不会影响到外部元素的位置。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BFC Margin Isolation Example</title>
<style>
.bfc-container {
/* 触发 BFC */
/* overflow: hidden; */
background-color: lightblue;
}
.bfc-child {
margin-top: 50px;
background-color: lightcoral;
height: 100px;
}
.outside-element {
background-color: lightgreen;
height: 100px;
}
</style>
</head>
<body>
<div class="bfc-container">
<div class="bfc-child"></div>
</div>
<div class="outside-element"></div>
</body>
</html>
3. 其他特性和普通容器一样:BFC 容器在布局和显示上遵循普通块级元素的一些基本规则,如可以设置宽度、高度、边距等。
怎么实现
1. overflow: hidden || auto || scroll; :通过设置元素的overflow属性为hidden、auto或scroll,可以创建 BFC。
2. float: left || right; :设置元素为浮动(left或right),也可以使该元素成为一个 BFC 容器。
3. position: absolute || fixed; :绝对定位(absolute)或固定定位(fixed)的元素会创建 BFC。
4. display: inline-xxx || table-xxxx || flex || grid || tabel; :一些特定的display属性值,如inline-block、table-cell、flex、grid等,也能使元素创建 BFC。
应用场景
1. 清除浮动:利用 BFC 容器计算高度时包含浮动元素的特性,可以解决浮动导致的父元素高度塌陷问题。如上述例子中,通过使父元素成为 BFC 容器(设置overflow: hidden;),成功清除了浮动带来的影响。
2. 防止 margin 重叠:在 BFC 内部,子元素的margin不会与外部元素的margin发生重叠,从而避免了一些布局上的问题。
3. 自适应两栏布局:可以利用 BFC 的特性实现自适应两栏布局。例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.left{
width: 200px;
height: 80vh;
background-color: red;
float: left;
}
.right{
height: 100vh;
background-color: rgb(94, 229, 229);
/* overflow: hidden; */
}
</style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
</body>
</html>
通过使右边元素成为 BFC 容器,它会自动适应左边浮动元素的布局,实现两栏自适应。