DrillLab
八股题库Question bank

105 道问答题,一道一卡105 questions, one card each

默认只显示问题 —— 先自己在心里答一遍,再展开对答案。答不上来就标「不会」,下次抽认卡会先抽它。Only the question shows by default. Answer it in your head first, then open the answer. Mark the ones you miss; the flashcard round puts those first.

0 / 105道自评过self-assessed
0Got it0模糊Shaky0不会No idea105还没做Not seen
正在读这台浏览器里的标记…Reading your marks from this browser…
标记不是打分,是给下一轮排队Marks are a queue, not a score

标「不会」的题会排到抽认卡最前面,标「会」的进低频池排最后。所以别客气 —— 觉得答得磕磕巴巴就标「模糊」。准备好了就去抽认卡“No idea” jumps to the front of the next round; “got it” drops to the back. So be honest — if it came out shaky, mark it shaky. Then go run a flashcard round.

题目Questions

筛出 105 道 · 第 1 / 9 页。105 of 105 questions · page 1 / 9.
HTMLHTML#269

块级元素 vs 行内元素

Block element vs Inline element

看答案Show answer

一句话:块级元素独占一行、宽高可控; 行内元素跟着文字流走、宽高由内容决定。

具体差别就三处,记住这三条就够答:

  • 换行—— 块级前后自动断行(divph1ul); 行内不断行(spanastrongimg)。
  • 宽高—— 块级可以设 width /height;行内设了不生效
  • 内外边距—— 块级四个方向都生效; 行内的上下 margin 不生效, 上下 padding 视觉上会溢出但不撑开行高。

会追问:「那 inline-block 呢?」 —— 它是折中:不换行(像行内),但宽高和上下 margin 都生效(像块级)。 导航按钮常用它。

还会追问:img 是行内元素, 为什么能设宽高?」—— 因为它是替换元素(replaced element), 内容由外部资源决定,浏览器对它网开一面。inputvideo 同理。 这个点答出来会加分。

In one line: a block element takes the whole line and you can set its width and height; an inline element flows with the text and is sized by its content.

There are exactly three differences worth remembering:

  • Line breaks — block elements break before and after (div, p, h1, ul); inline ones do not (span, a, strong, img).
  • Width and height — settable on block elements, ignored on inline ones.
  • Margin and padding — all four sides work on block elements; on inline elements vertical margin does nothing, and vertical padding overflows visually without pushing the line apart.

Follow-up: “What about inline-block?” — it is the compromise: no line break (like inline) but width, height and vertical margin all work (like block). Nav buttons use it constantly.

Also asked:img is inline, so why can you set its size?” — because it is a replaced element: its content comes from an external resource, so the browser makes an exception. Same for input and video. Getting this one right scores points.

HTMLHTML#380

事件冒泡 vs 事件捕获

Event bubbling vs Event capturing

看答案Show answer

一句话:一次点击在 DOM 里走三段 —— 先从 window 往下到目标(捕获), 在目标上触发(目标阶段),再从目标往上回到window(冒泡)。捕获从外到内,冒泡从内到外。

addEventListener 第三个参数决定你在哪一段听: 默认 false 听冒泡,true(或 { capture: true })听捕获。

为什么默认是冒泡?因为绝大多数时候你想知道的是 「用户点了什么」,从内往外传最自然 —— 而且这才让事件委托成为可能(见 #289)。

会追问:「怎么阻止?」

  • e.stopPropagation()—— 别再往上(或往下)传了。
  • e.stopImmediatePropagation()—— 连同一个元素上的其他监听器都别跑了。
  • e.preventDefault()—— 阻止的是默认行为(链接跳转、表单提交), 和传播完全无关。这两个最容易混,别答错。

还会追问:「有哪些事件不冒泡?」——focusblurloadmouseentermouseleave。 需要委托时用它们的冒泡版:focusin /focusout / mouseover /mouseout

In one line: a click travels the DOM in three phases — down from window to the target (capture), fires on the target, then back up to window (bubble). Capture goes outside-in, bubbling goes inside-out.

The third argument to addEventListener picks the phase you listen in: false (the default) is bubbling, true (or { capture: true }) is capture.

Why is bubbling the default? Because what you almost always want to know is “what did the user click”, and inside-out is the natural direction for that — it is also what makes event delegation possible (see #289).

Follow-up: “How do you stop it?”

  • e.stopPropagation() — stop travelling further up (or down).
  • e.stopImmediatePropagation() — also skip other listeners on the same element.
  • e.preventDefault() — cancels the default behaviour (link navigation, form submit) and has nothing to do with propagation. These two get mixed up most often; do not confuse them.

Also asked: “Which events do not bubble?” —focus, blur, load, mouseenter, mouseleave. When you need to delegate, use their bubbling counterparts: focusin / focusout / mouseover / mouseout.

JavaScript三个阶段的完整顺序The full order of the three phases示意Illustrative
1// <div id="outer"><div id="inner"><button id="btn">点我</button></div></div>
2
3outer.addEventListener("click", () => console.log("outer 捕获"), true);
4inner.addEventListener("click", () => console.log("inner 捕获"), true);
5btn .addEventListener("click", () => console.log("btn 目标"));
6inner.addEventListener("click", () => console.log("inner 冒泡"));
7outer.addEventListener("click", () => console.log("outer 冒泡"));
8
9// 点击 btn 的输出顺序:
10// outer 捕获 -> inner 捕获 -> btn 目标 -> inner 冒泡 -> outer 冒泡
1// <div id="outer"><div id="inner"><button id="btn">Click me</button></div></div>
2
3outer.addEventListener("click", () => console.log("outer capture"), true);
4inner.addEventListener("click", () => console.log("inner capture"), true);
5btn .addEventListener("click", () => console.log("btn target"));
6inner.addEventListener("click", () => console.log("inner bubble"));
7outer.addEventListener("click", () => console.log("outer bubble"));
8
9// Output order when btn is clicked:
10// outer capture -> inner capture -> btn target -> inner bubble -> outer bubble
面试里画得出这个顺序,基本就过了。注意目标元素上的监听器不分捕获/冒泡,按注册顺序执行。If you can draw this order in an interview, that question is handled. One detail: on the target element itself there is no capture or bubble distinction, so those listeners run in the order they were registered.
HTMLHTML#381

meta 标签有什么用

What is the importance of the meta tag?

看答案Show answer

一句话:meta 放的是 「关于这个页面的信息」—— 浏览器、搜索引擎、社交平台读它,用户看不到它。

真正天天用到的就四个,答这四个就够:

  • <meta charset="UTF-8">——必须放在 head 最前面。 没有它中文会乱码,因为浏览器得先知道用什么编码去解析后面的字节。
  • viewport——移动端适配的前提。 不写这一行,手机浏览器会假装自己有 980px 宽然后整页缩小, 你写的所有响应式 CSS 全白费(见 #274)。
  • description—— 搜索结果里那段摘要。 它不影响排名,但影响点击率。
  • Open Graphog:titleog:image)—— 链接分享到微信 / Slack / Twitter 时显示的卡片。

会追问:keywords 还有用吗?」 —— 没用了,Google 早就不看,因为被滥用成了堆关键词。 这个点能答出来说明你不是背的旧教程。

In one line: meta carries information about the page — browsers, search engines and social platforms read it; users never see it.

Only four of them actually matter day to day:

  • <meta charset="UTF-8"> must be first in the head. Without it non-ASCII text turns to mojibake, because the browser has to know the encoding before it can parse the bytes that follow.
  • viewport the precondition for mobile. Without this line a phone browser pretends it is 980px wide and scales the whole page down, which throws away every responsive rule you wrote (see #274).
  • description — the snippet in search results. It does not affect ranking, but it affects click-through.
  • Open Graph (og:title, og:image) — the card shown when the link is shared into Slack, Twitter or a chat app.

Follow-up: “Does keywords still do anything?” — no. Google stopped reading it long ago because it was abused into keyword stuffing. Knowing this shows you are not reciting an old tutorial.

Text实际会写的那几行示意Illustrative
1<head>
2 <meta charset="UTF-8"> <!-- 必须最先 -->
3 <meta name="viewport" content="width=device-width, initial-scale=1">
4 <meta name="description" content="一句话说明这个页面是干什么的">
5 <meta property="og:title" content="分享出去显示的标题">
6 <meta property="og:image" content="https://…/cover.png">
7 <title>页面标题</title>
8</head>
1<head>
2 <meta charset="UTF-8"> <!-- must come first -->
3 <meta name="viewport" content="width=device-width, initial-scale=1">
4 <meta name="description" content="one sentence on what this page is for">
5 <meta property="og:title" content="the title shown when shared">
6 <meta property="og:image" content="https://…/cover.png">
7 <title>Page title</title>
8</head>
HTMLHTML#382

什么是语义化标签

What are Semantic Elements?

看答案Show answer

一句话:标签名本身说明了内容的角色 ——header / nav / main /article / section /aside / footer, 而 divspan 什么都没说。

关键是别答成「代码更好看」。语义化有两个可以量化的真实收益:

  • 屏幕阅读器能导航。视障用户可以按「跳到主内容」「列出所有标题」来浏览 —— 这些功能依赖标签语义。 一整页 div,读屏软件只能从头念到尾。
  • 搜索引擎知道哪块是正文。main 里的内容权重高于 aside

会追问:sectiondiv 到底怎么选?」—— 判断标准是「这块内容有没有自己的标题」。 有(能配一个 h2)就用 section; 纯粹为了布局套一层就用 div为了样式而套的容器就该是 div, 硬换成 section 反而污染了大纲。

In one line: the tag name itself states the role of the content — header / nav / main /article / section / aside /footer — whereas div and span say nothing at all.

Do not answer “the code looks nicer”. Semantics buys you two things you can actually measure:

  • Screen readers can navigate. A blind user can jump to the main content or list every heading — and those features depend on tag semantics. On a page of nothing but divs, a screen reader can only read from the top.
  • Search engines know which part is the article. Content in main weighs more than content in aside.

Follow-up: “So how do you choose between section and div?” — the test is “does this block have its own heading?” If it does (you could give it an h2), use section. If it is a wrapper you added purely for layout, use div. A container that exists for styling should be a div — forcing it to be a section just pollutes the document outline.

HTMLHTML#385

无障碍、可用性、包容性

Could you explain accessibility, usability, and inclusion? Give some examples of each one in terms of web design.

看答案Show answer

一句话区分:

  • 无障碍(accessibility, a11y)——有障碍的人能不能用。视障、听障、 运动障碍、认知障碍。
  • 可用性(usability)——能用的人用得顺不顺。找得到、看得懂、不容易点错。
  • 包容性(inclusion)——范围够不够宽。老年人、网速慢的、 用小屏手机的、非母语用户、临时单手抱着孩子操作的。

三者是包含关系:无障碍是包容性的一部分, 可用性差的东西对所有人都差。

每个给一个例子(面试要的就是例子):

  • a11y:给 imgalt;表单 labelhtmlFor 关联到 input保证键盘能 Tab 到所有交互元素, 并且焦点环别用 outline: none 删掉。
  • usability:按钮文字写「保存草稿」 而不是「提交」;表单报错指向出错的那个字段, 而不是页面顶部一句「表单有误」。
  • inclusion:正文对比度至少 4.5:1; 不用颜色作为唯一的信息载体 (红绿色盲看不出「红色是错的」,要同时给图标或文字); 首屏在 3G 下也能出内容。

会追问:「怎么测?」—— 键盘走一遍(不碰鼠标能不能完成主流程)、 Chrome DevTools 的 Lighthouse 跑一次 a11y 评分、axe 插件扫一遍。说得出工具名比说概念更可信。

The distinction in one line each:

  • Accessibility (a11y) can people with disabilities use it: vision, hearing, motor, cognitive.
  • Usability how smoothly can people who can use it, use it: can they find things, understand them, avoid mis-taps.
  • Inclusion how wide is the net: older users, slow connections, small screens, non-native speakers, someone operating one-handed while holding a child.

The three nest: accessibility is part of inclusion, and anything with poor usability is worse for everyone.

One example each — examples are what the interviewer wants:

  • a11y: write alt on images; tie a label to its input with htmlFor; make sure Tab reaches every interactive element and do not delete the focus ring with outline: none.
  • usability: label the button “Save draft” rather than “Submit”; put the validation error on the field that failed, not a generic banner at the top of the page.
  • inclusion: at least 4.5:1 contrast for body text; never use colour as the only carrier of meaning (someone with red-green colour blindness cannot see that “red means wrong”, so add an icon or a word); make the first screen usable on 3G.

Follow-up: “How do you test it?” — walk the main flow with the keyboard only; run Lighthouse’s a11y audit in Chrome DevTools; scan with the axe extension. Naming the tools is more convincing than naming the concepts.

CSSCSS#271

什么是盒模型

What is the Box Model

看答案Show answer

一句话:每个元素都是一个盒子, 由内到外四层:content → padding → border → margin

真正的考点是「width 到底量的是哪一段」

box-sizingwidth: 200px 指的是加上 padding: 20px 后实际占
content-box(默认)只有 content240px(200 + 20 × 2)
border-boxcontent + padding + border200px,content 被挤到 160px

为什么现在几乎所有项目都全局改成border-box因为「我说 200 宽就是 200 宽」符合直觉。 默认那套会让你在做「三列各 33.3%」时, 一加 padding 就换行 —— 这是新手最常撞的墙。

会追问:「margin 属于盒子吗?」——border-box不包含 margin。 margin 永远在盒子外面,是「盒子之间的距离」。

还会追问 margin 折叠(margin collapse):上下相邻的两个块级元素,上面的 margin-bottom: 20px和下面的 margin-top: 30px不会得到 50px,而是 30px(取较大值)。 这也是很多人「怎么调都差一点」的原因。 Flex 和 Grid 容器的子项不发生折叠

In one line: every element is a box with four layers from the inside out: content → padding → border → margin.

What is actually being tested is “what exactly does width measure?”

box-sizingwidth: 200px meanswith padding: 20px it occupies
content-box (default)content only240px (200 + 20 × 2)
border-boxcontent + padding + border200px; content is squeezed to 160px

Why does nearly every project switch to border-box globally? Because “when I say 200 wide I mean 200 wide” matches intuition. The default makes three columns at 33.3% wrap the moment you add padding — the wall every beginner hits.

Follow-up: “Is margin part of the box?” — even border-box excludes margin. Margin is always outside; it is the distance between boxes.

They will also ask about margin collapse: two adjacent block elements with margin-bottom: 20px and margin-top: 30px give you 30px, not 50px (the larger wins). This is why spacing so often ends up “slightly off”. Flex and grid children do not collapse.

CSS全局重置示意Illustrative
1/* 几乎每个项目开头都有这三行 */
2*,
3*::before,
4*::after {
5 box-sizing: border-box;
6}
1/* Almost every project starts with these three lines */
2*,
3*::before,
4*::after {
5 box-sizing: border-box;
6}
CSSCSS#272

margin vs padding

Margin vs Padding

看答案Show answer

一句话:padding 在边框里面, 是「内容和边框的距离」;margin 在边框外面,是「这个盒子和别人的距离」。

实际选哪个,看三条:

  • 要不要背景色 / 点击区。padding 属于元素本身,会被背景色覆盖、点它算点到元素; margin 是空白,点不到。按钮想加大点击区一定用 padding。
  • 会不会折叠。margin 会上下折叠,padding 永远不会。 想要「稳定的 20px 间距」用 padding 更可控。
  • 负值。margin 可以是负数(常用来做重叠、抵消父级 padding), padding 不行。

会追问:margin: 0 auto 为什么能居中,padding: auto 为什么不行?」—— margin 的 auto 会吃掉剩余空间并平分, padding 根本不支持 auto。 而且这招只对设了宽度的块级元素有效。

In one line: padding is inside the border — the gap between content and border; margin is outside — the gap between this box and everything else.

Three things decide which one you reach for:

  • Background and hit area. Padding belongs to the element, so the background paints over it and clicks on it count as clicks on the element; margin is empty space you cannot click. Always use padding to enlarge a button’s hit area.
  • Collapsing. Vertical margins collapse; padding never does. For a dependable 20px gap, padding is more predictable.
  • Negative values. Margin can be negative (used for overlaps, or to cancel a parent’s padding); padding cannot.

Follow-up: “Why does margin: 0 auto centre something when padding: auto does nothing?” —auto margins absorb the leftover space and split it evenly; padding does not support auto at all. And the trick only works on a block element with a set width.

CSSCSS#273

Flexbox vs Grid

Flexbox vs Grid

看答案Show answer

一句话:Flex 是一维的 (一行或一列,内容驱动); Grid 是二维的(同时管行和列,布局驱动)。

怎么选,一个判断句就够:「我需要同时控制行和列的对齐吗?」 要 → Grid;不要 → Flex。

FlexGrid
维度一维二维
谁决定尺寸内容(子项说我要多大)容器(我先划好格子,你往里放)
典型场景导航栏、按钮组、卡片内部的图文排列、 「左边文字右边按钮」整页骨架(头/侧栏/主体/脚)、 商品瀑布流、日历、表单的标签列 + 输入列
缺口flex-wrap 换行后各行互不知道对方,对不齐要先想清楚格子,改结构比 Flex 麻烦

会追问:「能一起用吗?」——正常做法就是一起用: Grid 搭页面骨架,每个格子内部用 Flex 排内容。 答「二选一」反而显得没实战过。

还会追问 flex: 1 是什么:它是三个属性的简写 ——flex-grow: 1; flex-shrink: 1; flex-basis: 0%。 意思是「剩余空间我来占,需要时也可以被压缩, 初始尺寸按 0 算」。 这就是「一个固定宽侧栏 + 一个自适应主体」最短的写法。

In one line: Flex is one-dimensional (a row or a column, content-driven); Grid is two-dimensional (rows and columns together, layout-driven).

One sentence decides it: “Do I need to control alignment across rows and columns at once?” Yes → Grid. No → Flex.

FlexGrid
DimensionsOneTwo
Who decides sizeThe content (items say how big they are)The container (cells first, content after)
Typical useNav bars, button groups, image-plus-text inside a card, “text left, button right”Page skeleton (header / sidebar / main / footer), product grids, calendars, label-column plus input-column forms
WeaknessAfter flex-wrap, rows know nothing about each other, so nothing lines upYou must plan the cells; restructuring is more work

Follow-up: “Can you use both?” — using both is the normal answer: Grid for the page skeleton, Flex for the contents of each cell. Saying “pick one” suggests you have not shipped much.

They will also ask what flex: 1 means: it is shorthand for flex-grow: 1; flex-shrink: 1; flex-basis: 0% — “I take the leftover space, I may be compressed, and my starting size counts as zero”. That is the shortest way to write “fixed sidebar plus fluid main area”.

CSS实际项目里的分工示意Illustrative
1/* Grid 搭骨架 */
2.layout {
3 display: grid;
4 grid-template-columns: 240px 1fr; /* 侧栏固定,主体吃剩下的 */
5 grid-template-rows: 56px 1fr;
6 min-height: 100vh;
7}
8
9/* 格子内部用 Flex 排内容 */
10.topbar {
11 display: flex;
12 align-items: center;
13 justify-content: space-between;
14 gap: 12px;
15}
16
17/* 「固定宽 + 自适应」的经典两行 */
18.sidebar { flex: 0 0 240px; } /* 不长不缩,就 240 */
19.content { flex: 1; } /* 剩下全归我 */
1/* Grid for the skeleton */
2.layout {
3 display: grid;
4 grid-template-columns: 240px 1fr; /* sidebar fixed, main takes the rest */
5 grid-template-rows: 56px 1fr;
6 min-height: 100vh;
7}
8
9/* Flex for the content inside a cell */
10.topbar {
11 display: flex;
12 align-items: center;
13 justify-content: space-between;
14 gap: 12px;
15}
16
17/* The classic two lines for "fixed width plus fill the rest" */
18.sidebar { flex: 0 0 240px; } /* never grows, never shrinks, stays 240 */
19.content { flex: 1; } /* takes everything that is left */
CSSCSS#383

CSS 选择器有哪些类型

What are the different types of CSS selectors?

看答案Show answer

一句话:按「选中什么」分五类 —— 基础、组合、属性、伪类、伪元素。

  • 基础:标签 div、 类 .card、id #app、 通用 *
  • 组合:后代 a b(空格)、 直接子元素 a > b、 紧邻兄弟 a + b、 后面所有兄弟 a ~ b
  • 属性[type="text"][href^="https"](开头)、[class*="btn"](包含)
  • 伪类(状态)::hover:focus:nth-child(2n):not(.on):disabled
  • 伪元素(造出不存在的元素):::before::after::placeholder::selection

会追问优先级怎么算—— 这才是真考点。按三位数比大小(id, class, 标签),从左往右比,高位一个也顶不过低位一万个

选择器(id, class, 标签)
div p0, 0, 2
.card p0, 1, 1
.card.on0, 2, 0
#app p1, 0, 1 ← 赢过上面所有

伪类算一个 class,伪元素算一个标签,:not() 本身不算分但括号里的算。 行内 style 比任何选择器都高,!important 再高一层 ——但别把 !important 当解法, 它通常说明选择器设计已经失控了。

同分怎么办?后写的赢。 这就是为什么覆盖第三方样式时, 把自己的 CSS 放在后面加载往往就够了。

In one line: five families, grouped by what they select — basic, combinator, attribute, pseudo-class, pseudo-element.

  • Basic: type div, class .card, id #app, universal *
  • Combinators: descendant a b (space), direct child a > b, adjacent sibling a + b, all following siblings a ~ b
  • Attribute: [type="text"],[href^="https"] (starts with),[class*="btn"] (contains)
  • Pseudo-classes (state): :hover,:focus, :nth-child(2n),:not(.on), :disabled
  • Pseudo-elements (invent an element):::before, ::after,::placeholder, ::selection

The real question is specificity. Compare three numbers — (id, class, type) — left to right, and one high digit beats ten thousand low ones:

Selector(id, class, type)
div p0, 0, 2
.card p0, 1, 1
.card.on0, 2, 0
#app p1, 0, 1 ← beats all of the above

A pseudo-class counts as a class, a pseudo-element as a type, and :not() itself scores nothing but its argument does. Inline style outranks any selector, and !important outranks that — but do not treat !important as a solution; it usually means your selector design has already gone out of control.

What if they tie? The one written later wins. That is why loading your own CSS after a third-party stylesheet is often all you need.

CSSCSS#270

有几种方式引入 CSS

How many ways to import CSS in your project

看答案Show answer

一句话:传统上三种 —— 行内 style 属性、页内<style> 标签、外部<link> 文件(外加 CSS 里的@import)。

但面试问这题,其实想听你说现代工程里的做法:

  • 普通 import——import "./styles.css", 打包工具接管,全局生效。
  • CSS Modules——import s from "./x.module.css", 类名自动加哈希,天然不冲突
  • CSS-in-JS(styled-components、emotion)—— 样式写在 JS 里,能用 props 做条件样式。 代价是运行时开销。
  • 原子化(Tailwind)—— 不写 CSS,直接堆预设类名。

会追问:「为什么不推荐 @import?」—— 因为它是串行的: 浏览器要先下载并解析外层 CSS, 才发现里面还有个 @import,再去下载。 这形成了一条请求链,直接拖慢首屏。 构建工具里的 @import 是编译期合并的, 不算这个问题 —— 说清这个区别是加分项。

In one line: traditionally three — an inline style attribute, an in-page <style> tag, an external file via <link> (plus@import from within CSS).

But what the interviewer wants is how it is done in a modern build:

  • Plain import import "./styles.css"; the bundler takes over, styles are global.
  • CSS Modules import s from "./x.module.css"; class names are hashed, so collisions are impossible by construction.
  • CSS-in-JS (styled-components, emotion) — styles live in JS, so props can drive them. The cost is runtime work.
  • Atomic (Tailwind) — you do not write CSS, you compose preset class names.

Follow-up: “Why is @import discouraged?” — because it is serial: the browser must download and parse the outer stylesheet before it even discovers the@import, then fetch again. That request chain delays first paint. @import handled by a build tool is merged at compile time and does not have this problem — pointing out that distinction is what earns the marks.

CSSCSS#275

什么是 SCSS

What is SCSS

看答案Show answer

一句话:SCSS 是 Sass 的一种语法,CSS 的超集—— 合法的 CSS 就是合法的 SCSS, 但它多了变量、嵌套、mixin、函数这些编程能力, 最后编译成普通 CSS。

Sass 和 SCSS 什么关系?同一个工具的两种写法:.sass 靠缩进、没有大括号和分号;.scss 长得像 CSS。现在基本都用 .scss, 因为可以直接把老 CSS 粘进来。

核心能力四个:变量($brand: #2b6)、 嵌套(层级关系一眼看出来)、@mixin / @include(复用一组声明,可传参)、@use 拆文件。

会追问(这题真正想考的):「现在还需要它吗?」—— 老实说,需求少了很多: 变量被原生 CSS 自定义属性--brand)取代,而且原生的能在运行时改、 能被 JS 读写、能跟着主题切换,比 SCSS 变量更强(本站的深色模式就是这么做的)。 嵌套也已经进了 CSS 标准。
剩下真正还有价值的是 mixin 和循环生成。 能这么答说明你知道边界在哪。

In one line: SCSS is one of Sass’s two syntaxes and a superset of CSS — valid CSS is valid SCSS — but it adds variables, nesting, mixins and functions, and compiles down to plain CSS.

Sass vs SCSS? Two syntaxes for the same tool:.sass is indentation-based with no braces or semicolons;.scss looks like CSS. .scss is what everyone uses now, because you can paste existing CSS straight in.

Four core abilities: variables ($brand: #2b6), nesting (hierarchy visible at a glance),@mixin / @include (reuse a group of declarations, with arguments), and @use for splitting files.

The follow-up this question really exists for: “Do you still need it?” — honestly, much less. Variables have been superseded by native CSS custom properties (--brand), and the native ones are strictly more capable: they live at runtime, JS can read and write them, and they follow theme switches (this site’s dark mode works exactly that way). Nesting has landed in the CSS standard too.
What genuinely remains valuable is mixins and generated loops. Answering this way shows you know where the boundary is.

CSS为什么原生变量更强示意Illustrative
1/* SCSS 变量:编译期就被替换掉,运行时改不了 */
2$brand: #2b6cb0;
3.btn { background: $brand; }
4
5/* 原生自定义属性:运行时活着,JS 能改,能被主题覆盖 */
6:root { --brand: #2b6cb0; }
7[data-theme="dark"] { --brand: #90cdf4; } /* 换主题只改这一行 */
8.btn { background: var(--brand); }
1/* An SCSS variable is replaced at compile time and cannot change at runtime */
2$brand: #2b6cb0;
3.btn { background: $brand; }
4
5/* A native custom property is alive at runtime: JS can change it, a theme can override it */
6:root { --brand: #2b6cb0; }
7[data-theme="dark"] { --brand: #90cdf4; } /* switching theme changes only this line */
8.btn { background: var(--brand); }
CSSCSS#384

CSS 预处理器的优缺点

What is a CSS preprocessor? What are the advantages and disadvantages, if any, to using them over plain CSS?

看答案Show answer

一句话:预处理器是「用一种更强的语言写样式, 再编译成 CSS」。Sass / Less / Stylus 都是。

好处:变量集中管理、嵌套让结构清晰、 mixin 复用、能循环生成(比如 .mt-1.mt-10)、能拆成很多小文件再合并。

代价(面试重点问这半边):

  • 多一步构建。多一个依赖、多一份配置、 多一处可能出错的地方。
  • 嵌套太容易写深。一不注意就写出 .a .b .c .d span, 优先级越滚越高,最后只能靠!important 收场。这是预处理器最真实的坑—— 实践里一般限制自己不超过三层。
  • 调试要靠 source map。DevTools 里看到的是编译产物,行号对不上。
  • 门槛。新人得先学一套额外语法。

结论怎么说:「大项目、有设计系统、需要批量生成样式时值得; 小项目用原生 CSS 加自定义属性就够,因为它当年解决的两个主要问题(变量、嵌套) 原生已经支持了。」 —— 有取舍的回答比一味夸好。

In one line: a preprocessor lets you write styles in a more capable language and compiles them to CSS. Sass, Less and Stylus all qualify.

Upsides: variables in one place, nesting that makes structure obvious, mixins for reuse, loops that generate families of rules (.mt-1 through .mt-10), and splitting into many small files that get merged.

Costs — this is the half they probe:

  • An extra build step. One more dependency, one more config, one more place things break.
  • Nesting is far too easy to over-use. Before you notice you have written .a .b .c .d span, specificity keeps climbing, and the only way out is !important. This is the preprocessor’s most real trap — in practice teams cap themselves at about three levels.
  • Debugging needs source maps. DevTools shows you the compiled output and the line numbers do not match.
  • Onboarding cost. Newcomers must learn extra syntax.

How to land the conclusion: “Worth it on large projects with a design system and lots of generated styles; for small projects plain CSS plus custom properties is enough, because the two problems it originally solved — variables and nesting — are now native.” A weighed answer beats unconditional praise.

这些题从哪来Where these come from

99 道来自面试题库 #269–#387;TypeScript 深度那 6 道是 DrillLab 自出的(senior 补强,卡片上有标注)。答案都是 DrillLab 写的,所以讲解里的代码块一律标「示意」。每道题都能点回它出处的那一节课。99 questions come from the interview bank (#269–#387); the 6 TypeScript deep-dive ones are DrillLab-made (marked on the card). All answers are written by DrillLab, so every code block here is labelled “demo”. Each card links back to the lesson it came from.