拓冰建站拓冰建站
首页 / 资讯中心 / 正文

CSS面试高频考点全梳理:从盒模型到原子化CSS

最近帮团队做前端面试前后筛了几十份简历发现一个挺有意思的现象很多候选人项目经历写得花里胡哨但一问到CSS基础翻车的比例相当高。不是不会用而是说不清楚原理。Flex能调布局却讲不明白flex: 1到底是什么意思会用position: absolute但说不清它相对谁定位能写出display: grid但问到grid-template-columns和grid-template-rows配合使用时就开始含糊。这其实就是典型的“八股文”没背透。做前端这几年我越来越觉得CSS基础不是背题而是建立一套“浏览器怎么理解样式”的思维模型。这篇内容我梳理了2024年面试里最常碰到的CSS考点从盒模型、Flex、Grid到选择器优先级、定位与层叠上下文再到底部安全区适配、样式穿透、原子化CSS这类工程化话题把高频考点和容易踩的坑串起来。内容定位是“基础篇”适合正在准备前端面试的人也适合写了好几年业务代码但想回头夯实基础的朋友。1. 盒模型CSS布局的第一道坎盒模型是CSS里最基础也最容易忽略的知识点。面试的时候我一般会先问候选人“一个div的宽度设成200px加了padding和border之后它在页面上实际占多宽”别小看这个问题能准确答上来的人真不多。1.1 标准盒模型与怪异盒模型的区别标准盒模型W3C盒模型里width指的是内容区content的宽度padding和border都在这个宽度之外额外增加。怪异盒模型IE盒模型里width指的是内容区 padding border的总宽度。这是两者最核心的区别。用代码举个例子.box { width: 200px; padding: 20px; border: 1px solid #000; }标准盒模型下这个div实际占用的宽度是200 20*2 1*2 242px。怪异盒模型下实际占用就是200px内容区被压缩到了200 - 42 158px。这里有一个实操中的痛点用标准盒模型做响应式布局时改padding会撑破父容器。比如父容器宽度是50%子元素设了width: 50%再加padding就很容易溢出。这也是为什么我几乎在所有项目里都会先加这样一条全局样式*, *::before, *::after { box-sizing: border-box; }border-box就是怪异盒模型。全局开启之后写布局的时候不用反复计算宽度padding和border都从width里面“扣”心智负担小很多。1.2 box-sizing的选择与实战经验面试时还有一道变种题“box-sizing: border-box和content-box分别在什么场景下用”很多人只会背结论说不出选择依据。我自己的经验是常规业务页面、组件库开发默认用border-box原因上面说了省心。某些需要精确计算内容区宽度的场景比如富文本编辑器里的图片自适应、Canvas画布大小同步用content-box反而更容易控制。还有一个小细节box-sizing是可继承吗答案是不可继承。所以要么在*上统一设置要么在公共类里显式声明否则子元素会回到默认的content-box。注意项目里如果用了第三方组件库比如Ant Design、Element Plus有的组件内部会单独设置box-sizing接手老项目时不要想当然地全局改容易引起样式错乱。稳妥做法是在组件外层包一个容器在容器上单独控制。2. Flex布局面试必考的现代布局方案Flex布局现在是CSS面试的“必考题”基本没有哪场面试会绕过它。之所以大家爱问是因为Flex的语法不算难但很多细节一旦追问就露馅。2.1 Flex的两条轴与核心属性先理清楚一个基础概念Flex布局有两根轴主轴main axis和交叉轴cross axis。flex-direction决定主轴方向row表示水平方向column表示垂直方向。主轴的方向变了justify-content和align-items的效果也会跟着变。核心属性分成两组容器上的属性display: flex、flex-direction、justify-content、align-items、flex-wrap、align-content、gap。项目上的属性flex-grow、flex-shrink、flex-basis、align-self、order。面试里问得最多的是“justify-content: center和align-items: center一个是水平居中一个是垂直居中吗”这是个经典陷阱。准确说法是justify-content控制主轴方向上的对齐align-items控制交叉轴方向上的对齐。默认情况下主轴是水平所以大家会直接说“水平居中、垂直居中”。但如果flex-direction: column主轴变成垂直justify-content: center就变成垂直居中了这时候align-items才是水平居中。2.2 justify-content与align-items的常见面试追问光知道“主轴交叉轴”还不够面试官经常会继续追问gap、align-content这些属性。gap是2021年后全面支持的一个属性用来设置Flex项目之间的间距以前只能用margin实现现在直接gap: 12px就行。align-content这个属性很多人会忽略。它跟align-items的区别是align-content控制的是多行项目在交叉轴上的排列方式作用于“行”这个整体align-items控制的是单行内项目的对齐。可以这样理解align-content管“行和行之间的间距与分布”align-items管“行里面每个项目怎么摆放”。如果只有一行项目align-content不生效。实操心得Flex做“垂直水平居中”是最常见的需求但要注意子项在容器里内容超长时的表现。只写display: flex; justify-content: center; align-items: center;如果子项文字太多可能会被压缩得很丑。稳妥做法是给子项加上min-width: 0或flex-wrap: wrap让内容有换行或收缩的空间。2.3 flex: 1 到底是什么意思这个知识点面试出现频率极高但能完整讲明白的人不多。flex: 1其实是三个属性的简写flex-grow: 1; flex-shrink: 1; flex-basis: 0%;。拆开解释一下flex-grow剩余空间怎么分。默认0表示不放大。设为1表示把剩余空间按比例分给这个项目。flex-shrink空间不够时怎么缩。默认1表示空间不够会收缩。设为0表示即使空间不够也不收缩。flex-basis项目在分配剩余空间之前的“初始尺寸”。默认auto表示取项目的宽高。设成0表示不考虑项目自身的内容宽度完全平均分配。面试里经常出这样一道题三个item宽度默认是100px分别设置flex: 1、flex: 1、flex: 2容器宽度是600px问每个item最终多宽答案是三个item先把100px拿掉剩余300px按1:1:2分配分别多50、50、100所以最终是150、150、200加起来刚好600。这种计算题看着简单但面试官要的就是你能不能逻辑清晰地推导出来。3. Grid布局二维布局的降维打击Grid布局这两年问得越来越多尤其是做中后台系统、大屏可视化项目的候选人简历里都会写Grid。面试官通常会把Grid和Flex放在一起问两者到底什么区别什么时候用哪个3.1 Grid与Flex的核心区别一句话总结Flex是一维布局Grid是二维布局。Flex关注的是“一维方向上的排列”主轴处理好交叉轴只是辅助对齐Grid则是把容器划分成行和列组成的网格你可以同时控制项目在行和列两个维度上的位置。举个例子要把12个卡片排成3列4行用Flex需要写flex-wrap: wrap然后手动计算每个卡片的宽度比如width: calc((100% - 40px) / 3)用Grid就非常简单.container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }1fr是Grid特有的单位意思是“可用空间的一份”。repeat(3, 1fr)表示生成3列等宽的轨道。如果改成repeat(4, 1fr)就变成4列不需要动任何子元素样式。这就是二维布局的优势。3.2 实际面试里的Grid高频考点Grid里有一个细节容易被忽略grid-template-columns: repeat(3, 1fr)和grid-template-columns: 1fr 1fr 1fr等价吗这两者效果上确实一样的但repeat()更适合表达“重复N次”的语义还在配合auto-fill、minmax时更好用。比如.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }这行代码的意思是自动填充尽可能多的列每列最小200px最大占据剩余空间。这是做响应式卡片列表的常用手法——容器宽度变化时卡片数量自动加减无需写媒体查询。面试时能说出这种写法通常是加分的。还有一道常见的题Grid项目怎么跨列、跨行用grid-column: span 2或grid-row: span 2。这个属性在复杂报表布局里很实用。避坑提示Grid的fr单位不能和固定宽度直接混用而不加思考。比如grid-template-columns: 1fr 200px那么200px先被拿走剩余空间才属于1fr那一列。想清楚了这一点混合布局才不会翻车。4. 选择器与优先级CSS的裁判规则前面聊的布局都建立在“样式能生效”的前提下。但CSS里经常会遇到样式覆盖不掉、不生效的情况追根溯源就是选择器优先级问题。4.1 选择器分类与优先级计算方式CSS选择器可以分成几大类id选择器、类选择器、属性选择器、伪类选择器、标签选择器、伪元素选择器、通配符选择器。优先级从高到低大致是!important最高级慎用内联样式style属性id选择器类选择器、属性选择器、伪类选择器标签选择器、伪元素选择器通配符、继承样式面试时候的标准答法是“千分位计算”(a, b, c)a代表id选择器数量b代表类选择器和属性选择器数量c代表标签选择器数量。比如#app .header .nav a的优先级就是(1, 2, 1)。实际项目里最常踩的坑是过度嵌套导致优先级失控。比如写#main .container .wrap .content .title后来想在别的地方用一个title类覆盖就得写一长串选择器才能压住。这也是为什么很多团队坚持“类选择器为主id选择器只用来挂载根节点”。4.2 样式覆盖的常见误区和排查思路样式不生效的排查思路我一般按照下面这个顺序选择器优先级够不够是不是被!important压住了样式被内联style覆盖了样式写在的媒体查询条件没满足元素本身有没有display/visibility影响渲染面试题里喜欢问“那我加!important行不行”行但不推荐。!important是九阴真经练了能打人但反噬也大。它会让修改成本急剧上升一旦被塞进线上代码后面的人只能用更高的!important去覆盖最后代码变成一团乱麻。我处理线上样式冲突的做法是先看有没有class写错再看优先级最后才考虑!important。实操心得如果你在调试工具里改样式不生效优先怀疑优先级而不是属性写错。用Chrome的Computed面板看一下实际生效的规则来源比凭空猜测高效得多。4.3 BEM命名规范与样式隔离除了优先级计算面试里也会问到工程化层面的样式管理你怎么保证样式不互相污染常见的方案有BEM、CSS Modules、CSS-in-JS。BEM是Class命名规范全称是Block块、Element元素、Modifier修饰符。比如一个按钮组件命名为.btn它里面的图标叫.btn__icon主色调叫.btn--primary。核心思想是用一个扁平、语义化的类名表达结构避免深层嵌套。为什么BEM能减少样式冲突因为它要求类名全局唯一同类名的概率低。缺点也很明显类名长写起来啰嗦。现在的工程化方案里不少人直接用CSS Modules或者Vue的scoped效果也差不多。面试里能把BEM的优劣说清楚比单纯背名字印象分高。5. 定位与层叠上下文堆叠世界的规则CSS里除了“水平方向”和“垂直方向”还有一个“Z轴方向”。很多诡异的问题比如弹窗被遮挡、下拉菜单跑到背景后面都是定位和层叠上下文没搞明白。5.1 position的5个取值position有5个常用取值static、relative、absolute、fixed、sticky。这里面理解难点在absolute它的定位参照物是最近的非static定位祖先。如果所有祖先都是static那它就相对初始包含块通常是html或body定位。这个“最近的非static祖先”经常被忽略面试时让候选人举例说明很多人会卡壳。fixed也有一个类似的“坑”它会相对浏览器视口定位除非某个祖先元素设置了transform、perspective或filter属性fixed的包含块会被改变成那个祖先。这就是为什么有些弹窗写了position: fixed结果滚动页面时弹窗跟着跑——因为它的父级用了transform。sticky是兼容性已经比较好的定位方式它可以做到“滚动到某个位置时吸顶”但它的生效条件是父容器必须有足够的滚动空间且top/bottom等值要设置。如果父容器高度不够sticky就不粘。5.2 z-index失效的坑z-index是面试里容易出“送命题”的知识点。很多人知道“z-index越大越在上面”但忽略了z-index只对定位元素position非static生效。一个position: static的元素设置z-index: 9999也是无效的。另一个容易被忽略的是层叠上下文。每当一个元素满足某些条件比如opacity小于1、transform不为none、filter不为none、position加z-index等它就会创建一个新的层叠上下文。层叠上下文内部的z-index无法越过父级去和外部元素比较。举个例子父元素A的z-index是1子元素B的z-index是100另一个兄弟元素C的z-index是2。B虽然z-index为100但它不能跑到C上面因为Az-index: 1整体低于Cz-index: 2。这个机制和“公司部门与个人的关系”类似就算你在部门里职位再高部门整体在外部的优先级别不够你也没法代表部门去跟别的部门比。6. 高频CSS技巧面试官最爱的细节题面试进行到中段常常会问一些“看起来简单但实际很讲究”的细节题比如文字溢出、字体渐变、动画闪烁。这种题考察的是候选人有没有真正处理过业务里的样式难题而不是光会写布局。6.1 单行省略与多行省略让超长文字显示成省略号是前端日常开发里非常常见的需求。单行省略三件套背下来就能用.ellipsis { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }多行省略在WebKit内核下可以这样写.multiline-ellipsis { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }-webkit-line-clamp指定最多显示行数超过的部分截断并显示省略号。这个写法的兼容性在80%以上的场景都OK但在某些内部浏览器上可能失效。如果真的要把多行省略做得很稳可以用max-height配合line-height计算行数写起来笨一点但兼容性更好。6.2 文字竖排、字体渐变与CSS mask文字竖着排列在传统中文排版、海报设计里很常用。CSS写法是writing-mode: vertical-rl表示文字从上到下、从右到左排列。这个属性兼容性已经很好了不需要额外处理。字体渐变面试题里的经典问法“文字能不能用渐变颜色”可以用background-clip配合text实现.gradient-text { background: linear-gradient(90deg, #ff6a00, #ee0979); -webkit-background-clip: text; background-clip: text; color: transparent; }这里关键的两步background-clip: text让背景只作用于文字形状内部color: transparent把文字本身颜色变成透明露出背景渐变。原理不复杂但很多不常写的人容易忘记color: transparent。mask属性也经常在面试里出现它类似PS里的蒙版用来控制元素哪些区域可见、哪些透明。最简单的用法是用一张PNG图的透明度作为遮罩.mask { mask-image: url(shape.png); mask-size: cover; }常见的CSS动效网站喜欢用mask做图片渐隐渐显、镂空文字效果。它的兼容性在Chrome和Safari里需要加-webkit-前缀写的时候注意。6.3 涟漪动画、hover延迟关闭与伪元素变量控制热词里有“css涟漪光圈扩散”这是一种常见的交互反馈动画点击按钮时扩散一圈圆环。实现的核心是::after伪元素加动画.btn { position: relative; overflow: hidden; } .btn::after { content: ; position: absolute; width: 20px; height: 20px; border-radius: 50%; background: rgba(255, 255, 255, 0.5); transform: scale(0); animation: ripple 0.6s ease-out; } keyframes ripple { to { transform: scale(10); opacity: 0; } }“css hover延迟关闭”对应的是鼠标移出后下拉菜单延迟消失的需求。用transition和visibility配合可以实现但更简单的方案是在伪类上设置延迟.menu { visibility: hidden; opacity: 0; transition: opacity 0.3s ease, visibility 0s linear 0.3s; } .parent:hover .menu { visibility: visible; opacity: 1; transition-delay: 0s; }注意这里visibility的transition加了0.3s延迟为的是让它先保持“隐藏”状态直到透明度动画结束避免标签还可见时突然消失。“css 控制伪元素变量”是指通过CSS自定义属性CSS变量来动态控制伪元素的内容。例如.tip::after { content: var(--tip-content, 默认提示); }然后通过JavaScript修改--tip-content或者在不同场景下重新定义这个变量就能做到不改CSS文件只改变量的情况下更新伪元素内容。这个技巧在做换肤、动态提示语时很实用。避坑提示伪元素::before/::after必须声明content属性哪怕是空字符串。另外伪元素默认是display: inline直接设置宽高不生效需要先display: block或position: absolute。7. 移动端适配与兼容性小程序和H5的痛移动端兼容性是面试里很容易暴露项目经验深浅的部分因为只有真实上线过、被用户设备折磨过的人才写得出那些处理细节。7.1 小程序苹果底部兼容方案热词里有“小程序苹果底部兼容css”实际上是在说iPhone的底部Home条适配问题。iPhone X及以后机型底部有一条横线如果页面的底部操作栏盖住了它就会导致按钮点不到、滑动不顺畅。常规适配是用系统安全区变量.footer { padding-bottom: constant(safe-area-inset-bottom); /* 旧版iOS */ padding-bottom: env(safe-area-inset-bottom); /* 新版iOS */ }在小程序里为了兼容不同版本的iOS很多人习惯两条都写。顺序上有讲究constant在前env在后后者覆盖前者因为新系统认识env就不认识constant了。如果底部按钮是position: fixed定位建议把安全区的padding加到按钮本体的box-sizing: border-box范围内避免因为加了padding导致按钮整体高度变化、视觉上不对齐。7.2 响应式布局与媒体查询响应式布局的核心是媒体查询但“用哪个断点”一直是争论点。我的经验是不确定断点的情况下优先用Bootstrap的断点体系——576px、768px、992px、1200px团队协作时能减少分歧。断点设定后配合min-width和max-width的选择取决于设计思路。如果项目是“移动优先”用min-width向上兼容代表小屏是默认样式大屏逐级增强如果项目是“桌面优先”用max-width向下兼容。这里还有一个实用技巧与其每个断点都去调padding、margin不如把布局维度抽出来。比如一个大卡片在大屏上是两栏小屏上是一栏只需要改Grid的grid-template-columns别的样式通过Grid天然响应式自动调整。7.3 CSS deep方法样式穿透的原理热词“css deep方法”经常出现在Vue组件开发里。Vue的scoped样式会在元素上添加一个>:deep(.child-class) { color: red; }编译后的效果是把.child-class选择器的>
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门