前言
CSS的面试题可谓是鱼龙混杂,在整理这一类的面试题时,也是觉得写之不尽,越写越多,原本是打算用一篇文章去写尽CSS的面试题,现在看来是我想多了,在文章字符数达到10w的时候被提示超出最大字符限制了,那么就将CSS篇暂时分为上下篇吧
文章里的一些实例也因为篇幅原因无法展示,也许以后会补上?不知道
算了,多说无益,让我们开始吧

一、介绍一下CSS选择器及其优先级
CSS(层叠样式表)是网页设计的核心语言之一,而选择器则是CSS的基石 。CSS 选择器用于定位 HTML 元素,从而为其应用样式规则。
CSS选择器基础:认识选择器
CSS选择器的作用是"选择"HTML元素并为其应用样式。就像在人群中找人一样,我们需要不同的"识别方式"来找到特定的元素。
-
CSS 定义:层叠样式表,用于选择 HTML DOM 元素并应用样式规则。
-
引入方式
- 内联标签(
<style>
) :在 HTML 文件的<head>
标签内使用<style>
标签编写 CSS 代码。 - 外联样式(
<link>
) :通过<link>
标签引入外部 CSS 文件。 - 行内样式 :直接在 HTML 元素的
style
属性中编写 CSS 代码。
- 内联标签(
-
渲染流程:先下载样式,再解析 DOM 并应用样式,DOM 与 CSS 结合形成渲染树(render tree),最后通过浏览器渲染引擎渲染得到页面。
渲染树示意图

选择器类型一览
选择器类型 | 格式示例 | 优先级权重 |
---|---|---|
id 选择器 | #id | 100 |
类选择器 | .classname | 10 |
属性选择器 | a[ref="eee"] | 10 |
伪类选择器 | li:last-child | 10 |
标签选择器 | div | 1 |
伪元素选择器 | li:after | 1 |
相邻兄弟选择器 | h1+p | 0 |
子选择器 | ul>li | 0 |
后代选择器 | li a | 0 |
通配符选择器 | * | 0 |
1. 基本选择器类型
标签选择器 - 通过HTML标签名选择元素:
css
p {
color: blue;
}
这会选择页面中所有的<p>
段落元素,并将文字颜色设为蓝色。
类选择器 - 通过class属性选择元素:
css
.highlight {
background-color: yellow;
}
在HTML中使用:<p class="highlight">这段文字会高亮</p>
ID选择器 - 通过id属性选择唯一元素:
css
#header {
font-size: 24px;
}
在HTML中使用:<div id="header">网站标题</div>
二、CSS选择器优先级:谁说了算?
当多个样式规则作用于同一个元素时,浏览器如何决定应用哪个样式呢?这就涉及到优先级的概念。
优先级权重计算规则:
- 标签选择器:1
- 类选择器:10
- ID选择器:100
- 行内样式:1000
!important
:最高优先级
让我们看一个实际例子:
html
<div class="container" id="main">
<P style="color: pink;">我看看怎么个事!</P>
</div>
css
p {
color: blue !important;
}
.container p {
color: red;
}
#main p {
color: green;
}
虽然行内样式权重最高(1000),但!important
具有最高优先级,所以最终文字显示蓝色。如果没有!important
,则行内样式的粉色会生效。
实例与展示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS</title>
<style>
/* 1(样式) */
/* 如果一定要显示蓝色 */
/* !important 很重要 */
p {
color: blue !important;
}
/* 10(类) + 1(样式) */
.container p {
color: red;
}
/* 100(id) + 1(样式) */
#main p {
color: green;
}
</style>
</head>
<body>
<div class="container" id="main">
<P style="color: pink;/* 1000 */">我看看怎么个事!</P>
</div>
</body>
</html>

三、组合选择器:精准定位元素
1. 后代选择器(空格)
选择某个元素内部的所有特定后代元素:
css
.container p {
text-decoration: underline;
}
这会选择.container
内部的所有<p>
元素,无论嵌套多深。
2. 子元素选择器(>)
只选择直接子元素:
css
.container > p {
font-weight: bold;
}
这只会选择.container
直接子元素中的<p>
,不会选择嵌套在其他元素中的<p>
。
3. 相邻兄弟选择器(+)
选择紧接在某个元素后的第一个兄弟元素:
css
h1 + p {
color: red;
}
这会让紧跟在<h1>
后的第一个<p>
变为红色。
4. 通用兄弟选择器(~)
选择某个元素后面的所有同级元素:
css
h1 ~ p {
color: blue;
}
这会让<h1>
后面的所有<p>
兄弟元素变为蓝色。
实例与展示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>选择器</title>
<style>
/* 相邻兄弟选择器 */
/* 得分为2 */
h1+p{
color: red;
}
/* 通用兄弟选择器 */
/* 得分为2 */
h1~p{
color: blue;
}
/* 子元素选择器 直接子元素*/
/* 用于选择.container元素内的段落文本 */
.container >p{
font-weight: bold;
}
.container p{
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>标题</h1>
<p>这是第一段文字</p>
<p>这是第二段文字</p>
<a href="">链接</a>
<span>这是一个span元素</span>
<div class="inner">
<p>这是一个内部段落</p>
</div>
</div>
</body>
</html>

四、伪类选择器:元素的状态选择
伪类选择器允许我们根据元素的状态或位置来应用样式。
1. 交互状态伪类
css
/* 鼠标悬停时 */
p:hover {
background-color: yellow;
}
/* 按钮被点击时 */
button:active {
background-color: red;
color: white;
}
/* 输入框获得焦点时 */
input:focus {
border: 2px solid blue;
}
2. 结构伪类
css
/* 选择奇数位置的列表项 */
li:nth-child(odd) {
background-color: lightgray;
}
/* 选择除最后一个外的所有子元素 */
li:not(:last-child) {
margin-bottom: 10px;
}
3. 表单相关伪类
css
/* 复选框被选中时改变相邻标签颜色 */
input:checked + label {
color: blue;
}
实例与展示
html
<!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>
/* 伪类选择器 */
button:active{
background-color: red;
color: white;
}
p:hover{
background-color: yellow;
}
/* 鼠标选中文本的效果 */
::selection{
background-color: blue;
color: white;
}
/* 输入框的效果 */
input:focus{
border: 2px solid blue;
outline: none; /* 移除浏览器默认outline */
accent-color: blue; /* 设置复选框选中标记颜色 */
}
/* 复选框的效果 */
input:checked + label{
color: blue;
}
li:nth-child(odd){
background-color: lightgray;
}
li:not(:last-child){
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>伪类选择器示例</h1>
<button>点击我</button>
<p>鼠标悬浮在这里</p>
<input type="text" placeholder="输入框">
<input type="checkbox" id="option1">
<label for="option1">选项1</label>
<input type="checkbox" id="option2" checked>
<label for="option2">选项2</label>
<ul>
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
<li>列表项4</li>
</ul>
</div>
</body>
</html>

五、易错点一------组合选择器的优先级计算
下面我们来看一个题目
js
.container ul li:nth-child(odd)
这个选择器的优先级是多少?
答案为10+1+1+10=22
因为:nth-child(odd)是伪类选择器,优先级是10
六、易错点二------nth-child vs nth-of-type:关键区别
这两个选择器经常让人困惑,让我们通过一个例子来理解它们的区别:
html
<div class="container">
<h1>nth-child vs nth-of-type 例子</h1>
<p>这是第一个段落</p>
<div>这是一个div</div>
<p>这是第二个段落</p>
<p>这是第三个段落</p>
<div>这是第二个div</div>
</div>
css
/* 选择.container下第3个子元素,且这个元素必须是<p>标签 */
.container p:nth-child(3) {
background-color: yellow;
}
/* 实际不会生效,因为第3个子元素是div不是p */
/* 选择.container下第3个<p>类型的元素 */
.container p:nth-of-type(3) {
background-color: lightblue;
}
/* 这会选择"这是第三个段落" */
关键区别:
nth-child(n)
:选择父元素的第n个子元素,且必须是指定类型nth-of-type(n)
:选择父元素下第n个指定类型的子元素(忽略其他类型元素)

二、谈谈display的属性值
我们的详解会基于下面的表进行
display
属性值速查表
属性值 | 作用描述 | 示例代码 | 典型场景 |
---|---|---|---|
none |
完全隐藏元素,不占空间 | .hidden { display: none; } |
动态显示 / 隐藏元素 |
block |
块级元素,独占一行,支持宽高 | .block { display: block; width: 200px; } |
容器、段落、标题 |
inline |
行内元素,不换行,宽高由内容决定 | .inline { display: inline; } |
文本、链接、图片 |
inline-block |
不换行,但支持宽高 | .btn { display: inline-block; width: 100px; } |
水平按钮组、图标 |
table |
模拟表格布局 | .table { display: table; } |
数据表格、等高布局 |
table-cell |
模拟表格单元格,支持垂直居中 | .cell { display: table-cell; vertical-align: middle; } |
表单对齐、垂直居中 |
flex |
弹性布局,一维排列 | .flex { display: flex; justify-content: center; } |
导航栏、自适应卡片 |
grid |
网格布局,二维排列 | .grid { display: grid; grid-template-columns: repeat(3, 1fr); } |
图片画廊、响应式网格 |
一、基础布局属性值
1. display: none
-
作用:完全隐藏元素,不占用文档空间,脱离文档流。
-
示例:
xml<style> .hidden { display: none; } </style> <div>可见内容</div> <div class="hidden">隐藏内容</div> <!-- 完全消失 --> <div>可见内容</div>

2. display: block
-
作用:块级元素,独占一行,宽度默认为父元素的 100%,支持设置宽高。
-
示例:
xml<style> .block { display: block; width: 200px; height: 50px; background: lightblue; } </style> <div class="block">块级元素1</div> <div class="block">块级元素2</div> <!-- 自动换行 -->
-
常见元素 :
<div>
,<p>
,<h1>
,<ul>
等。

3. display: inline
-
作用:行内元素,不换行,宽度由内容决定,无法设置宽高。
-
示例:
xml<style> .inline { display: inline; background: lightgreen; width: 200px; /* 无效 */ } </style> <span class="inline">行内内容1</span> <span class="inline">行内内容2</span> <!-- 不换行 -->
-
限制 :垂直方向的
margin
和padding
无效,水平方向有效。 -
常见元素 :
<span>
,<a>
,<img>
等。

4. display: inline-block
-
作用 :行内块元素,不换行,但支持设置宽高,兼具
inline
和block
的特性。 -
示例:
xml<style> .inline-block { display: inline-block; width: 100px; height: 50px; background: lightcoral; } </style> <div class="inline-block">元素1</div> <div class="inline-block">元素2</div> <!-- 不换行 -->
-
应用场景:水平排列的按钮、图片画廊等。
-
二、表格布局属性值
5. display: table
-
作用 :将元素渲染为块级表格,需配合子元素的
table-row
和table-cell
。 -
示例:
xml<style> .table { display: table; } .row { display: table-row; } .cell { display: table-cell; border: 1px solid #ccc; } </style> <div class="table"> <div class="row"> <div class="cell">单元格1</div> <div class="cell">单元格2</div> </div> </div>
-
特性:自动应用表格的布局规则(如单元格等高)。

6. display: table-cell
-
作用:模拟表格单元格,常用于垂直居中。
-
示例:
xml<style> .container { display: table-cell; width: 200px; height: 100px; background: lightblue; vertical-align: middle; /* 垂直居中 */ text-align: center; /* 水平居中 */ } </style> <div class="container">居中内容</div>

三、弹性布局(Flexbox)
7. display: flex
-
作用:将元素转换为弹性容器,子元素成为弹性项目,支持灵活的对齐和分布。
-
示例:水平均匀分布三个按钮
xml<style> .flex-container { display: flex; justify-content: space-between; /* 均匀分布 */ } .btn { padding: 10px; background: lightgreen; } </style> <div class="flex-container"> <div class="btn">按钮1</div> <div class="btn">按钮2</div> <div class="btn">按钮3</div> </div>
-
常用属性 :
flex-direction
,justify-content
,align-items
,flex-wrap
等。

8. display: inline-flex
-
作用:弹性容器,但表现为内联元素,不独占一行。
-
示例:
xml<style> .inline-flex { display: inline-flex; background: lightyellow; } .item { width: 50px; height: 50px; background: lightcoral; } </style> <div class="inline-flex"> <div class="item">1</div> <div class="item">2</div> </div>

四、网格布局(Grid)
9. display: grid
-
作用:将元素转换为网格容器,子元素成为网格项目,支持二维布局。
-
示例:创建 3×3 网格
xml<style> .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); /* 3列,等宽 */ gap: 10px; } .grid-item { background: lightblue; padding: 20px; } </style> <div class="grid-container"> <div class="grid-item">1</div> <div class="grid-item">2</div> <div class="grid-item">3</div> <!-- 自动填充剩余网格 --> </div>

- 常用属性 :
grid-template-columns
,grid-template-rows
,gap
,place-items
等。
10. display: inline-grid
-
作用:网格容器,但表现为内联元素。
-
示例:
xml<style> .inline-grid { display: inline-grid; grid-template-columns: 50px 50px; gap: 5px; background: lightyellow; } </style> <div class="inline-grid"> <div>1</div> <div>2</div> </div>

三、block、inline和inline-block的区别
block(块级元素)
- 独占一行,前后会换行
- 可以设置宽度(width)、高度(height)、内外边距(margin/padding)
- 默认宽度为父元素的100%
- 常见块级元素:
<div>
,<p>
,<h1>-<h6>
,<ul>
,<ol>
,<li>
css
<div style="border: 2px solid blue; padding: 10px;">
这是一个块级元素
<p style="background: lightyellow;">块级元素内的段落</p>
</div>

inline(行内元素)
- 不会独占一行,与其他行内元素排列在同一行
- 设置宽度和高度无效
- 水平方向的内外边距有效,垂直方向的内外边距不会影响其他元素
- 默认宽度为内容宽度
- 常见行内元素:
<span>
,<a>
,<strong>
,<em>
,<img>
css
<p>
这是一段包含<span style="background: pink; padding: 0 10px;">行内元素</span>的文本,
<a href="#" style="color: red;">链接</a>也是行内元素。
</p>

inline-block(行内块元素)
- 结合了inline和block的特性
- 不会独占一行,与其他行内元素排列在同一行
- 可以设置宽度、高度、内外边距
- 默认宽度为内容宽度
css
<div style="background: #f0f0f0; padding: 10px;">
<span style="display: inline-block; width: 80px; height: 40px; background: lightgreen;">项目1</span>
<span style="display: inline-block; width: 80px; height: 60px; background: lightblue;">项目2</span>
<span style="display: inline-block; width: 80px; height: 50px; background: lightcoral;">项目3</span>
</div>

主要区别对比
特性 | block | inline | inline-block |
---|---|---|---|
是否换行 | 是 | 否 | 否 |
设置width/height | 有效 | 无效 | 有效 |
margin/padding | 全部有效 | 水平有效,垂直特殊 | 全部有效 |
默认宽度 | 父元素100% | 内容宽度 | 内容宽度 |
元素排列 | 垂直排列 | 水平排列 | 水平排列 |
包含关系 | 可包含其他块/行内 | 通常只含文本/行内 | 可包含其他块/行内 |
使用场景
- block:用于构建页面主要结构,如头部、导航、内容区域、页脚等
- inline:用于文本修饰或小图标等不需要设置宽高的元素
- inline-block:需要水平排列但又要设置宽高的元素,如导航菜单项、按钮组等
下面分别举一些例子来佐证
block
css
<!-- 页面头部 -->
<header style="display: block; background: #333; color: white; padding: 20px; text-align: center;">
<h1>网站标题</h1>
</header>
<!-- 导航栏 -->
<nav style="display: block; background: #444; padding: 10px;">
<ul style="margin: 0; padding: 0;">
<li style="display: inline-block; margin-right: 15px;"><a href="#" style="color: white;">首页</a></li>
<li style="display: inline-block; margin-right: 15px;"><a href="#" style="color: white;">产品</a></li>
<li style="display: inline-block;"><a href="#" style="color: white;">关于</a></li>
</ul>
</nav>
<!-- 内容区域 -->
<main style="display: block; padding: 20px; background: #f5f5f5;">
<p>这里是页面主要内容...</p>
</main>
<!-- 页脚 -->
<footer style="display: block; background: #333; color: white; text-align: center; padding: 10px;">
<p>© 2023 版权所有</p>
</footer>

inline
xml
<p>
这是一段包含 <strong style="display: inline; color: red;">强调文本</strong> 和
<a href="#" style="display: inline; text-decoration: underline;">超链接</a> 的段落。
</p>
<!-- 小图标(通过伪元素实现) -->
<style>
.icon::before {
content: "★";
display: inline;
color: gold;
margin-right: 5px;
}
</style>
<p><span class="icon">重要提示</span>:请阅读注意事项。</p>

inline-block
css
<!-- 导航菜单项 -->
<div style="background: #f0f0f0; padding: 10px;">
<a href="#" style="display: inline-block; width: 100px; height: 40px; line-height: 40px; text-align: center; background: #4CAF50; color: white; margin-right: 5px;">首页</a>
<a href="#" style="display: inline-block; width: 100px; height: 40px; line-height: 40px; text-align: center; background: #2196F3; color: white; margin-right: 5px;">产品</a>
<a href="#" style="display: inline-block; width: 100px; height: 40px; line-height: 40px; text-align: center; background: #FF9800; color: white;">关于</a>
</div>
<!-- 按钮组 -->
<div style="margin-top: 20px;">
<button style="display: inline-block; padding: 8px 16px; margin-right: 10px; background: #e0e0e0; border: none;">取消</button>
<button style="display: inline-block; padding: 8px 16px; background: #4CAF50; color: white; border: none;">确认</button>
</div>

四、说一说你知道的隐藏元素的方法
在前端开发中,隐藏元素是一个常见但需要谨慎处理的操作。不同的隐藏方法会导致不同的渲染表现、可访问性影响和性能开销。
一、完全移除型隐藏
1. display: none
- 彻底移除元素
css
.hide-element {
display: none;
}
核心特性:
- 元素不会出现在渲染树中
- 不占据任何文档流空间
- 所有子元素都会被连带隐藏
- 无法触发任何DOM事件
- 屏幕阅读器完全忽略该元素
- 触发浏览器重排(reflow)
性能影响:高(导致布局重新计算)
适用场景:
- 需要完全移除不需要的元素
- 标签页切换内容区域
- 响应式布局中在不同断点隐藏元素
示例:
html
<div class="tab-content" style="display: none;">
这个内容将在切换标签时显示
</div>
二、视觉隐藏但保留空间
2. visibility: hidden
- 隐形占位
css
.invisible {
visibility: hidden;
}
核心特性:
- 元素不可见但保留原有空间
- 无法触发鼠标等交互事件
- 只导致重绘(repaint),性能较好
- 可通过
visibility: visible
显示子元素 - 屏幕阅读器无法访问
性能影响:中等(仅重绘)
适用场景:
- 需要保留布局占位的隐藏
- 实现自定义复选框/单选框样式
- 需要保持布局稳定的场景
示例:
html
<div class="placeholder" style="visibility: hidden;">
这里的内容隐藏但仍占位
</div>
三、透明化隐藏
3. opacity: 0
- 完全透明
css
.transparent {
opacity: 0;
}
核心特性:
- 元素完全透明但占据空间
- 仍能触发所有DOM事件
- 会创建新的复合层,适合动画
- 屏幕阅读器可以访问
- 子元素无法单独恢复可见性
性能影响:低(GPU加速)
适用场景:
- 需要淡入淡出动画
- 需要隐藏但仍需交互的元素
- 可访问性要求高的内容
示例:
html
<button class="fade-button" style="opacity: 0;">
这个按钮透明但仍可点击
</button>
四、定位移出型隐藏
4. position: absolute
- 移出视口
css
.off-screen {
position: absolute;
left: -9999px;
top: -9999px;
}
核心特性:
- 视觉上不可见且不占空间
- 仍保留DOM位置和事件绑定
- 屏幕阅读器可以访问
- 不影响页面布局流
性能影响:高(导致重排)
适用场景:
- SEO优化需要隐藏但可抓取的内容
- 可访问性要求高的隐藏内容
- 需要隐藏但保留表单元素值
示例:
html
<label for="search" class="visually-hidden">搜索框</label>
<input type="text" id="search">
五、层叠隐藏
5. z-index: 负值
- 下层遮盖
css
.under-layer {
position: relative;
z-index: -1;
}
核心特性:
- 元素被其他层叠元素遮盖
- 仍占据原有文档流空间
- 事件触发取决于遮盖元素
- 屏幕阅读器可以访问
性能影响:低(复合层处理)
适用场景:
- 背景元素隐藏
- 特殊视觉效果实现
- 需要保留元素但置于底层的场景
示例:
html
<div class="background-element" style="z-index: -1;">
这个内容会被其他元素遮盖
</div>
六、裁剪型隐藏
6. clip/clip-path
- 元素裁剪
css
.clipped {
/* 传统clip方法(已废弃) */
clip: rect(0 0 0 0);
/* 现代clip-path方法 */
clip-path: circle(0);
}
核心特性:
- 视觉隐藏但保留元素空间
- 不响应交互事件
- 屏幕阅读器行为不一致
- 支持平滑动画过渡
性能影响:中等(GPU加速)
适用场景:
- 创意动画效果
- 渐进式内容展示
- 需要保留元素尺寸的隐藏
示例:
html
<div class="expandable" style="clip-path: inset(0 100% 0 0);">
这个内容可以通过动画展开
</div>
七、变形隐藏
7. transform: scale(0)
- 零尺寸缩放
css
.scaled-zero {
transform: scale(0);
}
核心特性:
- 元素视觉尺寸为零但保留布局空间
- 不响应交互事件
- 保持元素原本的盒模型特性
- 屏幕阅读器可以访问
- 支持平滑的缩放动画
性能影响:低(GPU加速)
适用场景:
- 需要缩放动画的元素
- 需要保留布局空间的隐藏
- 特殊交互效果的实现
示例:
html
<button class="zoom-button" style="transform: scale(0);">
点击后会放大显示
</button>
方法对比表
方法 | 占据空间 | 可交互性 | 可访问性 | 动画支持 | 性能影响 | SEO友好 |
---|---|---|---|---|---|---|
display: none |
❌ | ❌ | ❌ | ❌ | 高 | ❌ |
visibility: hidden |
✔️ | ❌ | ❌ | 有限 | 中 | ❌ |
opacity: 0 |
✔️ | ✔️ | ✔️ | ✔️ | 低 | ✔️ |
position: absolute |
❌ | ✔️ | ✔️ | ❌ | 高 | ✔️ |
z-index: 负值 |
✔️ | 可能 | ✔️ | ❌ | 低 | ✔️ |
clip-path |
✔️ | ❌ | 可能 | ✔️ | 中 | 可能 |
transform: scale(0) |
✔️ | ❌ | ✔️ | ✔️ | 低 | ✔️ |
选型建议
- 需要彻底移除元素:
- 首选:
display: none
- 场景:标签页切换、响应式布局隐藏
- 需要保留布局空间:
- 首选:
visibility: hidden
- 替代:
opacity: 0
(如需交互) - 场景:占位隐藏、自定义表单控件
- 需要动画效果:
- 淡入淡出:
opacity
- 缩放动画:
transform: scale()
- 裁剪动画:
clip-path
- 需要可访问性支持:
- 首选:
position: absolute
移出视口 - 替代:
opacity: 0
- 场景:屏幕阅读器可读的隐藏内容
- 需要SEO优化:
- 首选:
position: absolute
- 替代:
z-index
负值 - 场景:隐藏关键词但需要被搜索引擎抓取
在给面试官介绍这部分知识的时候,建议采用下面的步骤
首先分类概述8种方法(完全移除/视觉隐藏/特殊技巧三大类),然后逐类分析核心方法的特性、性能差异和应用场景,接着通过布局影响、交互性等维度系统对比,最后结合项目实战经验说明选型策略,并延伸提及现代CSS特性。这种回答既展现知识体系完整性,又体现技术决策的思考过程。
五、display:none与visibility:hidden有何区别
1. 两者差异
(1)渲染机制差异
-
display: none
浏览器会从 渲染树(Render Tree) 中完全移除该元素,后续布局计算时忽略其存在。
xml<div style="display: none;">Hidden</div> <!-- 等同于DOM中删除此元素 -->
-
visibility: hidden
元素仍保留在渲染树中,但会被标记为不可见(类似透明效果),浏览器仍会计算其布局。
xml<div style="visibility: hidden;">Invisible</div> <!-- 类似于设置透明度为0,但保留占位 -->
(2)性能影响
display: none
:触发 重排(Reflow) ,影响较大(尤其是频繁切换时)。visibility: hidden
:仅触发 重绘(Repaint) ,性能开销更小。
(3)子元素行为
visibility: hidden
会隐藏元素但保留占位,其子元素可通过 visibility: visible
重新显示;
display: none
会完全移除元素及其子元素,子元素无法通过 display: block
恢复显示。
css
<div style="visibility: hidden;">
<span style="visibility: visible;">我仍会显示!</span>
</div>
<div style="display: none;">
<span style="display: block;">我永远不会显示!</span>
</div>
2. 应用场景差异
何时用 display: none
?
- 需要 彻底移除元素(如标签页切换、响应式布局隐藏侧边栏)。
- 需要 减少DOM渲染压力(如长列表的懒加载)。
何时用 visibility: hidden
?
- 需要 保持布局稳定(如占位隐藏即将加载的内容)。
- 实现 自定义复选框/单选框 的视觉替换。
- 需要 保留元素状态(如表单隐藏字段仍需提交数据)。
3. 可以给面试官整点"夜宵"
(1)延伸问题(前文讲过)
- "如果希望隐藏元素但仍能被屏幕阅读器读取,你会怎么做?"
答:使用 绝对定位移出视口 或.visually-hidden
工具类(如Bootstrap的屏幕阅读器专用样式)。
(2)框架中的表现
- React 中
v-if
对应display: none
,v-show
对应visibility: hidden
。 - CSS动画 :
visibility
可配合transition
实现延迟隐藏(避免元素突然消失)
4. 核心区别总结
特性 | display: none | visibility: hidden |
---|---|---|
是否占据布局空间 | ❌ 完全移除,不占空间 | ✔️ 隐藏但保留原有空间 |
是否触发重排/重绘 | 触发重排 (Reflow) | 仅触发重绘 (Repaint) |
子元素是否可显示 | ❌ 子元素必然隐藏 | ✔️ 子元素可设 visibility: visible 单独显示 |
是否响应事件 | ❌ 无法触发任何事件 | ❌ 无法触发事件(但DOM仍存在) |
屏幕阅读器可访问性 | ❌ 完全忽略 | ❌ 无法访问 |
六、对盒模型的理解
盒模型是 CSS 布局的基础,描述了元素在页面中所占空间的计算方式。 每个元素都被视为一个矩形盒子,由四个主要部分组成:
一、盒模型的四个组成部分
1. 内容区(Content)
- 包含元素的实际内容(文本、图片等)。
- 由
width
和height
属性控制。
2. 内边距(Padding)
- 内容区与边框之间的距离。
- 由
padding-top
、padding-right
、padding-bottom
、padding-left
控制,也可简写为padding
。
3. 边框(Border)
- 围绕内边距和内容区的线条。
- 由
border-width
、border-style
、border-color
控制,也可简写为border
。
4. 外边距(Margin)
- 元素与其他元素之间的距离。
- 由
margin-top
、margin-right
、margin-bottom
、margin-left
控制,也可简写为margin
。
二、盒模型的宽度和高度计算
1. 标准盒模型(默认)
总宽度 = width
+ padding-left
+ padding-right
+ border-left-width
+ border-right-width
总高度 = height
+ padding-top
+ padding-bottom
+ border-top-width
+ border-bottom-width
示例:
css
div {
width: 200px; /* 内容区宽度 */
padding: 10px; /* 内边距:上下左右各10px */
border: 2px solid; /* 边框:2px宽 */
margin: 15px; /* 外边距:上下左右各15px */
}
总宽度 = 200 + 10×2 + 2×2 = 224px
总高度同理。
2. 怪异盒模型(IE 盒模型)
通过 box-sizing: border-box
设置。
总宽度 = width
(已包含 padding
和 border
)
总高度 = height
(已包含 padding
和 border
)
示例:
css
div {
width: 200px; /* 总宽度(包含padding和border) */
padding: 10px; /* 内边距:上下左右各10px */
border: 2px solid; /* 边框:2px宽 */
box-sizing: border-box; /* 使用怪异盒模型 */
}
总宽度 = 200px(内容区宽度 = 200 - 10×2 - 2×2 = 176px)
下面我们横向介绍一下标准盒模型(content-box)和IE盒模型(border-box)的不同
标准盒模型的宽度 / 高度仅包含内容区,而 IE 盒模型的宽度 / 高度包含内容区、内边距和边框。

三、盒模型的关键特性
1. 外边距合并(Margin Collapsing)
-
相邻元素的垂直外边距会合并为较大的一个。
-
示例:
css<div style="margin-bottom: 20px;">元素1</div> <div style="margin-top: 10px;">元素2</div>
元素 1 和元素 2 之间的实际间距为 20px(取较大值)。
2. 内边距和边框不影响元素的位置
- 增加内边距和边框会撑大元素,但不会改变其他元素的位置(除非超出父元素)。
3. 负外边距
- 可用于将元素拉向其他元素,例如:
margin-top: -10px
会使元素向上移动 10px。
四、最佳实践
1. 全局设置盒模型
css
* {
box-sizing: border-box;
}
这样可以避免因默认盒模型导致的宽度计算问题。
2. 合理使用内边距和外边距
- 内边距用于控制元素内部的空间。
- 外边距用于控制元素与其他元素之间的空间。
3. 避免外边距合并问题
- 使用
flex
或grid
布局,它们的子元素不会发生外边距合并。
五、盒模型可视化示例
xml
<style>
.box {
width: 200px;
height: 100px;
padding: 20px;
border: 5px solid #333;
margin: 30px;
background: lightblue;
}
</style>
<div class="box">内容区</div>

这个盒子的总尺寸计算:
- 宽度:200(内容) + 20×2(内边距) + 5×2(边框) = 250px
- 高度:100(内容) + 20×2(内边距) + 5×2(边框) = 150px
- 外边距(30px)会影响与其他元素的距离,但不包含在盒子自身尺寸内。
★★★ 建议在项目中统一使用 box-sizing: border-box
,以减少宽度计算的复杂性。
七、谈一谈CSS3的新特性
一、选择器增强
1. 属性选择器
-
作用:基于元素属性或属性值来选择元素。
-
示例:
css/* 选择所有title属性以"image"开头的元素 */ [title^="image"] { border: 1px solid red; } /* 选择所有href属性包含"example"的链接 */ a[href*="example"] { color: blue; } /* 选择所有data-type属性以"pdf"结尾的元素 */ [data-type$="pdf"] { background: #f0f0f0; }
2. 伪类选择器
-
作用:选择处于特定状态或位置的元素。
-
示例:
css/* 选择每个ul的第二个li */ li:nth-child(2) { font-weight: bold; } /* 选择每个section的第一个p */ p:first-of-type { color: #666; } /* 选择未被访问的链接 */ a:link { color: blue; } /* 选择鼠标悬停的按钮 */ button:hover { background: #e63946; }
3. 伪元素
-
作用:选择元素的特定部分或创建虚拟元素。
-
示例:
css/* 在每个blockquote前添加引号 */ blockquote::before { content: """; font-size: 2em; } /* 选中的文本变为红色背景 */ ::selection { background: red; color: white; } /* 首字母大写并设置特殊样式 */ p::first-letter { font-size: 200%; color: #e63946; }
二、盒模型相关
1. box-sizing 属性
-
作用:控制宽度和高度的计算方式。
-
示例:
css.standard-box { box-sizing: content-box; /* 默认值,宽度=内容区 */ width: 200px; padding: 20px; /* 总宽度=200+20*2=240px */ } .border-box { box-sizing: border-box; /* 宽度=内容区+padding+border */ width: 200px; padding: 20px; /* 内容区宽度=200-20*2=160px */ }
2. 多列布局
-
作用:将内容分成多列,类似报纸排版。
-
示例:
css.news-container { column-count: 3; /* 分成3列 */ column-gap: 20px; /* 列间距20px */ column-rule: 1px solid #ccc; /* 列分隔线 */ }
三、背景与边框
1. 背景增强
-
作用:提供更灵活的背景控制。
-
示例:
css.hero { background-image: url(bg.jpg); background-size: cover; /* 覆盖整个容器 */ background-position: center; /* 居中显示 */ background-repeat: no-repeat; background-attachment: fixed; /* 固定背景(滚动时不移动) */ } .gradient { background: linear-gradient(to right, #ff512f, #f09819); /* 线性渐变 */ }
2. 边框增强
-
作用:创建圆角、阴影和图片边框。
-
示例:
css.card { border-radius: 10px; /* 圆角 */ box-shadow: 0 4px 8px rgba(0,0,0,0.2); /* 阴影 */ } .fancy-border { border-image: url(border.png) 30 round; /* 图片边框 */ }
四、文本效果
1. 文本阴影
-
作用:为文本添加阴影效果。
-
示例:
cssh1 { text-shadow: 2px 2px 4px rgba(0,0,0,0.5); /* 水平偏移、垂直偏移、模糊半径、颜色 */ }
2. 文字溢出处理
-
作用:控制文本溢出容器时的显示方式。
-
示例:
css.truncate { white-space: nowrap; /* 不换行 */ overflow: hidden; /* 溢出隐藏 */ text-overflow: ellipsis; /* 显示省略号 */ }
3. 自定义字体
-
作用:引入非系统字体。
-
示例:
css@font-face { font-family: 'MyFont'; src: url('fonts/myfont.woff2') format('woff2'); font-weight: normal; font-style: normal; } body { font-family: 'MyFont', sans-serif; }
五、2D/3D 转换
1. 2D 转换
-
作用:对元素进行平移、旋转、缩放和倾斜。
-
示例:
css.box { transform: translate(50px, 20px); /* 平移 */ transform: rotate(45deg); /* 旋转 */ transform: scale(1.5); /* 缩放 */ transform: skew(20deg, 10deg); /* 倾斜 */ /* 组合转换 */ transform: translate(50px) rotate(30deg) scale(1.2); }
2. 3D 转换
-
作用:创建 3D 空间中的变换效果。
-
示例:
css.cube { transform: perspective(1000px) rotateY(45deg); /* 3D透视和旋转 */ transform-style: preserve-3d; /* 保留3D空间 */ } .card { transition: transform 0.5s; } .card:hover { transform: rotateY(180deg); /* 翻转动画 */ backface-visibility: hidden; /* 背面不可见 */ }
六、动画与过渡
1. 过渡(Transition)
-
作用:在两个状态之间平滑过渡。
-
示例:
css.button { background: blue; color: white; transition: background 0.3s ease, transform 0.3s ease; } .button:hover { background: red; transform: scale(1.1); }
2. 动画(Animation)
-
作用:创建复杂的多阶段动画。
-
示例:
css@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .element { animation: fadeIn 2s infinite alternate; /* 无限播放,交替反向 */ } @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } } .ball { animation: bounce 1s ease infinite; }
七、弹性布局(Flexbox)
-
作用:高效地布局、对齐和分配容器内的空间。
-
示例:
css.flex-container { display: flex; justify-content: space-between; /* 水平分布 */ align-items: center; /* 垂直居中 */ flex-wrap: wrap; /* 自动换行 */ } .flex-item { flex: 1; /* 平均分配空间 */ }
八、网格布局(Grid)
-
作用:创建二维网格布局。
-
示例:
css.grid-container { display: grid; grid-template-columns: repeat(3, 1fr); /* 3列等宽 */ grid-template-rows: auto 100px; /* 2行,第一行自动高度 */ gap: 20px; /* 行列间距 */ } .item1 { grid-column: 1 / 3; /* 跨越第1-2列 */ grid-row: 1; /* 位于第1行 */ }
九、媒体查询(Responsive Design)
-
作用:根据设备屏幕尺寸应用不同的样式。
-
示例:
css/* 大屏幕 */ .container { width: 80%; margin: 0 auto; } /* 小屏幕 */ @media (max-width: 768px) { .container { width: 100%; padding: 0 15px; } } /* 打印样式 */ @media print { body { font-size: 12pt; color: black; } }
十、其他特性
1. 滤镜(Filters)
-
作用:对元素应用视觉效果(模糊、亮度等)。
-
示例:
cssimg { filter: grayscale(100%); /* 灰度 */ filter: blur(5px); /* 模糊 */ filter: brightness(0.5); /* 亮度降低 */ } .hover-effect:hover { filter: contrast(150%); /* 增加对比度 */ }
2. 计算(calc ())
-
作用:动态计算 CSS 值。
-
示例:
css.sidebar { width: calc(25% - 20px); /* 宽度为父容器的25%减去20px */ } .full-height { height: calc(100vh - 80px); /* 高度为视口高度减去80px */ }
3. 多背景
-
作用:为元素应用多层背景。
-
示例:
css.element { background: url(top.png) top no-repeat, url(bottom.png) bottom no-repeat, linear-gradient(to bottom, #f0f0f0, #ccc); }
浏览器兼容性
大多数现代浏览器已全面支持上述特性,但部分旧版浏览器(如 IE)可能需要添加前缀或降级方案。建议使用工具如 Autoprefixer 自动处理前缀问题。
这些新特性让 CSS 从单纯的样式描述语言转变为强大的布局和动画工具,极大提升了前端开发的效率和网页的用户体验。
八、单行、多行内容的隐藏
一、单行文本溢出隐藏
核心属性 :
white-space: nowrap
+ overflow: hidden
+ text-overflow: ellipsis
示例代码:
css
.single-line {
white-space: nowrap; /* 强制不换行 */
overflow: hidden; /* 溢出内容隐藏 */
text-overflow: ellipsis; /* 显示省略号 */
width: 200px; /* 必须设置宽度 */
}
关键点:
- 容器需有固定宽度 (如
width
或max-width
) - 仅支持单行,无法处理多行文本
- 兼容性好(IE6+ 支持)
下面给大家一个小demo方便大家理解
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单行文本溢出示例</title>
<style>
.container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f9f9f9;
border-radius: 8px;
}
.demo-box {
margin: 20px 0;
}
.single-line {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 200px;
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
background-color: white;
}
.controls {
display: flex;
align-items: center;
gap: 10px;
margin-top: 15px;
}
input {
padding: 8px;
width: 80px;
border: 1px solid #ddd;
border-radius: 4px;
}
.code-block {
background-color: #333;
color: white;
padding: 15px;
border-radius: 4px;
font-family: monospace;
overflow-x: auto;
}
</style>
</head>
<body>
<div class="container">
<h2>单行文本溢出隐藏示例</h2>
<div class="demo-box">
<div class="single-line" id="demoText">
这是一段很长的文本内容,当宽度不足以显示全部内容时,会自动显示省略号...
</div>
<div class="controls">
<label for="widthInput">容器宽度 (px):</label>
<input type="number" id="widthInput" value="200" min="50" max="500">
<button onclick="updateWidth()">应用</button>
</div>
</div>
<div class="code-block">
<pre>
.single-line {
white-space: nowrap; /* 强制不换行 */
overflow: hidden; /* 溢出内容隐藏 */
text-overflow: ellipsis; /* 显示省略号 */
width: 200px; /* 必须设置宽度 */
}</pre>
</div>
</div>
<script>
function updateWidth() {
const width = document.getElementById('widthInput').value;
document.getElementById('demoText').style.width = `${width}px`;
}
</script>
</body>
</html>

二、多行文本溢出隐藏
方法 1:使用 -webkit-line-clamp
(推荐现代浏览器)
核心属性 :
display: -webkit-box
+ -webkit-line-clamp: 2
+ overflow: hidden
示例代码:
css
.multi-line {
display: -webkit-box; /* 必须 */
-webkit-box-orient: vertical; /* 必须 */
-webkit-line-clamp: 2; /* 显示的行数 */
overflow: hidden; /* 溢出隐藏 */
text-overflow: ellipsis; /* 省略号(可选) */
width: 200px; /* 容器宽度 */
}
关键点:
- 仅支持 webkit 内核浏览器(Chrome、Safari 等)
- 简单高效,推荐用于移动端
- 行数固定,无法根据内容动态调整
下面给大家一个小demo方便大家理解

方法 2:使用绝对定位 + 渐变遮罩(兼容所有浏览器)
原理 :
通过绝对定位覆盖一个带渐变的遮罩层,模拟省略号效果。
示例代码:
css
.multi-line-fallback {
position: relative;
line-height: 1.5em;
max-height: 3em; /* 显示的最大高度(行数×行高) */
overflow: hidden;
width: 200px;
}
.multi-line-fallback::after {
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding-left: 40px; /* 渐变区域宽度 */
background: linear-gradient(to right, transparent, white 70%);
}
关键点:
- 兼容性好(所有浏览器支持)
- 效果近似,但省略号位置可能不精确
- 需要手动计算高度(行数 × 行高)
下面给大家一个小demo方便大家理解
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多行文本溢出 - 渐变遮罩法</title>
<style>
.container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f9f9f9;
border-radius: 8px;
}
.demo-box {
margin: 20px 0;
}
.multi-line-mask {
position: relative;
line-height: 1.5em;
max-height: 4.5em; /* 默认3行 */
overflow: hidden;
width: 200px;
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
background-color: white;
}
.multi-line-mask::after {
content: "";
position: absolute;
bottom: 0;
right: 0;
width: 60px;
height: 1.5em;
background: linear-gradient(to right, transparent, white 80%);
}
.controls {
display: flex;
align-items: center;
gap: 10px;
margin-top: 15px;
}
input {
padding: 8px;
width: 50px;
border: 1px solid #ddd;
border-radius: 4px;
}
.code-block {
background-color: #333;
color: white;
padding: 15px;
border-radius: 4px;
font-family: monospace;
overflow-x: auto;
}
</style>
</head>
<body>
<div class="container">
<h2>多行文本溢出 - 渐变遮罩法</h2>

<div class="demo-box">
<div class="multi-line-mask" id="demoText">
这是一段多行文本内容,当超过容器高度时会通过渐变遮罩隐藏多余内容。这种方法兼容性好,但省略号位置可能不够精确。这是一段多行文本内容,当超过容器高度时会通过渐变遮罩隐藏多余内容。
</div>
<div class="controls">
<label for="linesInput">行数:</label>
<input type="number" id="linesInput" value="3" min="1" max="10">
<button onclick="updateLines()">应用</button>
</div>
</div>
<div class="code-block">
<pre>
.multi-line-mask {
position: relative;
line-height: 1.5em;
max-height: 4.5em; /* 3行 */
overflow: hidden;
}
.multi-line-mask::after {
content: "";
position: absolute;
bottom: 0;
right: 0;
width: 60px;
height: 1.5em;
background: linear-gradient(to right, transparent, white 80%);
}</pre>
</div>
</div>
<script>
function updateLines() {
const lines = document.getElementById('linesInput').value;
document.getElementById('demoText').style.maxHeight = `${lines * 1.5}em`;
}
</script>
</body>
</html>

方法 3:JavaScript 动态处理(最灵活)
原理 :
通过 JS 计算文本高度,超出时截断并添加省略号。
示例代码:
ini
function truncateText(element, maxLines) {
const lineHeight = parseInt(getComputedStyle(element).lineHeight);
const maxHeight = lineHeight * maxLines;
if (element.scrollHeight > maxHeight) {
element.style.overflow = 'hidden';
element.style.height = maxHeight + 'px';
// 添加省略号
const text = element.textContent;
while (element.scrollHeight > maxHeight) {
element.textContent = text.slice(0, -1);
}
element.textContent += '...';
}
}
// 使用方法
document.querySelectorAll('.truncate').forEach(el => {
truncateText(el, 3); // 限制3行
});
关键点:
- 完全自定义,可动态调整行数
- 性能开销较大,需遍历所有元素
- 适用于复杂场景(如响应式布局)
ini
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多行文本溢出 - JavaScript动态处理</title>
<style>
.container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f9f9f9;
border-radius: 8px;
}
.demo-box {
margin: 20px 0;
}
.multi-line-js {
line-height: 1.5em;
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
background-color: white;
}
.controls {
display: grid;
grid-template-columns: auto 1fr;
gap: 10px;
margin-top: 15px;
}
input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.code-block {
background-color: #333;
color: white;
padding: 15px;
border-radius: 4px;
font-family: monospace;
overflow-x: auto;
}
</style>
</head>
<body>
<div class="container">
<h2>多行文本溢出 - JavaScript动态处理</h2>
<div class="demo-box">
<div class="multi-line-js" id="demoText">
这是一段多行文本内容,使用JavaScript可以根据容器高度和行数限制动态截断文本并添加省略号。这种方法灵活性最高,适用于各种复杂场景,但需要注意性能开销。这是一段多行文本内容,使用JavaScript可以根据容器高度和行数限制动态截断文本并添加省略号。这种方法灵活性最高,适用于各种复杂场景,但需要注意性能开销。
</div>
<div class="controls">
<label for="linesInput">行数限制:</label>
<input type="number" id="linesInput" value="3" min="1" max="10">
<label for="widthInput">容器宽度 (px):</label>
<input type="number" id="widthInput" value="300" min="100" max="500">
<label for="customEllipsis">自定义省略号:</label>
<input type="text" id="customEllipsis" value="...">
</div>
<button onclick="applyTruncation()">应用设置</button>
</div>
<div class="code-block">
<pre>
function truncateText(element, maxLines, ellipsis = '...') {
const lineHeight = parseInt(getComputedStyle(element).lineHeight);
const maxHeight = lineHeight * maxLines;
// 保存原始内容
if (!element.dataset.originalText) {
element.dataset.originalText = element.textContent;
}
// 恢复原始内容再处理
element.textContent = element.dataset.originalText;
if (element.scrollHeight > maxHeight) {
element.style.overflow = 'hidden';
element.style.height = maxHeight + 'px';
// 截断文本
let text = element.textContent;
while (element.scrollHeight > maxHeight && text.length > 0) {
text = text.slice(0, -1);
element.textContent = text + ellipsis;
}
} else {
// 内容未超出,恢复完整显示
element.style.height = 'auto';
element.textContent = element.dataset.originalText;
}
}</pre>
</div>
</div>
<script>
function truncateText(element, maxLines, ellipsis = '...') {
const lineHeight = parseInt(getComputedStyle(element).lineHeight);
const maxHeight = lineHeight * maxLines;
// 保存原始内容
if (!element.dataset.originalText) {
element.dataset.originalText = element.textContent;
}
// 恢复原始内容再处理
element.textContent = element.dataset.originalText;
if (element.scrollHeight > maxHeight) {
element.style.overflow = 'hidden';
element.style.height = maxHeight + 'px';
// 截断文本
let text = element.textContent;
while (element.scrollHeight > maxHeight && text.length > 0) {
text = text.slice(0, -1);
element.textContent = text + ellipsis;
}
} else {
// 内容未超出,恢复完整显示
element.style.height = 'auto';
element.textContent = element.dataset.originalText;
}
}
function applyTruncation() {
const element = document.getElementById('demoText');
const lines = parseInt(document.getElementById('linesInput').value);
const width = document.getElementById('widthInput').value;
const ellipsis = document.getElementById('customEllipsis').value;
element.style.width = `${width}px`;
truncateText(element, lines, ellipsis);
}
// 初始化
applyTruncation();
</script>
</body>
</html>

三、面试回答总结
单行文本溢出 :
" 对于单行文本溢出,我会使用 white-space: nowrap
防止换行,配合 overflow: hidden
和 text-overflow: ellipsis
显示省略号。这种方法简单直接,兼容性好,但需要确保容器有固定宽度。"
多行文本溢出 :
" 对于多行文本溢出,有几种解决方案:
- 优先使用
-webkit-line-clamp
,它简单高效,但仅支持 webkit 内核浏览器。 - 对于兼容性要求高的场景,我会使用绝对定位 + 渐变遮罩的方式,通过 CSS 模拟省略号效果。
- 如果需要更灵活的控制(如动态调整行数),我会结合 JavaScript 计算文本高度并截断。"
补充说明 :
" 在实际项目中,我会根据业务需求选择方案。例如移动端可以优先使用 -webkit-line-clamp
,而 PC 端则考虑兼容性更好的方案。同时,我也会考虑性能因素,避免在大型列表中使用 JS 动态处理。"
九、手写两栏布局的实现
两栏布局是一种网页设计模式,将页面横向划分为两个主要区域,通常左侧为固定宽度(如导航、侧边栏),右侧为自适应宽度(如主内容区),通过浮动、Flexbox、Grid 等技术实现。
正如下面的效果

一、浮动(Float)布局
考虑到对Float布局不是很熟悉的各位,给各位推荐一个b站的视频,五分钟即可入门浮动 b23.tv/ucCTDAi
核心原理 :通过 float
属性使一侧元素浮动,另一侧自适应宽度。
这里注意,要给浮动元素预留空间,不要让主内容区的内容被浮动内容覆盖
示例代码:
xml
<style>
.container {
overflow: auto; /* 清除浮动 */
}
.sidebar {
float: left;
width: 30%;
}
.main {
margin-left: 30%; /* 为浮动元素留出空间 */
}
</style>
<div class="container">
<div class="sidebar">侧边栏</div>
<div class="main">主内容区</div>
</div>
仔细观察上述的代码,可以发现,浮动元素的宽度为(width: 30%;),而主内容区给浮动元素留的宽度也是(margin-left: 30%;),这也是前文提到的'要给浮动元素预留空间,不要让主内容区的内容被浮动内容覆盖'
优点 :兼容性好(IE6+)。
缺点 :需要清除浮动,容易出现高度塌陷问题。
适用场景:需要兼容旧浏览器的项目。
二、Flexbox 布局
核心原理 :使用 display: flex
实现弹性布局。
flex布局在这里的运用,主要是'弹性的'占据剩余区域,即flex: 1; 这样就可以实现两栏布局
示例代码:
xml
<style>
.container {
display: flex;
}
.sidebar {
width: 30%;
}
.main {
flex: 1; /* 占据剩余空间 */
}
</style>
<div class="container">
<div class="sidebar">侧边栏</div>
<div class="main">主内容区</div>
</div>
优点:
- 代码简洁,无需清除浮动
- 支持响应式调整
- 垂直居中简单(
align-items: center
)
缺点 :IE10+ 支持,旧浏览器不兼容。
适用场景:现代 Web 应用、移动端。
三、Grid 布局
核心原理 :使用 display: grid
创建二维网格。
示例代码:
xml
<style>
.container {
display: grid;
grid-template-columns: 30% 1fr; /* 两列布局 */
}
</style>
<div class="container">
<div class="sidebar">侧边栏</div>
<div class="main">主内容区</div>
</div>
优点:
-
语法最简洁
-
支持高级布局(如间距、自动填充)
-
响应式调整更灵活(
grid-template-columns
)
缺点 :IE 不支持,Chrome/Firefox/Safari 完全支持。
适用场景:现代 Web 应用、管理后台。
四、绝对定位(Absolute)布局
核心原理 :通过 position: absolute
固定一侧宽度,另一侧自适应。
示例代码:
xml
<style>
.container {
position: relative;
height: 100vh; /* 需要指定高度 */
}
.sidebar {
position: absolute;
left: 0;
width: 30%;
height: 100%;
}
.main {
margin-left: 30%;
height: 100%;
}
</style>
<div class="container">
<div class="sidebar">侧边栏</div>
<div class="main">主内容区</div>
</div>
优点 :布局稳定,不受内容影响。
缺点:
- 脱离文档流,可能影响其他元素
- 需要明确高度(如
height: 100%
)
适用场景:固定侧边栏的页面(如邮件客户端)。
五、表格布局(Table)
核心原理 :使用 display: table
和 table-cell
模拟表格。
示例代码:
xml
<style>
.container {
display: table;
width: 100%;
}
.sidebar, .main {
display: table-cell;
}
.sidebar {
width: 30%;
}
</style>
<div class="container">
<div class="sidebar">侧边栏</div>
<div class="main">主内容区</div>
</div>
优点:
- 单元格高度自动匹配
- 兼容性好(IE8+)
缺点:
- 语义不明确
- 灵活性差,难以实现复杂布局
适用场景:简单的两栏布局,需要等高效果。
六、响应式实现
★★★ 这里是和其他面试者拉开差距的关键
方法:结合媒体查询(Media Query)实现不同屏幕下的布局变化。
示例代码:
css
.container {
display: flex;
flex-direction: column; /* 移动端垂直排列 */
}
@media (min-width: 768px) {
.container {
flex-direction: row; /* 桌面端水平排列 */
}
.sidebar {
width: 30%;
}
.main {
flex: 1;
}
}
优点:
- 适配各种设备屏幕
- 移动端可优化为单列布局
适用场景:需要响应式设计的项目。
前三个实现方法是关键,是一定要记住的
面试回答总结
" 两栏布局的实现有多种方式,我会根据项目需求和兼容性要求选择合适的方案:
- 浮动布局 :适合需要兼容旧浏览器的场景,但需要处理清除浮动的问题。
- Flexbox :现代项目的首选,代码简洁且支持灵活的对齐和响应式调整。
- Grid :最强大的布局方式,特别适合复杂的二维布局,但兼容性稍差。
- 绝对定位:适合固定侧边栏的场景,但会脱离文档流。
- 表格布局:兼容性好,但语义不明确,灵活性较低。
在实际项目中,我会优先使用 Flexbox 或 Grid,并结合媒体查询实现响应式设计。例如,在移动端将两栏布局转为单列,提升用户体验。"
十、手写三栏布局的实现
三栏布局是前端开发里较为常见的页面结构,它主要包含左、中、右三个部分。
正如下面的实现

三栏布局稍微比两栏布局复杂一点点,如果看不懂,我推荐一个B站视频 b23.tv/9mLcRjd
浮动实现
左右两栏分别向左/右浮动脱离文档流,中间栏通过外边距(margin)避开浮动元素,形成三栏布局。
xml
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
padding: 0;
}
.container {
width: 100%;
}
.left {
float: left;
width: 200px;
background-color: #f2f2f2;
height: 300px;
}
.right {
float: right;
width: 200px;
background-color: #f2f2f2;
height: 300px;
}
.main {
margin-left: 210px; /* 大于左侧栏宽度 */
margin-right: 210px; /* 大于右侧栏宽度 */
background-color: #ccc;
height: 300px;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
</style>
</head>
<body>
<div class="container clearfix">
<div class="left">左侧栏</div>
<div class="right">右侧栏</div>
<div class="main">主要内容</div>
</div>
</body>
</html>

Flexbox 实现
此方法利用 Flexbox 的弹性布局能力,能很方便地对列宽和对齐方式进行控制。
xml
<style>
.container {
display: flex;
}
.left, .right {
width: 200px;
background: #f0f0f0;
}
.center {
flex: 1;
background: #e0e0e0;
}
</style>
<div class="container">
<div class="left">左列</div>
<div class="center">中间列</div>
<div class="right">右列</div>
</div>
Grid 实现
Grid 布局是专门为二维布局设计的,能够简洁地实现复杂的网格结构。
xml
<style>
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
}
.left, .right {
background: #f0f0f0;
}
.center {
background: #e0e0e0;
}
</style>
<div class="container">
<div class="left">左列</div>
<div class="center">中间列</div>
<div class="right">右列</div>
</div>
表格布局实现
该方法把容器当作表格,各列当作表格单元格来进行布局。
xml
<style>
.container {
display: table;
width: 100%;
}
.left, .right, .center {
display: table-cell;
}
.left, .right {
width: 200px;
background: #f0f0f0;
}
.center {
background: #e0e0e0;
}
</style>
<div class="container">
<div class="left">左列</div>
<div class="center">中间列</div>
<div class="right">右列</div>
</div>
绝对定位实现
这种方法通过绝对定位来固定左右两列的位置,中间列则利用边距来留出空间。
xml
<style>
.container {
position: relative;
height: 200px;
}
.left, .right {
position: absolute;
top: 0;
width: 200px;
background: #f0f0f0;
}
.left {
left: 0;
}
.right {
right: 0;
}
.center {
margin: 0 200px;
background: #e0e0e0;
height: 100%;
}
</style>
<div class="container">
<div class="left">左列</div>
<div class="center">中间列</div>
<div class="right">右列</div>
</div>
下面的圣杯布局实现和双飞翼布局实现以及被现代技术淘汰,但是对于面试来说,还是有学习的必要的
圣杯布局实现
圣杯布局的特点是中间列优先加载,并且左右两列宽度固定。
通过 浮动 + 负边距(margin-left: -100%
) + 相对定位(position: relative
)让左右栏"挤"到中间栏两侧,并用父容器的 padding
预留空间
xml
<style>
.container {
padding: 0 200px;
}
.columns {
display: flex;
}
.center {
flex: 1;
order: 2;
background: #e0e0e0;
}
.left {
width: 200px;
order: 1;
margin-left: -100%;
position: relative;
right: 200px;
background: #f0f0f0;
}
.right {
width: 200px;
order: 3;
margin-right: -200px;
background: #f0f0f0;
}
</style>
<div class="container">
<div class="columns">
<div class="center">中间列</div>
<div class="left">左列</div>
<div class="right">右列</div>
</div>
</div>
双飞翼布局实现
中间栏嵌套一层 div
,用其 margin
预留左右空间,左右栏仅靠浮动 + 负边距(margin-left
)定位,无需相对定位,简化实现。
xml
<style>
.container {
overflow: hidden;
}
.center {
float: left;
width: 100%;
background: #e0e0e0;
}
.center-inner {
margin: 0 200px;
}
.left, .right {
float: left;
width: 200px;
background: #f0f0f0;
}
.left {
margin-left: -100%;
}
.right {
margin-left: -200px;
}
</style>
<div class="container">
<div class="center">
<div class="center-inner">中间列</div>
</div>
<div class="left">左列</div>
<div class="right">右列</div>
</div>
响应式三栏布局实现
这种布局会依据屏幕尺寸自动调整为适合移动端的单列布局。
xml
<style>
.container {
display: flex;
flex-wrap: wrap;
}
.left, .right, .center {
width: 100%;
}
@media (min-width: 768px) {
.left, .right {
width: 200px;
}
.center {
flex: 1;
}
}
</style>
<div class="container">
<div class="left">左列</div>
<div class="center">中间列</div>
<div class="right">右列</div>
</div>
在实际的项目开发中,建议优先考虑使用 Flexbox 或者 Grid 布局,因为它们的代码更简洁,也更容易维护。要是需要兼容旧版本的浏览器,浮动布局或者表格布局也是不错的选择。而圣杯布局和双飞翼布局则适用于需要中间列优先加载的特殊场景。
十一、水平垂直居中的实现方法
1. 行内元素 / 文本居中(单行)
通过将容器的 line-height
值设置为与容器高度相等,使单行文本在垂直方向上自动居中。同时使用 text-align: center
实现水平居中。
xml
<style>
.center {
height: 100px;
line-height: 100px; /* 高度等于行高 */
text-align: center; /* 水平居中 */
border: 1px solid #ccc;
}
</style>
<div class="center">单行文本居中</div>
2. 行内元素 / 文本居中(多行)
将容器设置为 display: table-cell
,模拟表格单元格的行为。利用 vertical-align: middle
实现垂直居中,配合 text-align: center
实现水平居中。
xml
<style>
.center {
display: table-cell;
width: 200px;
height: 200px;
text-align: center; /* 水平居中 */
vertical-align: middle; /* 垂直居中 */
border: 1px solid #ccc;
}
</style>
<div class="center">多行文本居中示例<br>第二行文本</div>
3. 块级元素居中(已知宽高)
父元素设置 position: relative
作为定位参考。子元素使用 position: absolute
配合 top: 50%
和 left: 50%
将左上角定位到父元素中心。通过 margin-top
和 margin-left
的负值(各为元素宽高的一半)将元素向上和向左偏移,实现完全居中。
xml
<style>
.container {
position: relative;
height: 300px;
border: 1px solid #ccc;
}
.center {
position: absolute;
top: 50%; /* 顶部偏移50% */
left: 50%; /* 左侧偏移50% */
width: 200px;
height: 100px;
margin-top: -50px; /* 高度的负一半 */
margin-left: -100px; /* 宽度的负一半 */
background: #f0f0f0;
}
</style>
<div class="container">
<div class="center">块级元素居中</div>
</div>
★★★ 4. 块级元素居中(未知宽高)
父元素设置 position: relative
。子元素使用 position: absolute
和 top: 50%
, left: 50%
定位到父元素中心。通过 transform: translate(-50%, -50%)
动态将元素自身向上和向左偏移其宽度和高度的 50%,无需知道具体尺寸。
xml
<style>
.container {
position: relative;
height: 300px;
border: 1px solid #ccc;
}
.center {
position: absolute;
top: 50%; /* 顶部偏移50% */
left: 50%; /* 左侧偏移50% */
transform: translate(-50%, -50%); /* 利用transform调整 */
background: #f0f0f0;
}
</style>
<div class="container">
<div class="center">未知宽高元素居中</div>
</div>
5. Flexbox 居中(现代方案)
父元素设置 display: flex
或 display: inline-flex
。使用 justify-content: center
实现水平居中,align-items: center
实现垂直居中。
优势:代码简洁,支持响应式布局,是现代前端开发的首选方案。
xml
<style>
.container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 300px;
border: 1px solid #ccc;
}
.center {
background: #f0f0f0;
padding: 20px;
}
</style>
<div class="container">
<div class="center">Flexbox居中</div>
</div>
6. Grid 居中(现代方案)
父元素设置 display: grid
或 display: inline-grid
。使用 place-items: center
同时实现水平和垂直居中(等同于 justify-items: center
和 align-items: center
的组合)。
xml
<style>
.container {
display: grid;
place-items: center; /* 水平和垂直同时居中 */
height: 300px;
border: 1px solid #ccc;
}
.center {
background: #f0f0f0;
padding: 20px;
}
</style>
<div class="container">
<div class="center">Grid居中</div>
</div>
7. 绝对定位 + 弹性布局混合方案
父元素设置 position: relative
。子元素使用 position: absolute
和 inset: 0
(等同于 top: 0; right: 0; bottom: 0; left: 0
)将元素扩展至父元素边界。通过 margin: auto
使浏览器自动计算并分配上下左右的边距,实现居中。
限制:需明确设置子元素的宽高,否则会填满父容器。
xml
<style>
.container {
position: relative;
height: 300px;
border: 1px solid #ccc;
}
.center {
position: absolute;
inset: 0; /* 等同于top:0;right:0;bottom:0;left:0; */
margin: auto; /* 自动计算边距 */
width: 200px;
height: 100px;
background: #f0f0f0;
}
</style>
<div class="container">
<div class="center">绝对定位+弹性布局居中</div>
</div>
十二、谈一谈你对Flex的理解
这里给大家贴一篇我之前写过的文章掌握Flex布局:面向小白的Flex全面教程 - 掘金
Flexbox(Flexible Box Layout)是 CSS3 引入的一维布局模型,旨在为容器内的子元素提供弹性的空间分配和对齐方式。它的核心思想是让容器能够自动调整子元素的宽度、高度和排列顺序,以适应不同的屏幕尺寸和设备类型。
一、核心概念
-
Flex 容器(Flex Container)
应用
display: flex
或display: inline-flex
的父元素,它定义了一个 Flex 布局的作用域。 -
Flex 项目(Flex Items)
容器内的直接子元素,它们会被 Flex 布局所控制。
-
主轴(Main Axis)和交叉轴(Cross Axis)
- 主轴:由
flex-direction
定义的方向,默认为水平从左到右。 - 交叉轴:垂直于主轴的方向,默认是垂直方向。
- 主轴:由
二、容器属性(控制整体布局)
1. flex-direction
:定义主轴方向
sql
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
- row(默认):水平从左到右。
- row-reverse:水平从右到左。
- column:垂直从上到下。
- column-reverse:垂直从下到上。
2. flex-wrap
:控制换行
lua
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
- nowrap(默认):不换行,元素可能溢出。
- wrap:换行,新行位于下方。
- wrap-reverse:换行,新行位于上方。
3. flex-flow
:flex-direction
和 flex-wrap
的简写
css
.container {
flex-flow: row wrap; /* 常用组合 */
}
4. justify-content
:主轴对齐方式
sql
.container {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
- flex-start(默认):元素靠主轴起点。
- flex-end:元素靠主轴终点。
- center:元素居中。
- space-between:两端对齐,间距平均分配。
- space-around:每个元素两侧间距相等(边缘间距为中间间距的一半)。
- space-evenly:所有间距完全相等。
5. align-items
:交叉轴对齐方式
css
.container {
align-items: stretch | flex-start | flex-end | center | baseline;
}
- stretch(默认):元素拉伸填充容器高度 / 宽度。
- flex-start:靠交叉轴起点。
- flex-end:靠交叉轴终点。
- center:居中。
- baseline:元素基线对齐。
6. align-content
:多行对齐方式(当存在换行时生效)
sql
.container {
align-content: stretch | flex-start | flex-end | center | space-between | space-around;
}
三、项目属性(控制单个元素)
1. order
:定义元素排列顺序
css
.item {
order: 0; /* 默认值,数值越小越靠前 */
}
2. flex-grow
:定义元素的扩展比例
css
.item {
flex-grow: 1; /* 默认0,不扩展;值为1时平均分配剩余空间 */
}
3. flex-shrink
:定义元素的收缩比例
css
.item {
flex-shrink: 1; /* 默认1,空间不足时等比例收缩;设为0则不收缩 */
}
4. flex-basis
:定义元素在分配空间前的初始大小
css
.item {
flex-basis: auto | 200px; /* 默认auto,使用元素自身宽度/高度 */
}
5. flex
:flex-grow
, flex-shrink
, flex-basis
的简写
css
.item {
flex: 1 1 auto; /* 默认值 */
flex: 1; /* 等同于 flex: 1 1 0 */
}
6. align-self
:单独定义元素的交叉轴对齐方式
arduino
.item {
align-self: auto | flex-start | flex-end | center | stretch;
}
四、你什么时候会使用Flex布局?
-
导航栏
- 水平排列菜单项,支持响应式折叠。
- 使用
justify-content: space-between
实现左右对齐。
-
卡片布局
- 等高卡片自动适应容器宽度。
- 使用
flex-wrap: wrap
和justify-content: center
实现卡片自动换行和居中。
-
垂直居中
- 使用
align-items: center
和justify-content: center
快速实现元素的水平垂直居中。
- 使用
-
自适应侧边栏
- 主内容区域自动扩展,侧边栏固定宽度。
- 使用
flex: 1
让主内容占满剩余空间。
-
响应式表单
- 标签和输入框在小屏幕上垂直排列,大屏幕上水平排列。
- 使用
flex-direction: column
和媒体查询实现。
-
底部固定页脚
- 当内容不足时,页脚固定在底部;内容充足时,页脚随内容滚动。
- 使用
min-height: 100vh
和flex-direction: column
实现。
五、Flex的优缺点对比
优点
- 简洁灵活:大幅减少浮动和定位的使用,代码更简洁。
- 响应式友好:天然支持根据容器尺寸动态调整元素。
- 对齐能力强:轻松实现水平和垂直居中、等间距分布。
- 顺序灵活 :通过
order
属性可随意改变元素显示顺序。
缺点
- 兼容性问题:IE10 及以下不支持,需提供降级方案。
- 二维布局能力有限:对于复杂的网格布局,Grid 更合适。
在向面试官介绍时,一定要介绍flex布局出现的原因,flex的关键参数,flex何时使用以及优缺点
十三、你是否理解BFC,在实际项目中如何运用(不是KFC)
BFC(Block Formatting Context,块级格式化上下文) 是CSS中的一个重要概念,它是页面上的一个独立的渲染区域,规定了内部的块级盒子如何布局,并且与外部区域互不影响。BFC可以看作是一个隔离的容器,容器内的元素布局不会影响到外部的元素。
BFC的特性(可以想象html的特性,因为html也是一个BFC):
- 内部盒子垂直排列:BFC内的块级盒子会按照垂直方向一个接一个地放置。
- 外边距折叠(Margin Collapse) :属于同一个BFC的两个相邻块级盒子的上下外边距会发生重叠。
- 独立布局:BFC的区域不会与浮动元素重叠,且可以包含浮动元素。
- 隔离性:BFC内的元素不会影响外部的元素,反之亦然。
如何创建BFC
可以通过以下CSS属性或条件触发BFC的创建:
- 根元素(
<html>
) :整个页面默认是一个BFC。 - 浮动元素 :元素的
float
值不为none
(如float: left
或float: right
)。 - 绝对定位元素 :元素的
position
为absolute
或fixed
。 display: inline-block
:设置为inline-block
的元素。display: table-cell
或table-caption
:表格单元格或表格标题。overflow
不为visible
:如overflow: hidden
、auto
、scroll
。display: flow-root
:专门用于创建BFC的属性(现代浏览器支持,无副作用)。- Flex或Grid的直接子项 :
display: flex
或display: grid
的容器的直接子元素。
常见应用场景
-
清除浮动:父元素创建BFC后可以包含浮动子元素(避免高度塌陷)。
css.parent { overflow: hidden; /* 触发BFC */ }
-
避免外边距折叠:将相邻元素放入不同的BFC中。
xml<div class="bfc"> <p>第一个段落</p> </div> <div class="bfc"> <p>第二个段落</p> </div>
css.bfc { overflow: hidden; /* 创建BFC */ }
-
阻止元素被浮动元素覆盖:非浮动元素通过BFC与浮动元素分栏。
css.content { overflow: hidden; /* 创建BFC,避免与浮动元素重叠 */ }
在你对实际运用中,一般是如何创建BFC的?
-
使用
display: flow-root
创建BFC,因为它无副作用(不会隐藏内容或产生滚动条)。css.container { display: flow-root; }
十四、清除浮动的原因?如何清除?
清除浮动是 CSS 布局中的重要概念,主要用于解决浮动元素导致的父元素高度塌陷问题。
一、为什么需要清除浮动?
当子元素设置 float: left/right
后,会脱离正常的文档流,导致父元素无法计算其高度,出现高度塌陷(父元素高度为 0)。这会影响布局的正常显示,例如:
- 父元素无法包裹浮动的子元素
- 后续元素可能会与浮动元素重叠
- 背景和边框无法正确显示
示例问题代码:
xml
<style>
.parent {
border: 1px solid red;
}
.child {
float: left;
width: 100px;
height: 100px;
background: #f0f0f0;
}
</style>
<div class="parent">
<div class="child"></div>
</div>
<!-- 父元素高度为0,边框无法包裹浮动子元素 -->

这里父元素并不能包含子元素,因为子元素浮动,而且父元素本身的大小比子元素小(或者没有大小)导致父元素高度塌陷(原本应该由子元素的大小撑开)
有的读者可能会思考------我将父元素的大小设置的比子元素大不就行了吗?
但是在实际的项目中子元素的大小很多情况下是不能确定的,所有清除浮动就很有必要
二、清除浮动的常见方式
1. 使用 clear
属性(传统方法)
在浮动元素后添加一个空元素,并设置 clear: both
。
xml
<style>
.parent {
border: 1px solid #ccc;
}
.float {
float: left;
}
.clear {
clear: both;
}
</style>
<div class="parent">
<div class="float">浮动元素</div>
<div class="clear"></div> <!-- 清除浮动 -->
</div>
缺点:需要额外的 HTML 元素,增加冗余代码。
2. BFC(块级格式化上下文)
通过触发父元素的 BFC 来包含浮动元素。常见方式:
css
.parent {
overflow: hidden; /* 触发BFC */
}
原理:BFC 会包含内部所有浮动元素,计算高度时会考虑浮动子元素。
3. 伪元素清除法(推荐)
使用 ::after
伪元素在父元素末尾插入一个清除浮动的元素。
css
.parent::after {
content: "";
display: block;
clear: both;
}
4. 浮动父元素本身
将父元素也设置为浮动:
css
.parent {
float: left; /* 触发BFC */
}
缺点:可能影响后续元素布局,需要再次清除浮动。
5. 设置父元素为表格单元格
css
.parent {
display: table-cell;
}
缺点:可能影响宽度和布局特性。
三、各方法对比
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
空元素 + clear | 兼容性好 | 增加 HTML 冗余 | 兼容老旧浏览器 |
overflow:hidden | 代码简单 | 内容溢出会被隐藏 | 内容不会溢出的容器 |
display:flow-root | 专门为清除浮动设计 | IE 不支持 | 现代浏览器环境 |
伪元素清除法 | 无冗余 HTML,兼容性好 | 需要额外 CSS 类 | 大多数场景推荐使用 |
浮动父元素 | 简单直接 | 影响后续布局 | 临时解决方案 |
四、现代替代方案
在 Flexbox 和 Grid 布局中,浮动的使用场景大幅减少,因为它们会自动包含子元素,无需清除浮动:
css
.parent {
display: flex; /* Flex布局 */
/* 或 display: grid; */
}
清除浮动的核心目标是让父元素正确包含浮动的子元素,避免高度塌陷。在现代前端开发中,优先使用伪元素清除法或BFC 触发,并尽量用 Flexbox/Grid 替代浮动布局,以减少布局复杂度。
十五、position的属性有哪些,区别是什么
推荐一个position的讲解视频 b23.tv/wwag429
CSS 中的position
属性用于控制元素在文档中的定位方式,共有五种主要取值:static
、relative
、absolute
、fixed
和sticky
。
一、position: static
(默认值)
-
特性 :元素按照正常的文档流布局,
top
、right
、bottom
、left
和z-index
属性无效。 -
示例:
arduino.element { position: static; /* 默认值,无需显式声明 */ }
-
应用场景:大多数普通元素默认使用静态定位。
二、position: relative
(相对定位)
-
特性:
- 元素先按照正常文档流布局,然后相对于其正常位置进行偏移。
- 偏移不会影响其他元素的布局(其他元素仍视为该元素在原位)。
- 可通过
top
、right
、bottom
、left
调整位置。 - 会创建新的层叠上下文(stacking context)。
-
示例:
css.element { position: relative; top: 10px; /* 向下偏移10px */ left: 20px; /* 向右偏移20px */ }
-
应用场景 :作为绝对定位元素的容器(父元素设置
relative
)。
为了方便大家了解relative,我提供一个实例,大家可以复制运行
各位,这里不能给实例了,超出最大字符限制了,下面是演示实例,大家凑合看吧

三、position: absolute
(绝对定位)
-
特性:
- 元素脱离正常文档流,不再占据空间。
- 相对于最近的已定位祖先元素 (即
position
值为relative
、absolute
、fixed
或sticky
的元素)定位。 - 若无已定位祖先元素,则相对于初始包含块(通常是浏览器视口)。
- 可通过
top
、right
、bottom
、left
精确控制位置。
-
示例:
css.parent { position: relative; /* 作为参考容器 */ } .child { position: absolute; top: 0; right: 0; /* 定位到父元素右上角 */ }
-
应用场景:悬浮菜单、弹出框、绝对定位的图标等。
再给大家提供一个实例,可以复制运行
各位,这里不能给实例了,超出最大字符限制了,下面是演示实例,大家凑合看吧

四、position: fixed
(固定定位)
-
特性:
- 元素脱离文档流,相对于浏览器视口固定位置。
- 滚动页面时,元素位置保持不变。
- 常用于创建导航栏、返回顶部按钮等。
-
示例:
css.navbar { position: fixed; top: 0; left: 0; width: 100%; /* 固定在顶部的导航栏 */ }
-
应用场景:固定导航、悬浮广告、模态框遮罩层。
五、position: sticky
(粘性定位)
-
特性:
- 混合了
relative
和fixed
的特性,初始时按正常文档流布局。 - 当滚动到特定位置时(通过
top
、right
、bottom
、left
指定阈值),变为相对于视口固定。 - 必须指定至少一个偏移值(如
top: 0
)才能生效。
- 混合了
-
示例:
css.sidebar { position: sticky; top: 20px; /* 滚动到距离视口顶部20px时固定 */ }
-
应用场景:滚动时固定的侧边栏、标题栏。
六、关键区别对比表
属性值 | 定位参考对象 | 是否脱离文档流 | 滚动时表现 |
---|---|---|---|
static |
正常文档流 | 否 | 随文档滚动 |
relative |
元素自身正常位置 | 否 | 随文档滚动 |
absolute |
最近的已定位祖先元素 | 是 | 随祖先元素滚动(若祖先固定则不动) |
fixed |
浏览器视口 | 是 | 固定不动 |
sticky |
正常文档流(滚动到阈值后固定) | 否 | 初始滚动,达到阈值后固定 |
十六、实现一个三角形
这一题看似是考察我们使用css画图的能力,但是实时却不是这样,这题考察的是css中的border特性
在 CSS 中实现三角形主要基于边框(border)的特性。当元素的宽度和高度为 0 时,其边框会被相邻边框均分,形成一个由边框组成的多边形。通过调整边框的宽度和颜色,可以轻松创建各种三角形。
一、实现原理
边框的本质
每个元素的边框实际上是由四个梯形组成的,当元素宽度和高度为 0 时,梯形退化为三角形。
二、实现代码
1. 向上的三角形
xml
<style>
.triangle-up {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red; /* 底边显示颜色 */
}
</style>
<div class="triangle-up"></div>

2. 向下的三角形
xml
<style>
.triangle-down {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-top: 100px solid blue; /* 顶边显示颜色 */
}
</style>
<div class="triangle-down"></div>

3. 向左的三角形
xml
<style>
.triangle-left {
width: 0;
height: 0;
border-top: 50px solid transparent;
border-bottom: 50px solid transparent;
border-right: 100px solid green; /* 右边显示颜色 */
}
</style>
<div class="triangle-left"></div>

4. 向右的三角形
xml
<style>
.triangle-right {
width: 0;
height: 0;
border-top: 50px solid transparent;
border-bottom: 50px solid transparent;
border-left: 100px solid purple; /* 左边显示颜色 */
}
</style>
<div class="triangle-right"></div>

5. 任意角度的三角形
通过调整各边的宽度比例,可以创建不同角度的三角形:
xml
<style>
.triangle-custom {
width: 0;
height: 0;
border-left: 30px solid transparent;
border-right: 70px solid transparent;
border-bottom: 100px solid orange;
}
</style>
<div class="triangle-custom"></div>

最后给大家说明一下代码中可能困惑的地方
transparent是使不需要的边框透明,只有需要显示的边框我们才设置颜色
十七、如何解决1px 问题?
为何会产生1px问题?何为1px问题?
首先我们要明确三个概念,一个使逻辑像素,一个是物理像素,还有一个设备像素比(DPR)
- CSS 像素(逻辑像素)
前端开发中使用的单位(如1px
),是抽象的逻辑单位,用于描述元素的尺寸和位置。 - 物理像素
设备屏幕实际的物理显示单元,例如 iPhone 13 的分辨率为 2532×1170 像素。 - 设备像素比(DPR)
DPR = 物理像素 / CSS像素
- 普通屏幕:DPR = 1,1 个 CSS 像素对应 1 个物理像素。
- Retina 屏:DPR = 2 或 3,1 个 CSS 像素对应 4 个(2×2)或 9 个(3×3)物理像素。
由此我们可以得出当 CSS 中设置border: 1px
时:
- 在 DPR=1 的屏幕上,显示为 1 个物理像素宽。
- 在 DPR=2 的屏幕上,实际渲染为 2 个物理像素宽,视觉上变粗(例如 iOS 设备)。
- 在 DPR=3 的屏幕上,渲染为 3 个物理像素宽,更粗(例如部分 Android 设备)。
现在我们可以区解决1px问题了
1. 媒体查询 + transform 缩放(推荐)
通过检测设备像素比(DPR),使用伪元素和缩放创建精确的 1px 边框。
css
.border {
position: relative;
}
/* 1倍屏 */
@media (-webkit-min-device-pixel-ratio: 1), (min-device-pixel-ratio: 1) {
.border::after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
background: #000;
}
}
/* 2倍屏 */
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
.border::after {
transform: scaleY(0.5);
transform-origin: 0 0;
}
}
/* 3倍屏 */
@media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
.border::after {
transform: scaleY(0.333);
transform-origin: 0 0;
}
}
优点 :精确控制物理像素,兼容性好(IE9+)。
缺点:代码量较大,需为每个方向的边框单独设置。
2. viewport 缩放(整页解决方案)
根据设备像素比动态调整 viewport 的缩放比例:
ini
const scale = 1 / window.devicePixelRatio;
document.write(`<meta name="viewport" content="width=device-width, initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no">`);
优点 :一劳永逸,所有 1px 问题自动解决。
缺点:需配合 rem/em 布局,可能影响第三方组件。
3. box-shadow 模拟边框
利用阴影的扩散特性模拟极细边框:
css
.border {
box-shadow: 0 0 0 1px #000; /* 1px边框 */
}
优点 :代码简单,兼容性好。
缺点:阴影可能模糊,无法精确控制单边。
4. SVG 边框(现代方案)
使用内联 SVG 定义精确的 1px 边框:
ini
.border {
border: 1px solid transparent;
background-origin: border-box;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1' height='1'%3E%3Crect x='0' y='0' width='1' height='1' fill='%23000'/%3E%3C/svg%3E");
}
优点 :精确控制物理像素,支持各种形状。
缺点:代码复杂,IE 不支持。
5. CSS 渐变(适合单边边框)
使用线性渐变创建精确的 1px 线条:
css
.border-bottom {
background: linear-gradient(to bottom, #000, #000 1px, transparent 1px) no-repeat;
background-size: 100% 1px;
background-position: bottom;
}
优点 :简单灵活,兼容性好。
缺点:只能模拟单边边框。
三、各方案对比
方法 | 优点 | 缺点 | 兼容性 |
---|---|---|---|
transform 缩放 | 精确控制,支持圆角 | 代码复杂,需多方向处理 | 现代浏览器 |
viewport 缩放 | 全局生效,简单直接 | 影响整体布局 | 所有浏览器 |
box-shadow | 实现简单 | 效果模糊,不支持圆角 | 所有浏览器 |
SVG 边框 | 精确控制,支持复杂形状 | 代码复杂 | IE 不支持 |
CSS 渐变 | 简单灵活 | 只能单边,不支持圆角 | 现代浏览器 |
那么这些方案有没有什么弊端?
- 圆角问题:transform 缩放方案可能导致圆角在某些浏览器中显示不流畅。
- 性能影响:大量使用伪元素或 transform 可能影响渲染性能。
- 混合方案:复杂项目中可能需要结合多种方案(如 viewport 缩放 + 局部 transform)。
优先考虑 viewport 缩放或 transform 缩放方案。
相信大家看到这里的时候还是会有一些疑问的,诸如------
1.1px问题只会影响到边框的设置吗,不会影响字体等其他的效果吗 2.只有1px时会出现这种问题吗?2px时会有给个问题吗?
下面回答一下这些疑问
1. 关于1px问题的影响范围
1px问题主要影响边框、细线和微小UI元素,但基本不影响字体。这是因为:
- 边框/线条是纯色块渲染,高DPR下1CSS像素直接映射为多个物理像素时,浏览器无法智能优化,导致过粗或模糊;
- 字体则自带抗锯齿和次像素渲染技术,操作系统和浏览器会动态调整显示方式,确保在不同DPI下保持视觉一致性。不过,极端情况下(如极小字号或1px文字描边)仍可能受影响。
2. 关于2px是否会出现类似问题
2px不会出现典型的"1px问题" ,原因在于:
- 物理像素对齐:2px的宽度足够大,在高DPR设备(如DPR=2)下会直接渲染为4物理像素,浏览器不会触发抗锯齿优化,显示清晰且稳定;
- 视觉容忍度:即使DPR=3时2px变为6物理像素,其粗细变化是线性且可预测的,而1px的细微偏差(如虚边或半像素渲染)更容易被察觉。因此,只有1px会因渲染策略不一致引发显著问题,2px及以上则无此困扰。
结语
CSS面试上篇就截取到这里了,上篇的考点是比较高频的考点。
CSS面试下篇也会尽快发出来