Skip to content

第 02 章 · CSS 面试题集


Q1:CSS 盒模型有哪两种?区别是什么?

考察点:盒模型、box-sizing

标准答案: CSS 盒模型分两种:

  1. content-box(W3C 标准盒模型,默认):width / height 只算 content;元素实际占位 = width + padding + border
  2. border-box(IE 盒模型 / 怪异盒模型):width / height 包含 content + padding + border;元素实际占位 = width

通过 box-sizing 切换,现代项目几乎都用 border-box

css
*, *::before, *::after { box-sizing: border-box; }

通俗理解

  • content-box:你说"我要 200 平米的房子",结果墙体厚度另算,实际占地 220 平。
  • border-box:你说"占地 200 平",墙、保温层都包在 200 平里——所见即所得。

代码示例

css
.a { width: 200px; padding: 20px; border: 5px solid; }      /* 实际宽 250px */
.b { width: 200px; padding: 20px; border: 5px solid;
     box-sizing: border-box; }                               /* 实际宽 200px */

加分回答

  • 早期 IE6 用的就是 border-box,后来"反水"跟 W3C 走了 content-box,现代项目又集体回到 border-box——历史轮回。
  • 第三方组件库经常带自己的 box-sizing,引入时检查冲突。
  • outline 不计入任何盒模型尺寸,所以画聚焦圈用 outline 不会撑大布局。

追问

  • margin 是盒模型的一部分吗?(是,最外层)
  • 行内元素的盒模型有什么不同?(margin/padding 上下不影响布局)

Q2:CSS 选择器优先级(权重)怎么算?

考察点:层叠、优先级

标准答案: 权重用 4 元组表示 (a, b, c, d),从高到低:

权重来源
a行内 style="..."
bid 选择器(#xxx)数量
cclass、属性、伪类数量
d标签、伪元素数量

比较时逐位对比,左边大的就赢。!important 高于一切(除了同样 important 时按上面规则比)。通配符 * 和组合符 > + ~ 不计权重。

通俗理解: 就像比职位高低——总裁(a)→部长(b)→经理(c)→员工(d)。10 个员工也比不过 1 个经理。

代码示例

css
#nav .item a:hover     { color: red;   }   /* (0,1,2,1) */
.menu .list .link      { color: blue;  }   /* (0,0,3,0) */
/* 红色赢,因为有一个 id */

加分回答

  • :not(.x) 本身不计权重,但括号里的选择器计权重。
  • :where(...) 权重永远是 0,常用于 reset。
  • :is(.a, #b) 取括号内最高权重那个。
  • 同权重时,后写的覆盖先写的
  • 避免 id 和 !important,多用 class,方便后期重写。

追问

  • !important 之间冲突怎么办?(按权重 + 顺序)
  • 行内 style 能被覆盖吗?(用 !important 可以)

Q3:水平垂直居中有哪几种实现方式?

考察点:布局功底

标准答案: 按推荐度排序:

css
/* 1. Flex(最推荐) */
.parent { display: flex; justify-content: center; align-items: center; }

/* 2. Grid(更短) */
.parent { display: grid; place-items: center; }

/* 3. 绝对定位 + transform(无需知道宽高) */
.parent { position: relative; }
.child  { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }

/* 4. 绝对定位 + margin: auto(需要 inset 全 0) */
.child  { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }

/* 5. 行内元素居中:text-align + line-height */
.parent { text-align: center; line-height: 200px; }  /* 父高度等于 line-height */

通俗理解: 往一个空盒子的正中间贴一张贴纸——Flex 是"自动定位贴纸机",transform 是"先贴左上 50% 再回退自身一半"。

代码示例

html
<div class="parent" style="display:flex;justify-content:center;align-items:center;height:200px;background:#eee">
  <div style="background:#2563eb;color:#fff;padding:8px 16px">居中元素</div>
</div>

加分回答

  • Flex 方案最简单且兼容好;Grid 的 place-itemsalign-items + justify-items 的简写。
  • transform 方案适合不知道子元素宽高的场景(如动态内容、文本行数不定)。
  • 老项目还能见到 display: table-cell + vertical-align: middle
  • 文本垂直居中可以用 line-height 等于容器高度,但只适合单行文本。

追问

  • align-itemsalign-content 区别?
  • 为什么 vertical-align: middle 不能让 div 垂直居中?(仅对 inline / table-cell 生效)

Q4:position 的几种值有什么区别?

考察点:定位机制

标准答案

脱离文档流参照物典型用途
static默认值
relative自己原位置微调 / 给子绝对定位当地基
absolute最近的非 static 祖先弹窗、tooltip、角标
fixed浏览器视口回到顶部按钮、导航栏
sticky否(特殊)最近的滚动祖先表格表头、章节标题吸顶

通俗理解

  • relative:站在原位喊"我可以挪 5 步"——别人还是按你原来位置排队。
  • absolute:飞起来贴在墙上——别人当你不存在。
  • fixed:贴在车窗上——车开它不动。
  • sticky:滚着滚着粘住——之后跟着滚条不动。

代码示例

css
.tooltip-wrapper { position: relative; }
.tooltip {
  position: absolute;
  top: 100%; left: 0;
  background: #333; color: #fff; padding: 4px 8px;
}
.back-to-top {
  position: fixed;
  bottom: 20px; right: 20px;
}
.section-title {
  position: sticky; top: 0;
  background: #fff;
}

加分回答

  • absolute / fixed 元素如果没设 width,会收缩到内容宽度
  • sticky 父元素必须有滚动且不能 overflow: hidden,否则失效。
  • position 改变会创建新的 包含块层叠上下文
  • 设了 transform / filter 的元素会成为其后代 fixed 的"伪 viewport"——这是常见 bug。

追问

  • z-index 在哪些 position 下生效?(除 static 外)
  • 层叠上下文(stacking context)是什么?

Q5:Flex 布局的核心属性都有哪些?

考察点:Flex 布局

标准答案

容器属性(写在父元素上):

  • display: flex / inline-flex — 启用
  • flex-direction: row / column — 主轴方向
  • flex-wrap: nowrap / wrap — 是否换行
  • justify-content — 主轴对齐:flex-start / center / flex-end / space-between / space-around / space-evenly
  • align-items — 交叉轴对齐:stretch / center / flex-start / flex-end / baseline
  • align-content — 多行的交叉轴对齐
  • gap — 子项间距

子项属性

  • flex-grow — 剩余空间分配比例(默认 0)
  • flex-shrink — 空间不够时缩小比例(默认 1)
  • flex-basis — 初始大小
  • flex — 简写,常用 flex: 1
  • align-self — 单独覆盖父级 align-items
  • order — 排序

通俗理解: Flex 就是让父元素当"队长",子元素自动排队。父元素发命令"横排还是竖排","间距怎么留","宽度不够要不要缩"。

代码示例

css
.nav {
  display: flex;
  justify-content: space-between;  /* 两端对齐 */
  align-items: center;              /* 垂直居中 */
}
.layout {
  display: flex;
  gap: 16px;
}
.layout > .side { width: 200px; }
.layout > .main { flex: 1; }   /* 占满剩余 */

加分回答

  • flex: 1flex: 1 1 0,从 0 开始等比生长,所有子项等宽
  • flex: autoflex: 1 1 auto,从内容宽度开始生长,内容多的更宽。
  • flex: noneflex: 0 0 auto完全不伸缩
  • 主轴方向决定 justify-content 作用方向,flex-direction: column 时它管"上下"。
  • IE10/11 的 flex 实现有 bug,老项目要小心。

追问

  • Flex 与 Grid 区别?
  • align-itemsalign-content 区别?

Q6:Grid 和 Flex 有什么区别?什么时候用哪个?

考察点:布局方案选型

标准答案

维度FlexGrid
维度一维(行 或 列)二维(行 + 列)
思维内容驱动(先有子元素再排布)容器驱动(先画格子再放)
适用导航栏、按钮组、单行/单列对齐整页布局、卡片网格、复杂表单
居中难度justify-content + align-itemsplace-items: center
浏览器支持极好(IE10+)现代浏览器(IE11 部分支持)

经验法则

  • 整体布局用 Grid(页面分区、卡片墙)。
  • 组件内部用 Flex(按钮内的图标+文字、卡片内部排列)。
  • 两者可以嵌套:grid 容器里的某个格子又是 flex 容器。

通俗理解

  • Flex 像排队——一队人按顺序站成一行 / 一列。
  • Grid 像棋盘——格子先画好,棋子各自往格子里放。

代码示例

css
/* Grid 整页布局 */
.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header header"
    "side   main"
    "footer footer";
}

/* 某个格子内部用 Flex */
.page > header {
  grid-area: header;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

加分回答

  • Grid 的 repeat(auto-fill, minmax(200px, 1fr)) 一行实现"自适应卡片墙",是 Flex 做不到的。
  • Grid 的 gap 早于 Flex 的 gap(Flex 的 gap 是后期加的,Safari 14.1 才支持)。
  • Grid 支持显式区域命名grid-template-areas),可读性极强。

追问

  • grid-auto-flow 是干嘛的?
  • fr 单位是什么?

Q7:CSS 中 emrem 区别?

考察点:相对单位

标准答案

单位参照累积效应
em当前元素的 font-size(继承自父级)嵌套时会层层累积
rem根元素 html 的 font-size全局统一,不累积

通俗理解

  • em 像"按当前部门标准"——你部门规定 14px,你的 1em 就是 14px;你下级部门加倍,下下级再加倍——传染病一样累积。
  • rem 像"按公司总部标准"——不管嵌套多深,都参照公司总部那一个数字,调一处全局变。

代码示例

css
html { font-size: 16px; }

/* em 累积示例 */
.a { font-size: 1.5em; }   /* 16 × 1.5 = 24px */
.a .b { font-size: 1.5em; } /* 24 × 1.5 = 36px ⚠️ */

/* rem 不累积 */
.x { font-size: 1.5rem; }   /* 24px */
.x .y { font-size: 1.5rem; } /* 还是 24px */

加分回答

  • 设字号大小用 rem,方便用户在浏览器调整字号(无障碍)。
  • 设 padding/margin 等"和字号相关的间距"用 em(按钮内边距随按钮字号变化)。
  • 移动端"全站缩放"套路:JS 监听 resize,动态改 html { font-size },全站 rem 自动跟随。
  • 不要用 px 写正文字号——用户在系统里调大字号会失效。

追问

  • vw vh 是什么?
  • 100vh 在手机上为什么会有问题?(地址栏遮挡,新提案 dvh / svh / lvh

Q8:CSS 动画 transition 和 animation 区别?

考察点:动画 API

标准答案

维度transitionanimation
触发状态变化(hover、class 切换)自动执行
关键帧只有起止两点可定义多个百分比节点
循环不能循环infinite 无限循环
复杂度简单复杂
暂停不可animation-play-state: paused

通俗理解

  • transition 像自动门:人靠近 → 开;人走远 → 关。只有"开"和"关"两态。
  • animation 像预先编排好的舞蹈:从第 1 拍 → 第 2 拍 → ... → 第 8 拍,可以反复跳。

代码示例

css
/* transition:hover 时背景变色,抬升 */
.btn {
  background: #2563eb;
  transition: background 0.3s, transform 0.2s;
}
.btn:hover {
  background: #1d4ed8;
  transform: translateY(-2px);
}

/* animation:心跳效果,无限循环 */
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.1); }
}
.heart { animation: heartbeat 1s infinite; }

加分回答

  • transition 必须有状态变化才会触发;display: noneblock 是无法过渡的(值不连续)。
  • 现代用 @starting-style 可以让 display: none → block 动起来。
  • 优先用 transformopacity 做动画——它们走 GPU 合成,60fps 不卡;width / left / top 会触发重排,卡顿。
  • will-change: transform 提示浏览器提前准备 GPU 层(不要滥用,会占内存)。
  • prefers-reduced-motion 媒体查询可以为有前庭障碍的用户关掉动画(无障碍)。

追问

  • transition: all 有什么问题?(无差别监听所有属性,性能差)
  • 为什么 transformtop 性能好?

Q9:什么是 BFC?怎么触发?

考察点:CSS 渲染机制

标准答案BFC(Block Formatting Context,块级格式化上下文)是 CSS 的一种独立渲染区域,内部元素的布局不会影响外部,外部也不影响内部。

触发方式

  • float 不为 none
  • overflow 不为 visible(hidden / auto / scroll
  • display: inline-block / flex / grid / flow-root
  • position: absolute / fixed

作用(解决问题):

  1. 清除浮动:包含浮动子元素,撑开父容器高度。
  2. 避免 margin 折叠:BFC 内的元素和外部不会发生上下 margin 合并。
  3. 阻止文字环绕浮动元素

通俗理解: BFC 像一个独立隔间——里面发生的事情(margin 折叠、浮动溢出),不会影响隔间外的人;反之亦然。

代码示例

css
/* 父元素包含浮动子元素,需要撑开高度 */
.parent {
  overflow: hidden;       /* 触发 BFC,包含浮动 */
  /* 或 display: flow-root(更现代、副作用最小) */
}
.child { float: left; width: 100px; height: 100px; }

加分回答

  • display: flow-root 是 BFC 的"专用"触发方式,没有 overflow: hidden 的副作用(如裁剪阴影)。
  • BFC 内部的盒子按文档流垂直堆叠。
  • 实际项目里,flex / grid 已经是 BFC,所以"清除浮动"问题大幅减少。
  • 还有 IFC(行内格式化上下文)、GFC(grid)、FFC(flex)等概念。

追问

  • 有了 flex 和 grid 还需要 float 吗?(基本不用了)
  • BFC、IFC、FFC 区别?

Q10:响应式设计有哪些常用手段?

考察点:响应式 / 自适应

标准答案

  1. viewport meta:移动端必备。

    html
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  2. 媒体查询 @media:按屏宽切换样式。

    css
    @media (min-width: 768px) { /* 平板及以上 */ }
  3. 流式布局:用 %frflex 让宽度弹性。

    css
    .container { width: 90%; max-width: 1200px; }
  4. rem / vw 字号缩放

    css
    html { font-size: clamp(14px, 2vw, 18px); }
  5. 响应式图片<picture> + srcset + sizes

    html
    <img srcset="small.jpg 480w, big.jpg 1200w" sizes="(min-width: 768px) 1200px, 100vw" />
  6. CSS Grid 自适应

    css
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  7. clamp() 函数:一行实现"最小-理想-最大"。

    css
    font-size: clamp(14px, 4vw, 24px);
  8. 容器查询(新):根据父容器宽度而非视口。

    css
    @container (min-width: 400px) { .card { display: flex; } }

通俗理解: 响应式 = 一份代码,让网页在不同屏幕上自己变形——就像变形金刚。

代码示例

css
/* 移动优先 */
.container { padding: 12px; }
.card-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }

@media (min-width: 768px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .card-grid { grid-template-columns: repeat(3, 1fr); }
}

加分回答

  • "响应式"和"自适应"严格说不一样:响应式是连续变化(流式),自适应是几个固定断点切换。
  • 移动优先(mobile-first)比桌面优先更推荐:用 min-width 渐进增强。
  • 别只测断点边缘——测中间宽度(770px)和极端宽度(320px、1920px)。
  • prefers-color-scheme 实现暗黑模式响应。

追问

  • vw 在 iframe 里是什么?
  • 如何处理高分屏(Retina)图片?