CSS面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

前端阅读 655月28日 03:23

CSS 选择器的权重怎么计算?

CSS 权重(Specificity)用四元组 (a, b, c, d) 表示,从左往右逐位比较,高位相同才比下一位:| 位置 | 含义 | 示例 | 每个贡献值 ||------|------|------|-----------|| a | 行内样式 | style="" | 1 || b | ID 选择器 | #header | +1 || c | 类/属性/伪类 | .nav、[type="text"]、:hover | +1 || d | 标签/伪元素 | div、::before | +1 |:::tip通配符 * 、组合符(>、+、~、空格)不贡献权重。 :where() 始终零权重, :is() 取参数中最高权重参与计算。:::权重计算实战逐个拆解选择器,把各部分归入对应位:/* (0, 1, 0, 0) */#header { }/* (0, 0, 2, 1) — 2个类 + 1个标签 */.nav .item a { }/* (0, 1, 1, 0) — 1个ID + 1个类 */#sidebar .active { }/* (0, 0, 1, 2) — 1个伪类 + 2个标签 */div p:hover { }/* (0, 0, 0, 0) — 通配符不贡献 */* { }比较规则:高位相同才比下一位。(0,1,0,0) 永远大于 (0,0,99,99) ——ID 列永远比 class 列大,不可进位。!important 与权重的关系!important 不参与四元组计算,它独立于权重体系之外:优先级从高到低:!important > 行内 > ID > class > tag > *当多条 !important 规则冲突时,回到权重比较决定谁胜出;权重也相同则后写的覆盖先写的。.box { color: red !important; } /* 同为 !important,回到权重比较 */#box { color: blue !important; } /* #box 权重更高,blue 胜出 */:::warning滥用 !important 会导致样式不可维护,只能在覆盖第三方库等少数场景使用,并注释原因。::::is() 与 :where() 的权重差异这是面试高频追问点:/* :is() 取参数最高权重 */:is(.nav, #main) a { }/* 等价于 #main a → (0, 1, 0, 1) *//* :where() 始终零权重 */:where(.nav, #main) a { }/* 等价于 a → (0, 0, 0, 1) */:where() 的零权重特性非常适合写基础/重置样式——使用者用任意 class 即可覆盖,无需担心权重冲突。@layer 对权重的影响CSS Cascading Layers(@layer)引入了层叠层的概念,层的优先级规则:无层样式 > 具名层样式(不管权重多高)层内按声明顺序:后声明的层优先级更高同一层内才按权重比较@layer base { #header { color: blue; } /* (0,1,0,0) 但在 base 层 */}/* 无层 —— 即使权重低也会赢 */.header { color: red; } /* (0,0,1,0) 无层,优先级更高 */继承的权重继承的样式没有权重,甚至低于通配符 *:* { color: gray; } /* (0,0,0,0) 但属于直接匹配 */body { color: black; } /* 子元素通过继承得到 black *//* p 元素会显示 gray —— 直接匹配 > 继承 */实际项目中的权重管理策略BEM 命名:只用 class,杜绝 ID 和嵌套选择器,权重始终为 (0,0,1,0) 级别选择器嵌套不超过 3 层:.block__element--modifier 足够,避免 .a .b .c .d用 :where() 写重置样式:where(reset) 可被任意 class 轻松覆盖CSS Modules / Scoped CSS:工具自动处理作用域,天然避免权重冲突避免 !important:仅在覆盖第三方库样式时使用,务必注释原因追问多个类选择器和一个 ID 选择器哪个权重高?ID 权重更高。#foo 是 (0,1,0,0),.a.b.c.d.e 再多类也是 (0,0,5,0)——高位相同才比下一位,b 列 1 > c 列 5,ID 永远胜出。怎么快速判断两个选择器的优先级?分三步:(1) 先看有没有 !important;(2) 再看是否在 @layer 中(无层 > 有层);(3) 最后按四元组从左往右逐位比。同权重时后写的覆盖先写的。内联样式和 !important 谁优先?!important 优先。!important > 行内样式 > ID > class > tag。但两条都是 !important 时,再回到权重体系比较。伪类 :not() 的权重怎么算?:not() 本身不贡献权重,但它括号内的选择器参与计算。:not(.foo) 的权重等于 .foo,即 (0,0,1,0)。同理 :not(#bar) 按 ID 计算权重 (0,1,0,0)。注意 :not() 内可以写复杂选择器,取其完整权重。
前端阅读 675月28日 03:22

什么是伪类和伪元素?它们之间有什么区别?

伪类和伪元素都是 CSS 选择器的扩展机制,但本质不同:伪类(单冒号 :):选择 DOM 中已有元素的某种状态。元素本身存在,伪类只是在特定条件下"筛选"它。比如 :hover 选中的还是那个 <a> 元素,只不过它正处于鼠标悬停状态。伪元素(双冒号 ::):在 DOM 树中创建一个不存在的虚拟节点,然后对这个虚拟节点施加样式。比如 ::before 在元素内容前面插入一个匿名盒子,这个盒子在 HTML 源码里根本不存在。用一个类比:伪类是给已有的人拍一张特定状态的照片(站着、坐着),伪元素则是凭空造出一个不存在的人再给他拍照。/* 伪类:选择处于悬停状态的 a 元素 */a:hover { color: red;}/* 伪元素:在元素内容前插入虚拟内容 */a::before { content: "→ ";}语法规范的演变CSS1 和 CSS2 时代,伪类和伪元素都用单冒号 :,比如 :before、:after、:first-letter 和 :hover、:focus 混在一起,容易混淆。CSS3 为了区分二者,规定:伪类继续用单冒号 :hover伪元素改用双冒号 ::before浏览器为了向后兼容,仍然支持 :before 这种单冒号写法,但在新项目中应该统一使用双冒号。常见伪类分类| 类别 | 示例 | 说明 ||------|------|------|| 交互状态 | :hover :active :focus :focus-within | 用户交互触发的状态 || 位置匹配 | :first-child :last-child :nth-child(n) :nth-of-type(n) | 基于元素在兄弟中的位置 || 否定与匹配 | :not() :is() :where() :has() | 逻辑组合选择器 || 表单相关 | :checked :disabled :valid :invalid :required | 表单元素的状态 || 链接状态 | :link :visited | 未访问/已访问链接 |常见伪元素分类| 伪元素 | 作用 ||--------|------|| ::before / ::after | 在元素内容前后插入虚拟盒子 || ::first-letter | 选中块级元素首字母(可实现首字下沉效果) || ::first-line | 选中块级元素首行(字号变化时首行范围自适应) || ::selection | 用户选中文本的样式 || ::placeholder | 输入框占位文字的样式 |选择器组合规则一个选择器可以同时使用多个伪类,它们叠加生效:/* 合法:同时匹配"第一个子元素"和"悬停状态" */li:first-child:hover { background: yellow;}但一个选择器只能使用一个伪元素,且伪元素必须出现在选择器末尾:/* 合法:伪元素在最后 */a:hover::before { content: "🔗";}/* 非法:伪元素后面不能再接伪类 */a::before:hover { } /* 无效 */原因是伪元素创建了一个新的虚拟盒子,它不是 DOM 节点,无法拥有状态,所以 ::before:hover 没有意义。渲染层面的差异伪类不影响渲染树的构建——它只是让选择器在匹配阶段多了一个条件,匹配到的元素照常进入渲染树。伪元素则会在渲染树中额外生成一个匿名盒子。浏览器在布局计算时,::before 和 ::after 生成的盒子会参与父元素的排版,占用空间(如果设置了宽高或内容的话)。你可以打开 DevTools 的 Elements 面板,看到 ::before 和 ::after 出现在元素节点下方。追问:nth-child(n) 和 :nth-of-type(n) 有什么区别?:nth-child(n) 在所有兄弟元素中数第 n 个,不管标签类型。:nth-of-type(n) 只在同标签类型的兄弟中数第 n 个。<div> <h2>标题</h2> <p>第一段</p> <!-- p:nth-child(2) 匹配失败:它是第2个子元素但不是h2 --> <p>第二段</p> <!-- p:nth-of-type(2) 匹配成功:它是第2个p --></div>关键记忆:nth-child 先数位置再验类型,nth-of-type 先筛类型再数位置。::before 和 ::after 必须配合 content 属性吗?是的。没有 content 属性,伪元素不会生成盒子。哪怕不需要任何文字内容,也必须写 content: ''。content 支持的值包括字符串、attr() 函数、图片 url()、计数器 counter() 等:.tooltip::after { content: attr(data-tip); /* 读取元素属性作为内容 */}.counter::before { content: counter(section) ". "; /* 配合 counter-increment 使用 */}伪元素可以绑定 JS 事件吗?不能。伪元素不存在于 DOM 树中,document.querySelector 无法选中它,JS 事件也无法直接绑定。如果想间接检测伪元素的点击,可以通过判断 event.offsetX / event.offsetY 是否落在伪元素的渲染区域内。实际开发中更推荐用真实 DOM 元素替代伪元素来实现交互需求。:has() 伪类和伪元素有什么关系?:has() 是 CSS4 引入的关系型伪类(不是伪元素),被称为"父选择器"。它可以根据子元素的状态来选择父元素:/* 选择包含 img 子元素的 a 标签 */a:has(> img) { border: 1px solid #ccc;}/* 选择后面紧跟着 h2 的 h1(兄弟关系) */h1:has(+ h2) { margin-bottom: 0;}:has() 的出现弥补了 CSS 长期缺失的"向上选择"能力,目前主流浏览器已全面支持。
前端阅读 575月28日 03:15

CSS display 有哪些值?面试必考的 9 个属性详解

CSS display 控制元素在页面上的渲染方式,面试常考的就这几个:none — 元素不渲染、不占空间,从布局树中移除。和 visibility: hidden 的关键区别:后者保留空间只隐藏视觉效果。频繁切换显隐优先用 visibility,因为只触发重绘不触发回流。block — 独占一行,可设宽高。<div>、<p>、<h1> 默认就是 block。inline — 不换行,宽高由内容撑开,垂直方向的 margin/padding 不生效。<span>、<a> 默认 inline。inline-block — 对外像 inline 不换行,对内像 block 能设宽高。做横排按钮、导航菜单首选。flex — 弹性布局容器,子元素沿主轴排列。居中、等分空间、对齐一行搞定,一维布局主力。grid — 网格布局容器,同时控制行和列。二维布局(如页面骨架、卡片网格)用 grid 更直观。table 系列(table / table-row / table-cell)— 不用 <table> 标签也能模拟表格布局,现在主要用来做垂直居中(table-cell + vertical-align)。contents — 元素本身不生成盒子,子元素直接参与父级布局。做组件封装时有用,不想让容器标签影响布局。flow-root — 创建新的 BFC,等效于 clearfix 的正经方案。浮动清除不再需要伪元素 hack。补充一点:现代 CSS 支持 display 双值语法,比如 inline flex 等于 inline-flex,第一个值控制外部显示类型,第二个值控制内部。目前浏览器支持度还不错,面试提一句是加分项。追问inline 元素设置 width/height 为什么不生效?CSS 规范规定非替换 inline 元素的盒模型由内容决定,宽高属性不适用。想设宽高就换成 inline-block 或 block。但 <img>、<input> 这类替换元素虽然是 inline,却可以设宽高——因为它们有内在尺寸。flex 和 grid 怎么选?一维用 flex,二维用 grid。实际项目经常混搭:外层 grid 做页面骨架,内层 flex 做组件对齐。别纠结"哪个更好",它们解决的不是同一个问题。display: none、visibility: hidden、opacity: 0 有什么区别?| | display: none | visibility: hidden | opacity: 0 ||---|---|---|---|| 占空间 | 不占 | 占 | 占 || 触发回流 | 是 | 否 | 否 || 触发重绘 | 是 | 是 | 否 || 子元素可覆盖 | 否 | 是(设 visible) | 否 || 响应事件 | 否 | 否 | 是 || 可访问性 | 不可见 | 不可见 | 可见 |频繁切换用 visibility(只重绘),需要完全移除用 display: none,做淡入淡出动画用 opacity。display: contents 在实际项目里有什么用?做组件封装时,容器 div 只是想传 props,不想让它参与布局。比如一个 <Card> 组件渲染成 <div class="card"><slot/></div>,但外层用 grid 布局时不希望 .card 这层 div 打断网格结构,这时候给 .card 设 display: contents 就行。注意:contents 会导致元素本身的样式和可访问性语义丢失,屏幕阅读器可能跳过它。
前端阅读 655月28日 03:13

移动端如何画 0.5px 细线?3 种方案原理与实现

移动端高清屏上 1px 线太粗,本质是设备像素比(DPR)的锅。CSS 的 1px 在 2 倍屏上渲染成 2 个物理像素,在 3 倍屏上渲染成 3 个。想要真正 0.5px 的细线,业界主流有三种方案。transform + 伪元素是最稳的:用 ::after 画 1px 边框,再 scaleY(0.5) 缩一半。伪元素独立缩放,不影响容器内子元素。需要适配 3 倍屏时,DPR 为 3 的设备用 scaleY(0.333)。.hairline::after { content: ''; position: absolute; left: 0; bottom: 0; width: 100%; border-bottom: 1px solid #ccc; transform: scaleY(0.5); transform-origin: 0 0;}/* 3 倍屏适配 */@media (-webkit-min-device-pixel-ratio: 3) { .hairline::after { transform: scaleY(0.333); }}Vant、Ant Design Mobile 等组件库底层就是这个方案。meta viewport 缩放:把页面整体 initial-scale=0.5,然后正常写 1px。但这会让字号、间距全缩小一半,还得手动把所有尺寸乘 2 补回来,工程成本太高,几乎没人用。SVG / Canvas:stroke-width="0.5" 或 lineWidth = 0.5 精确控制像素。只适合画图场景,做边框属于杀鸡用牛刀。追问为什么不直接写 border: 0.5px?Chrome 和大部分 Android 浏览器会把小于 1px 的值当 0 处理或向上取整到 1px。iOS Safari 8+ 虽然支持 0.5px,但 Android 阵营几乎全军覆没,兼容性不可靠。3 倍屏怎么处理?3 倍屏(如部分安卓旗舰)CSS 1px 渲染成 3 物理像素,scaleY(0.5) 只缩到 1.5 物理像素,还不够细。正确做法是 scaleY(1/3),通过 @media (-webkit-min-device-pixel-ratio: 3) 匹配后单独处理。transform 缩放会不会影响点击事件?不会。transform 只影响视觉渲染层(composite),元素的布局尺寸和事件响应区域不变。伪元素本身也不参与事件传递。项目里怎么统一处理细线?封装一个 PostCSS 插件或 Less/Mixin,构建时自动把 1px 边框替换成伪元素方案。Vant 的 border-hairline 类就是这种思路:开发者写 class="van-hairline--bottom",框架自动生成 ::after + scale 代码。线性渐变和 box-shadow 方案呢?linear-gradient 画 50% 颜色 + 50% 透明的 1px 条带也能模拟 0.5px,但圆角边框没法用。box-shadow: 0 1px 1px -1px rgba(0,0,0,0.5) 利用负扩展让阴影只露一半,不过颜色控制不精确,深色线效果差。这两种都是备选,生产环境首选 transform 方案。
前端阅读 285月27日 01:06

什么是 CSS 弹性盒布局模型?

Flexbox(弹性盒布局)是一维布局模型,控制元素在一条轴(主轴或交叉轴)上的排列和对齐。设 display: flex 后,容器变成弹性容器,子元素变成弹性项目。核心概念:主轴(flex-direction 决定方向)和交叉轴容器属性:justify-content(主轴对齐)、align-items(交叉轴对齐)、flex-wrap(换行)、gap(间距)项目属性:flex-grow(放大比例)、flex-shrink(缩小比例)、flex-basis(基础大小)、align-self(单独对齐)最常用的三件套:display: flex; justify-content: center; align-items: center; —— 一行代码实现水平垂直居中。追问flex: 1 是什么意思?flex: 1 = flex-grow: 1; flex-shrink: 1; flex-basis: 0%。表示元素按比例瓜分剩余空间,常用于等分布局。flex: auto 不同在于 flex-basis: auto(先看元素自身尺寸再瓜分剩余空间)。Flexbox 和 Grid 什么时候用哪个?Flexbox 是一维的,适合组件内部排列(导航栏、按钮组、表单行)。Grid 是二维的,适合页面级布局(一行多列、复杂网格)。实际项目混用居多:Grid 做页面骨架,Flexbox 做组件内部。为什么 flex 子元素设置 width 有时不生效?flex-shrink 默认是 1,空间不够时项目会被压缩。加上 flex-shrink: 0 或 min-width: <你的宽度> 阻止收缩即可。
前端阅读 02月7日 13:55

CSS中的盒子模型是什么?

CSS中的盒子模型是用于设计和布局在网页上的元素的一种模型。它主要由以下几部分组成:内容(Content): 这是元素的实际内容区域,可以是文本、图片或其他媒体内容。内边距(Padding): 内边距是内容区域周围的空白区域,它位于内容区域和边框之间。边框(Border): 围绕内边距和内容的线框,可以设定其样式、宽度和颜色。外边距(Margin): 边框外的空白区域,用于将不同的元素彼此分开。整个盒子的宽度和高度不仅包括内容的尺寸,还包括内边距、边框和外边距的大小。理解盒模型对于掌握CSS布局至关重要,尤其是在处理元素间的空间关系和响应式设计时。
前端阅读 22月7日 13:55

什么是CSS伪元素?举例说明它们的用法。

CSS伪元素是一种特殊的语法,用于选择元素的特定部分,而不是选择整个元素。它们通常用来添加装饰或特殊效果。伪元素以双冒号 :: 开始,并且附加在选择器的末尾。比如:::before 和 ::after 是两个常用的伪元素。示例用法::before 和 ::after这两个伪元素常用于在元素的内容前后添加内容或装饰。这些内容通过CSS插入,并且可以通过 content 属性来指定。/* 在每个 <p> 元素前添加装饰性的引号 */p::before { content: open-quote; color: red;}/* 在每个 <p> 元素后添加装饰性的引号 */p::after { content: close-quote; color: red;}::first-letter这个伪元素用于选择文本的第一个字母,并进行特殊的样式化。/* 将段落的第一个字母样式化 */p::first-letter { font-size: 200%; color: blue;}::first-line这个伪元素用于选择文本的第一行,并进行样式化。/* 将段落的第一行字体加粗 */p::first-line { font-weight: bold;}这些伪元素提供了一个强大的工具,用于改进和增强网页的视觉表现,而不需要额外的HTML标记。
前端阅读 1712024年8月5日 12:50

Web 端应用如何做移动的适配

为了确保Web应用能够在移动设备上良好运行,我们需要关注几个关键点:1. 响应式设计(Responsive Design)响应式设计是适配移动端的核心。通过使用媒体查询(Media Queries)和相对单位(如百分比,em,rem等),我们可以确保网页布局和元素能够根据不同设备屏幕尺寸和分辨率自动调整。例如,Bootstrap框架提供了一系列预定义的响应式类,可以帮助开发者更快地实现响应式设计。例子:@media screen and (max-width: 768px) { .container { width: 100%; }}上面的媒体查询表明,当屏幕宽度小于或等于768像素时,.container 类的宽度将被设置为100%。2. 触控优化(Touch Optimization)移动设备通常是通过触控进行操作的,因此需要确保所有的交互元素(如按钮、链接、表单控件等)都足够大,以便手指点击,并有足够的间距,以防误触。HTML5为表单元素提供了适用于移动端的类型,如 <input type="email">,这会调用适合输入电子邮件的虚拟键盘。例子:<button class="touch-optimized-button">Submit</button>.touch-optimized-button { padding: 15px; margin: 10px; font-size: 18px;}3. 视口配置(Viewport Configuration)通过设置 <meta>标签中的 viewport属性,我们可以控制视口的尺寸和比例。这告诉浏览器如何控制页面的尺寸和比例,以匹配不同设备的屏幕。例子:<meta name="viewport" content="width=device-width, initial-scale=1.0">4. 性能优化(Performance Optimization)移动设备相比于桌面设备,其网络连接可能更不稳定,处理能力可能更弱。因此,要特别注意减少代码体积、图片大小,以及优化加载时间。使用压缩工具、图片懒加载、缓存策略等,都是性能优化的常见做法。例子:使用WebP格式的图片,它比传统的JPEG或PNG格式具有更好的压缩率,可以更快地加载。5. 使用框架和工具(Frameworks and Tools)现代前端框架和库,如React、Vue、Angular等,通常都有考虑到移动设备的适配。使用这些框架和它们的UI组件库(如Material-UI, Vuetify等),可以更快地开发出适合移动设备的界面。例子:import { Button } from '@material-ui/core';<Button variant="contained" color="primary"> Click me</Button>综上所述,要做好移动端的Web应用适配,需要综合考虑布局、交互、视口设置、性能优化以及合适的开发工具。通过以上这些方法,我们可以提供更好的移动用户体验,并确保应用在不同设备上都能够良好地运行。
前端阅读 1362024年8月5日 12:48

如何做 CSS 的性能优化

CSS 性能优化是 web 项目性能优化中的重要部分。以下是一些策略来帮助优化 CSS 的性能:减少冗余代码为类或元素重复写入相同的 CSS 规则会浪费带宽和浏览解析时间。实用工具如 PurgeCSS 可帮助删除无用的 CSS。CSS 压缩CSS 压缩可以移除所有多余的字符,包括空格、换行符和注释。使用CSS 压缩工具如 CSSO 或 clean-css。使用 CSS 雪碧图CSS 雪碧图合并了一系列的小图片到一张大的图片中。这可以减少HTTP请求的数量,提高加载速度。CSS 对象模型(CSSOM) 和 渲染树浏览器通过解析 HTML 和 CSS 成 CSSOM 和 DOM ,然后结合他们形成渲染树。因此,应该尽量把 CSS 放在 HTML 文档的顶部,以加快渲染速度。避免使用过于复杂的选择器复杂的选择器可能会导致浏览器使用更多的资源来解析它们,优先使用类和 ID 选择器。使用 CSS 预处理器CSS 预处理器如 Sass 或 Less 可以使 CSS 更易于维护,同时可以使用变量,嵌套,混入 (Mixins) 等高级特性。使用硬件加速利用 GPU 来提供高效渲染,例如 transform 或 opacity。避免使用 @import@import 可能会导致更多的 HTTP 请求,使页面加载速度变慢。应该尽量使用命令行工具或构建系统的导入功能,以便在构建过程中进行文件合并。按需加载 CSS只加载需要立即使用的 CSS。缩小 CSS 的范围例如, instead of using * {margin: 0; padding: 0;}, 用类似 .myClass {margin: 0; padding: 0;} 更好。
前端阅读 1252024年8月5日 12:48

css 清除浮动的几种方式以及各自的优缺点

CSS中清除浮动(Float)的几种常见方法如下:1. 使用clear属性在浮动元素之后添加一个空的元素,并为其设置clear属性。<div class="float-element"></div><div class="clear"></div>.float-element { float: left;}.clear { clear: both;}优点:简单易懂。兼容性好,适用于所有浏览器。缺点:需要额外的标记(markup),可能导致HTML结构变得臃肿。与内容分离度不高,不符合现代Web开发的最佳实践。2. 使用overflow属性为父元素设置overflow: auto或overflow: hidden可以清除子元素的浮动。.parent { overflow: auto;}优点:不需要添加额外的HTML元素。代码简洁。缺点:在某些情况下可能会导致不期望的滚动条出现。如果子元素需要超出父容器边界显示,此方法可能会剪切子元素的部分内容。3. 使用伪元素清除浮动(clearfix hack)通过在父元素上添加一个伪元素来清除浮动。.clearfix::after { content: ""; display: block; clear: both;}优点:不需要在HTML中添加额外的元素。代码整洁且符合无障碍标准。被广泛采纳,成为一种标准做法。缺点:在旧版IE浏览器中可能需要额外的兼容性处理。4. 使用Flexbox将父元素设为Flex容器。.parent { display: flex;}优点:为现代网站提供了更强大的布局选项。自动处理了元素的浮动问题,不需要显式清除。缺点:在不支持Flexbox的老旧浏览器中不可用。涉及到布局方式的更改,可能需要重新考虑整个布局结构。5. 使用Grid布局将父元素设为Grid容器。.parent { display: grid;}优点:更先进的布局系统,提供了更多布局选项。同样自动处理元素的浮动问题。缺点:兼容性不如Flexbox,特别是在老旧浏览器上。总的来说,选择哪种方法取决于具体项目的要求、浏览器兼容性,以及开发者对于CSS规范的熟悉程度。清除浮动是一个常见的问题,现代前端开发倾向于使用clearfix技术或更现代的布局方法(如Flexbox或Grid)来避免这个问题。