Skip to content

HTML 与 CSS ​

1. Tailwind 的响应式断点(如 md:)底层如何实现? ​

答案:

Tailwind 的响应式前缀本质上是媒体查询变体。构建时,Tailwind 扫描源码中的类名,把 md:flex 之类的候选类编译为带转义选择器的 CSS,并包进对应断点的 @media:

css
@media (width >= 48rem) {
  .md\:flex { display: flex; }
}

默认断点采用移动优先的 min-width 语义:无前缀样式作用于所有宽度,sm:、md: 等从断点开始覆盖,而不是表示“仅在该尺寸”。例如 block md:flex 在小屏是块布局,到 md 及以上变为 Flex。具体断点值取决于 Tailwind 版本和项目主题配置,不应在业务代码中假定它永远是某个固定像素值。

多个响应式前缀还可以和状态、容器查询等变体组合,如 md:hover:bg-blue-500。最终是否生效仍由普通 CSS 的媒体条件和层叠规则决定;Tailwind 只是在构建阶段生成对应规则。

2. Tailwind 是怎么解决样式冲突的? ​

答案:

Tailwind 不能消除 CSS 层叠冲突,它通过一套稳定、可预测的生成规则降低冲突概率:

  • 工具类通常只负责少量声明,选择器大多是单个类,特异性保持一致。
  • theme 统一颜色、间距和断点等设计令牌,减少随意值。
  • base、components、utilities 等层控制不同类别规则的优先顺序;同层再按 Tailwind 的生成顺序参与层叠。
  • 响应式、状态等变体把规则放入相应媒体查询或伪类选择器中,使覆盖条件明确。
  • 只生成扫描到的候选类,避免一份庞大全局样式表中大量偶然命中。

要特别注意,class='p-2 p-4' 中类名的书写顺序通常不决定胜负,决定结果的是生成后 CSS 规则的层叠顺序。因此不要依赖冲突工具类共存;条件拼接类名时应保证同一属性只保留一个类,必要时可在组件封装层使用 tailwind-merge 合并冲突类。自定义样式优先用 @layer 放入合适层级,!important 只作为明确的例外。

3. 怎么实现一个固定宽高比(如16:9)的容器 ​

答案:

现代浏览器直接使用 aspect-ratio:

css
.media {
  width: 100%;
  aspect-ratio: 16 / 9;
}

.media > img,
.media > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

当只确定宽度时,浏览器会据此计算首选高度;若同时设置了确定的 width 和 height,确定尺寸会优先,比例不再决定最终大小。内容的最小尺寸也可能把容器撑开,可按场景配合 overflow: hidden、min-height: 0。

兼容旧浏览器时可用百分比内边距,因为垂直方向的百分比 padding 按包含块宽度计算:

css
.media { position: relative; height: 0; padding-top: 56.25%; }
.media > * { position: absolute; inset: 0; width: 100%; height: 100%; }

56.25% = 9 / 16。优先使用 aspect-ratio,回退方案主要用于确有旧环境要求的项目。

4. SPA和MPA的区别? ​

答案:

**SPA(单页应用)**通常只首次加载一个 HTML 外壳,后续路由由前端接管,通过 Fetch/Ajax 获取数据并局部更新页面。页面切换流畅,客户端状态容易保留,适合后台系统、交互复杂的应用;代价是首屏资源和前端复杂度可能更高,需要额外处理路由、数据缓存、SEO、错误恢复和代码分包。SSR/SSG 可以改善首屏与 SEO,但它仍可在激活后表现为 SPA。

**MPA(多页应用)**的每个页面通常有独立 URL 和 HTML 文档,导航会向服务器请求新文档并重新执行页面生命周期。它天然适合内容站、多个相对独立的业务页面,SEO、渐进增强和故障隔离通常更直接;缺点是跨页切换会重载资源,跨页状态和统一交互需要额外设计。

二者不是“前后端分离”和“服务端渲染”的同义词。选择时主要看交互连续性、SEO/首屏要求、团队复杂度承受能力和页面之间的耦合程度,也可以采用局部 SPA、MPA 加岛屿组件等混合架构。

5. 常见的H5标签有哪些 ,你是怎么用的 ​

答案:

常说的 H5 标签主要是 HTML5 引入或普及的语义化、媒体和表单能力:

  • 页面结构:header、nav、main、section、article、aside、footer。
  • 内容语义:figure、figcaption、time、mark、details、summary。
  • 媒体与图形:audio、video、source、track、canvas、svg。
  • 表单:datalist、output、progress、meter,以及 email、date、number 等输入类型。
  • 复用与弹层:template、dialog。

使用原则是按内容含义选标签,而不是按默认样式选。例如站点唯一主体用 main,可独立分发的内容用 article,一组有主题标题的内容可用 section;仅为布局且没有语义时仍用 div。正确语义有利于可访问性、SEO 和维护,但不能用 section 取代所有 div,也不要仅靠标签而省略正确的标题层级、表单 label、图片替代文本和键盘交互。

6. 你都了解哪些 CSS 布局技术?它们各自的特点和适用场景是什么? ​

答案:

常见 CSS 布局技术及适用场景如下:

  • 普通文档流:块级元素纵向、行内内容按行排列,是文章、表单等线性内容的基础,语义和自适应最好。
  • Flexbox:以一个主轴为核心的一维布局,擅长导航栏、工具栏、卡片行、居中以及未知尺寸的空间分配。可以换行,但复杂二维对齐通常不如 Grid。
  • Grid:同时控制行和列的二维布局,适合页面骨架、仪表盘和规则网格;minmax()、auto-fit 等可实现强大的响应式布局。
  • 定位:relative/absolute/fixed/sticky 适合角标、弹层、吸顶和覆盖关系。绝对/固定定位会脱离常规流,不宜承担主体自适应布局。
  • 浮动:核心用途是让文字环绕图片;历史上可做多栏,但现代页面布局更适合 Flex/Grid。
  • 多列布局:column-count/column-width 让连续文本自动分栏,适合报刊式内容,不适合要求精确行列对应的组件。
  • 表格布局:真正的二维表格数据应使用 table;display: table 可兼容旧布局,但新项目一般不作为首选。

实际项目通常组合使用:Grid 定页面区域,Flex 排组件内部,普通流承载内容,定位只处理局部叠放。选择标准是内容维度、换行方式、源代码顺序、响应式要求和可访问性,而不是只看能否“摆出来”。

7. 说说你对原子化 CSS 的了解 ​

答案:

原子化 CSS(Atomic/Utility-first CSS)把样式拆成职责很小、可组合的工具类,例如 flex、mt-4、text-center。开发者在标记中组合这些类,而不是为每个组件另写一组语义类。Tailwind、UnoCSS 都属于常见实现。

主要优点:

  • 规则高度复用,新增页面时 CSS 体积增长较慢;按需生成还能只输出实际用到的类。
  • 样式作用范围直观,减少命名和全局级联冲突。
  • 通过受约束的间距、颜色等令牌提高设计一致性。
  • 修改标记即可完成多数响应式和状态样式,减少在 HTML 与 CSS 文件之间跳转。

代价是类名较长、标记更密集,复杂组件可能出现重复组合;动态拼接出构建器无法识别的类名还会导致样式未生成。通常用组件封装重复结构,用条件类名工具维护分支,并保留少量组件 CSS 处理复杂选择器、关键帧或第三方覆盖。

它不等于内联样式:工具类仍是共享 CSS 规则,支持伪类、媒体查询和设计令牌,也仍参与正常层叠。

8. position 的 sticky 有什么应用场景? ​

答案:

position: sticky 适合元素先随文档滚动,到达阈值后在所属滚动容器内保持可见,例如表头、侧栏目录、分组标题、移动端操作栏。

css
.toc {
  position: sticky;
  top: 16px;
  align-self: start;
}

它可以理解为 relative 与受约束的吸附定位:元素仍占据原来的布局空间;滚动到 top: 16px 后吸附,但不会越过包含块的边界。至少要给对应方向设置非 auto 的偏移量,如 top。

常见失效原因包括:祖先创建了预期之外的滚动容器(如设置 overflow: auto/hidden/scroll)、滚动容器没有可滚动空间、父容器高度不足,或 Flex/Grid 的拉伸使 sticky 元素与容器等高。遮挡时还需设置背景和合适的 z-index。它不是全局 fixed 的替代品;需要始终相对视口固定时应使用 position: fixed。

9. 说说你对 CSS 变量的了解 ​

答案:

CSS 变量的正式名称是自定义属性。用 --name 声明,用 var() 读取:

css
:root { --brand: #1769aa; --space: 8px; }
.button { color: var(--brand); padding: calc(var(--space) * 2); }
.panel { color: var(--panel-color, #222); }

它与预处理器变量的关键区别是:自定义属性保留在最终 CSS 中,在计算值阶段参与层叠和继承,可被媒体查询、主题类、元素行内样式或 JavaScript 动态修改。默认会继承,因此很适合设计令牌、主题和组件参数。回退值只在变量未定义或值无效时使用,不代表浏览器不支持某个普通属性。

自定义属性的值本质上是一段 token,使用处必须能组成该属性的合法值;变量引用还可能形成循环并导致值失效。需要类型、初始值或禁止继承时可用 @property 注册:

css
@property --progress {
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}

JavaScript 可通过 style.setProperty('--brand', value) 修改。大量高频更新仍要考虑它触发的样式计算范围。

10. 浏览器是怎么解析 HTML 文档的? ​

答案:

浏览器会以流式方式解析 HTML,大致过程是:

  1. 根据响应头、BOM 等确定字符编码,把字节解码成字符。
  2. tokenizer 按 HTML 状态机把字符转成开始标签、结束标签、文本、注释等 token。
  3. tree builder 根据插入模式和 HTML 内容模型构造 DOM。HTML 有明确的错误恢复规则,所以非法嵌套可能被自动补全、关闭或重排,最终 DOM 不一定等于源码字面结构。
  4. 遇到外部资源时发起请求。预加载扫描器可能提前发现后续资源,但实际行为由浏览器实现决定。

普通外部脚本默认会暂停 HTML 解析,等待脚本下载并执行,因为脚本可能调用 document.write() 或修改当前 DOM;defer 在文档解析完成后按顺序执行,async 下载完即执行且不保证顺序。模块脚本默认具有类似 defer 的执行时机。CSS 通常不阻塞 DOM 的继续构建,但会阻塞渲染,并可能间接等待需要读取样式的脚本。

HTML 得到 DOM,CSS 得到 CSSOM;浏览器结合二者生成渲染树,随后布局、绘制和合成。DOM 解析完成触发 DOMContentLoaded,图片等依赖资源完成后才触发 load。

11. gap 属性是用来设置什么的? ​

答案:

gap 用来设置布局项目之间的间距,适用于 Grid、Flex 和多列布局。它是 row-gap 与 column-gap 的简写:

css
.list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 20px; /* 行间距 列间距 */
}

只有一个值时行列间距相同。与给子元素设置 margin 相比,gap 只出现在项目之间,不会在容器外沿额外产生空白,也不需要为首尾项清除 margin。

在单行 Flex 中,实际可见的是沿主轴的项目间距;发生换行后另一方向的 gap 才体现为行间距。gap 不会自动缩小项目以保证容纳,项目总尺寸加间距超出容器时仍可能溢出或触发 Flex 收缩。

12. 怎么实现一段文字颜色渐变的效果? ​

答案:

可以把渐变绘制为文字背景,再把背景裁剪到字形:

css
.gradient-text {
  color: #1769aa; /* 不支持裁剪时的回退 */
  background: linear-gradient(90deg, #e53935, #8e24aa, #1565c0);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

linear-gradient() 生成背景图,background-clip: text 只在文字轮廓内显示它,透明文字让背景可见。部分 WebKit 环境仍需要前缀。也可以使用 color: transparent,但保留一个先声明的实体色有利于不支持该能力时降级。

渐变色要保证各位置与背景有足够对比度;正文大段使用会降低可读性,更适合标题或短文本。若文字需要换行并希望每行分别重复渐变,可再根据效果选择 box-decoration-break 或为各行建立独立元素。

13. 怎么让页面上的某块区域全屏展示? ​

答案:

真正进入浏览器全屏应使用 Fullscreen API,并由用户手势触发:

js
const panel = document.querySelector('#panel');

async function enterFullscreen() {
  if (!document.fullscreenElement) {
    await panel.requestFullscreen();
  }
}

async function exitFullscreen() {
  if (document.fullscreenElement) {
    await document.exitFullscreen();
  }
}

document.addEventListener('fullscreenchange', () => {
  panel.classList.toggle('is-fullscreen', !!document.fullscreenElement);
});

可用 :fullscreen 设置进入全屏后的样式。requestFullscreen() 返回 Promise,可能因没有瞬时用户激活、权限策略或平台限制而拒绝,因此要捕获错误。跨源 iframe 中还需要通过 allow='fullscreen' 等方式授予权限。用户可按 Esc 退出,业务不能阻止。

如果只是让区域铺满视口而不进入系统全屏,可用 position: fixed; inset: 0; width: 100%; height: 100dvh;。这仍保留浏览器界面,与 Fullscreen API 的含义不同。

14. 怎么在页面上获取用户的定位信息? ​

答案:

使用浏览器 Geolocation API。它只在安全上下文(通常是 HTTPS;本地开发环境例外)中可用,并且必须由用户授权:

js
function locate() {
  if (!('geolocation' in navigator)) {
    throw new Error('当前浏览器不支持定位');
  }

  navigator.geolocation.getCurrentPosition(
    ({ coords, timestamp }) => {
      console.log({
        latitude: coords.latitude,
        longitude: coords.longitude,
        accuracy: coords.accuracy,
        timestamp
      });
    },
    (error) => {
      console.error(error.code, error.message);
    },
    { enableHighAccuracy: false, timeout: 10000, maximumAge: 60000 }
  );
}

getCurrentPosition 获取一次;持续跟踪用 watchPosition,结束时调用 clearWatch(id)。定位来源可能是 GPS、Wi-Fi、基站或 IP,accuracy 是以米为单位的估计精度,不能假定坐标绝对准确。

应在明确说明用途后再请求权限,处理拒绝、超时和不可用状态,并尽量降低精度、频率与保存时间。权限被拒后不能反复弹窗强求,通常应提供手动选择城市或地址的降级方案。

15. html 中有哪些常见的实体字符? ​

答案:

HTML 字符引用用于表示在 HTML 中有语法含义、难以直接输入或希望明确表达的字符。常见写法有:

字符引用显示字符常见用途
&lt;<文本中的小于号,避免被当成标签起始
&gt;>大于号
&amp;&文本或属性值中的与号
&quot;"双引号
&apos;'单引号
&nbsp;不换行空格阻止该空格处换行
&copy;©版权符号
&reg;®注册商标
&times;×乘号

还可以使用十进制或十六进制数字引用,如 &#169;、&#xA9;。现代 UTF-8 文档可直接书写大多数普通字符,不必全部转义;但 & 和会被解释为标记的 < 等字符应按上下文转义。实体编码也不是防止 XSS 的固定方案,输出用户数据时必须按 HTML 文本、属性、URL、JavaScript 等具体上下文采用正确编码。

16. html 文档中常见的   是什么,有什么作用? ​

答案:

&nbsp; 是 HTML 命名字符引用,解析后得到 Unicode 的不换行空格 U+00A0。它主要有两个效果:

  • 在该空格处不允许自动换行,可让数字与单位、姓名等短组合保持在同一行。
  • 在普通的空白折叠规则下,它不会像连续普通空格那样被合并,因此多个 &nbsp; 看起来能形成额外空白。

但不应靠堆叠 &nbsp; 做缩进、对齐或布局,这会破坏响应式排版和可访问性,应使用 margin、padding、gap、Grid/Flex 或 text-indent。若只需防止一整段换行,也可考虑 white-space: nowrap;需要允许在特定位置换行时可使用普通空格或 <wbr>,应按文本语义选择。

17. 说说你对 html 嵌套规则的了解 ​

答案:

HTML 能否嵌套由元素的内容模型决定,不能简单概括为“块元素不能放进行内元素”。常见规则包括:

  • ul/ol 的直接子元素通常应为 li;dl 使用 dt/dd;table 内应遵循 caption、thead/tbody/tfoot、tr、th/td 的结构。
  • p 只能包含短语内容,放入 div、另一个 p 等元素时,解析器会自动结束前一个 p。
  • a 可以包裹流式内容,但不能包含另一个 a;button 也不能嵌套链接、按钮等交互内容,避免焦点和点击语义冲突。
  • header、footer、main 等语义元素还有各自的祖先或后代限制。
  • img、input、br、meta、link 等 void 元素不能有子节点,也不写结束标签。

浏览器会对错误标记执行容错修复,因此“页面看起来正常”不代表结构合法,脚本拿到的 DOM 甚至可能与源码层级不同。应使用语义正确的父子关系并借助 HTML 校验器检查。display: block/inline/flex 是 CSS 布局行为,通常不会改变元素本身的 HTML 内容模型。

18. 如何使用 JavaScript 控制 <audio> 和 <video> 元素? ​

答案:

audio 和 video 都实现 HTMLMediaElement 接口,可以通过同一组属性、方法和事件控制:

js
const media = document.querySelector('video');

async function play() {
  try {
    await media.play();
  } catch (error) {
    console.error('播放被阻止或资源不可用', error);
  }
}

media.pause();
media.currentTime = 30;
media.volume = 0.5;       // 0~1
media.muted = true;
media.playbackRate = 1.25;

media.addEventListener('timeupdate', () => {
  console.log(media.currentTime, media.duration);
});
media.addEventListener('ended', () => console.log('播放结束'));

常用状态包括 paused、duration、buffered、readyState,常用事件包括 loadedmetadata、canplay、play、pause、seeking、timeupdate、volumechange、error。可保留原生 controls,也可用这些 API 实现自定义控件。

play() 返回 Promise;浏览器通常禁止没有用户手势的有声自动播放,静音自动播放也仍受平台策略影响。自定义控件必须补齐键盘操作、焦点、可访问名称、字幕入口和错误/加载状态,不能只实现鼠标点击。

19. html 中的视频,怎么添加字幕? ​

答案:

使用 <track> 为 <video> 关联 WebVTT 字幕文件:

html
<video controls src='movie.mp4'>
  <track
    kind='subtitles'
    src='subtitles-zh.vtt'
    srclang='zh-CN'
    label='中文'
    default
  >
  <track
    kind='subtitles'
    src='subtitles-en.vtt'
    srclang='en'
    label='English'
  >
</video>

WebVTT 文件示例:

vtt
WEBVTT

00:00:01.000 --> 00:00:04.000
欢迎观看本视频。

kind='subtitles' 表示语言翻译字幕;包含对白及声音提示、面向听障用户的字幕通常用 kind='captions'。srclang 声明字幕语言,label 是字幕菜单中的可读名称,default 表示默认启用候选。

字幕文件要以正确 MIME 类型提供;跨源加载时,视频/轨道服务器还要正确配置 CORS。脚本可通过 video.textTracks 控制轨道的 mode,但优先保留浏览器原生字幕选择能力。

20. 未知高度和宽度元素的水平垂直居中的方案有哪些, 简单手写一下? ​

答案:

元素宽高未知时,首选 Flex 或 Grid,它们不依赖子元素尺寸。

Flex:

css
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

Grid:

css
.parent {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

需要让元素脱离文档流、覆盖在容器中央时,可以用定位加变换:

css
.parent { position: relative; }
.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

50% 定位以包含块尺寸为基准,translate(-50%, -50%) 以元素自身尺寸为基准,所以无需知道宽高。

若只居中单个 Grid 子项,也可在父级 display: grid 后给子项 margin: auto。主体布局应优先 Flex/Grid;绝对定位会脱离文档流,父容器不会被它撑高,更适合弹层、角标等叠加场景。使用 100vh 时移动端通常可按需求改为 100dvh。

21. 浏览器如何解析css选择器? ​

答案:

浏览器先把 CSS 选择器解析成内部结构,在样式计算时为 DOM 元素寻找匹配规则。对于后代选择器 .nav ul li a,匹配通常从最右侧的关键选择器 a 开始筛选候选元素,再沿祖先方向检查 li、ul、.nav;这样能尽早排除大量节点。引擎还会利用 id、class、标签等索引和失效规则优化,具体算法属于浏览器实现,并非规范要求它必须机械地逐字符“从右向左”。

规则匹配成功后,浏览器再根据来源、重要性、级联层、特异性和源码顺序等层叠规则决定最终声明,继承则为未直接指定的可继承属性补值。DOM、class、属性或样式表变化会使受影响元素重新进行样式计算。

性能上应优先清晰、可维护的选择器。过深后代链、宽泛通配符和依赖大量祖先状态的选择器可能扩大匹配或样式失效范围,但现代浏览器对常见选择器已有成熟优化,通常应先用性能工具确认瓶颈,不必为了所谓“从右向左”把所有规则都改成单类选择器。

22. CSS 尺寸单位有哪些? ​

答案:

CSS 尺寸单位可按参照物分类:

  • 绝对单位:px、cm、mm、Q、in、pt、pc。屏幕上的 px 是 CSS 像素,不一定等于一个物理像素;物理单位在屏幕上也未必对应真实尺子长度。
  • 字体相对单位:em 相对当前元素计算后的字号(用于 font-size 时相对父元素),rem 相对根元素字号;ex、ch、cap、ic 参考字体字形;lh、rlh 参考行高。
  • 视口单位:vw、vh、vmin、vmax;svh/lvh/dvh 等分别对应小、大、动态视口,更适合处理移动端地址栏变化。
  • 容器查询单位:cqw、cqh、cqi、cqb、cqmin、cqmax,相对查询容器尺寸。
  • 百分比 %:相对值,参照对象由属性决定。例如 width 通常相对包含块宽度,百分比 padding 也以包含块的行内尺寸为基准,不能一概而论。
  • Grid 弹性单位 fr:分配 Grid 容器扣除固定轨道和间距后的剩余空间,不是通用长度单位。

实践中字号常用 rem,局部比例用 %/em,边框和精确小尺寸用 px,响应式布局结合 %、Grid/Flex、容器或视口单位。不要单纯依赖视口单位缩放所有文字,还要保证缩放和可访问性。

23. css 中三栏布局的实现方案有哪些? ​

答案:

假设左右栏固定、中间栏自适应,现代实现首选 Grid:

css
.layout {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr) 240px;
  gap: 16px;
}

minmax(0, 1fr) 允许中栏缩小,避免长内容把网格撑破。响应式时可通过媒体查询改为一列。

Flex 也很合适:

css
.layout { display: flex; gap: 16px; }
.left  { flex: 0 0 200px; }
.main  { flex: 1 1 auto; min-width: 0; }
.right { flex: 0 0 240px; }

min-width: 0 允许中栏小于其内容的最小宽度。若要求中栏在 HTML 中最先出现,可用 Grid 区域或 Flex 的 order 做视觉排列,但要注意键盘焦点和读屏顺序仍按 DOM,最好让源码顺序本身符合语义。

传统方案还有浮动、圣杯/双飞翼布局、绝对定位和 display: table。浮动方案需清除浮动,绝对定位又无法自然撑开父容器;它们主要用于维护旧项目,新代码通常选择 Grid 或 Flex。

24. CSS 中的文档流是什么? ​

答案:

文档流通常指元素在没有特殊脱离规则时,按照书写顺序和格式化上下文参与尺寸计算与位置排列的机制。普通流中,块级盒通常沿块轴依次排列,行内内容组成行盒;后面的元素会基于前面元素占据的空间继续布局。

不同属性对文档流的影响:

  • position: relative 仍保留原占位,只是视觉位置可偏移。
  • position: sticky 也保留占位,只在滚动达到阈值后受约束地偏移。
  • position: absolute/fixed 脱离普通流,不再占据原位置,通常也不会撑开父元素。
  • 浮动元素脱离普通的块级排列,但仍会影响周围行内内容环绕,并影响相关高度计算。
  • transform 只改变绘制结果,通常不重新安排其他元素的位置。
  • Flex 和 Grid 项目仍参与父容器布局,只是父容器建立了不同于普通块流的格式化上下文。

理解文档流的关键是区分“是否占位”和“视觉上是否移动”。主体结构应尽量依赖正常布局,让内容增减时能自然推开相邻元素。

25. 如何避免重绘或者重排? ​

答案:

重排(layout/reflow)会重新计算元素几何信息,通常还会导致后续绘制;重绘(paint)只更新像素外观,不一定改变布局。它们无法完全避免,优化目标是减少次数和影响范围:

  • 批量修改 DOM 或 class,避免在循环中逐项改完就读取布局。可先在内存中构造节点,或一次性插入 DocumentFragment。
  • 避免布局抖动:不要交替执行 offsetWidth/getBoundingClientRect() 等布局读取和 style 写入;先集中读,再集中写。动画写入可放进 requestAnimationFrame。
  • 动画优先使用 transform、opacity,它们通常可由合成阶段处理;动画 width、height、top 等更容易触发布局或绘制。
  • 为图片、视频、广告预留稳定尺寸,减少加载后的布局偏移。
  • 用 contain、content-visibility 等限制大型独立区域的布局和绘制影响,但要评估可访问性、尺寸估算与粘性定位等副作用。
  • 高频 scroll/resize/input 逻辑按需求节流或合并,避免每个事件都进行昂贵计算。
  • will-change 只对即将发生的动画短期使用;长期、批量滥用会增加内存和合成成本。

最终应通过浏览器 Performance、Rendering 工具确认 Style、Layout、Paint 和 Composite 的实际耗时,因为不同属性、图层与浏览器的优化结果并不完全相同。

26. 说下 css 中的 BFC、IFC、GFC 和 FFC 分别指什么? ​

答案:

它们都是盒子参与布局时形成的格式化上下文:

  • BFC,块级格式化上下文:内部块盒按块方向排列。独立 BFC 会包含内部浮动,外部浮动不会侵入其布局,并且其内部与外部块的垂直 margin 不会相互折叠。常见创建方式有 display: flow-root、浮动、绝对定位、非 visible/clip 的 overflow、Flex/Grid 项等。清除浮动时优先用语义直接的 flow-root。
  • IFC,行内格式化上下文:块容器中的行内内容形成一个个行盒,受字体、line-height、vertical-align、text-align、换行规则等影响。它是普通文本排版的基础。
  • GFC,网格格式化上下文:display: grid/inline-grid 建立,直接子元素成为 Grid 项,在显式或隐式网格的行列轨道中布局,可精确控制二维区域、对齐和间距。
  • FFC,弹性格式化上下文:display: flex/inline-flex 建立,直接子元素成为 Flex 项,围绕主轴分配空间,并在交叉轴对齐,适合一维布局。

Flex/Grid 容器内的项目遵循各自算法,项目 margin 不会像普通块流那样折叠,浮动对 Flex/Grid 项本身也不产生传统浮动布局效果。GFC、FFC 是工程中常用的简称,核心是理解不同 display 值建立了不同布局规则。

27. canvas 与 svg 在可视化领域优劣如何 ​

答案:

Canvas 是立即模式的位图画布:JavaScript 发出绘制命令后,图形被栅格化为像素,浏览器不保留每个图元对应的 DOM 节点。它适合高频重绘、粒子、热力图、游戏或数据点非常多的场景。缺点是缩放时要处理设备像素比,否则会模糊;命中检测、局部更新、事件和可访问语义通常都要自行维护。画布内容也不天然可被搜索或选择。

SVG 是保留模式的矢量图形:圆、路径、文本等都是可寻址的节点,缩放保持清晰,可直接用 CSS、DOM、事件和无障碍属性控制。它适合图标、流程图、地图、节点数量适中的交互式图表。缺点是节点极多或每帧大量修改属性时,DOM、样式计算和绘制成本会明显上升。

选择没有固定数量分界,应按设备和交互实测。一般来说,元素较少、需要精细交互和可访问性时优先 SVG;图元海量、整体连续重绘时优先 Canvas。复杂可视化也常混合使用,例如 Canvas 绘数据,SVG/HTML 绘坐标轴、标签与交互控件。两者都可导出,但 Canvas 导出位图很直接,SVG 更适合保留矢量结构。

28. CSS 伪类和伪元素有哪些,它们的区别和实际应用 ​

答案:

伪类选择元素在某种状态、位置或逻辑条件下的表现,使用单冒号,例如:

  • 交互状态::hover、:focus-visible、:active、:checked、:disabled。
  • 结构关系::first-child、:last-child、:nth-child()、:only-of-type。
  • 逻辑与关系::not()、:is()、:where()、:has()。
  • 其他::link、:visited、:target、:valid、:fullscreen。
css
.field:focus-visible { outline: 2px solid #1565c0; }
.card:has(img) { grid-template-columns: 8rem 1fr; }

伪元素选择或生成元素的某个抽象部分,现代语法使用双冒号,例如 ::before、::after、::first-line、::first-letter、::selection、::placeholder、::marker、::file-selector-button。

css
.required::after { content: ' *'; color: #c62828; }
li::marker { color: #1565c0; }

区别是伪类仍匹配真实元素,伪元素针对元素的一部分或生成的盒。二者都无需额外 HTML,但 ::before/::after 的生成内容不应承载关键信息或可交互控件。特异性也有细节:普通伪类按类选择器计,伪元素按类型选择器计;:where() 特异性为零,:is()、:not()、:has() 由参数中最高特异性决定。

29. web components 是什么? ​

答案:

Web Components 是一组浏览器原生的组件化标准,核心包括:

  • Custom Elements:用 customElements.define() 注册带连字符的自定义标签,并通过 connectedCallback、disconnectedCallback、attributeChangedCallback 等生命周期响应变化。
  • Shadow DOM:用 attachShadow() 创建封装的 DOM 子树,隔离大部分内部样式和外部选择器。
  • HTML Template 与 Slot:template 保存惰性 DOM 模板,slot 把使用者提供的内容投射到组件内部。
js
class UserBadge extends HTMLElement {
  connectedCallback() {
    const root = this.attachShadow({ mode: 'open' });
    root.innerHTML = `<style>:host{display:inline-flex}</style><slot></slot>`;
  }
}
customElements.define('user-badge', UserBadge);

它的优势是跨框架、浏览器原生、封装边界明确,适合设计系统和需要被多技术栈复用的组件。组件通过属性、属性值、方法、自定义事件、slot 和 CSS 自定义属性/::part 设计公共 API。

边界也要考虑:Shadow DOM 不是安全边界;全局继承属性和 CSS 变量仍可进入,弹层定位、表单关联、服务端渲染、可访问性及主题能力需要专门设计。框架对象不宜直接塞进属性,复杂数据通常通过 DOM 属性或方法传递。

30. PostCSS 是什么,有什么作用? ​

答案:

PostCSS 是一个用 JavaScript 处理 CSS 的工具平台。它把 CSS 解析为 AST,插件读取或修改这棵树,再输出 CSS 和 source map。PostCSS 本身既不是一种新语法,也不是固定功能的预处理器;能力由插件链决定。

常见用途包括:

  • autoprefixer 根据 Browserslist 给需要的声明添加浏览器前缀。
  • postcss-preset-env 按目标环境转换部分较新的 CSS 特性。
  • CSS Modules 相关插件生成局部化类名。
  • 通过其他插件完成导入处理、代码检查、设计令牌替换或压缩。
  • Tailwind 等工具也可作为 PostCSS 构建链的一部分运行,具体集成方式取决于版本。

典型配置是:

js
export default {
  plugins: {
    autoprefixer: {}
  }
};

插件顺序可能影响结果,例如先展开语法再加前缀通常比反过来合理。选插件时要确认其维护状态和支持的 CSS 语义,不能假设所有“未来 CSS”都能无损转译;像容器尺寸、浏览器布局能力这类运行时特性无法仅靠 AST 改写完整模拟。

31. html 元素节点上, 有多个 class 名称,这几个class 名称对应的样式渲染优先级是如何的? ​

答案:

一个元素有多个 class 时,class 属性中的名称顺序不决定样式优先级。浏览器先找出所有匹配声明,再按 CSS 层叠规则选择结果。可概括为:

  1. 声明是否适用,如媒体条件是否满足。
  2. 来源、!important 和级联层 @layer。
  3. 选择器特异性:一般可理解为内联样式、ID、类/属性/伪类、类型/伪元素几个层级。
  4. 前面仍相同时,样式表中后出现的声明获胜。
html
<div class='red blue'>文字</div>
css
.blue { color: blue; }
.red  { color: red; }

结果是红色,因为 .red 与 .blue 特异性相同,而 .red 在 CSS 中更晚;把 HTML 改成 class='blue red' 结果仍不变。若有 .box.red,它比单个类选择器更具体;行内样式通常又高于普通作者规则,但 !important、动画/过渡、不同来源和级联层还会影响完整顺序。

工程上应控制选择器特异性,利用 @layer 明确第三方、基础和组件样式层级,避免靠不断增加选择器长度或滥用 !important 竞争。

32. 如何避免全局样式污染? ​

答案:

避免全局样式污染的核心是缩小选择器作用域,并明确少量真正全局的规则:

  • 组件项目可使用 CSS Modules、Vue scoped、框架的局部 CSS 或 CSS-in-JS,让类名自动局部化。
  • 跨框架且需要强封装时使用 Shadow DOM;同时用 CSS 自定义属性和 ::part 暴露有意的主题接口。
  • 普通 CSS 采用 BEM、项目命名空间等稳定命名约定,避免 .title、.item 这类过宽的类名。
  • 使用 @layer reset, base, components, utilities, overrides 管理层叠顺序;可用 :where() 提供低特异性的默认样式,便于业务覆盖。
  • 支持目标浏览器时可用 @scope 把一组规则限制在某个 DOM 子树。
  • Reset、字体、主题令牌等全局样式集中在单一入口,只作用于确有必要的元素;引入第三方 CSS 时放入独立层或容器命名空间。

不要用 * 或深层标签选择器给整个页面施加组件细节,也不要让组件依赖不可见的全局祖先样式。局部化解决的是命名和作用域,不会自动解决设计令牌、继承属性、弹层渲染到 body、第三方内联样式等问题,这些仍需通过清晰的样式 API、Portal 容器和层叠策略处理。

33. 什么是 HTML 文档的预解析? ​

答案:

HTML 文档预解析通常指浏览器的预加载扫描器(preload scanner):主 HTML 解析器在顺序构建 DOM 时,可能被同步脚本等资源阻塞;预加载扫描器会继续向后扫描尚未正式解析的标记,提前发现 img、link、script 等标签中的外部资源 URL 并发起请求,从而把网络下载与主解析过程并行化。

它是一种推测性优化,不会代替正式解析、执行脚本或创建 DOM。由 JavaScript 动态生成的 URL、依赖运行时条件的资源通常无法被预解析发现。资源也可能通过 <link rel="preload"> 显式提示浏览器提前加载,但该提示与浏览器内部的文档预解析不是同一个概念。

34. html 中前缀为 data- 开头的元素属性是什么? ​

答案:

data-* 是 HTML 的自定义数据属性,用于在元素上保存与该元素相关、没有合适标准属性可表达的私有数据,例如:

html
<button data-user-id="42" data-loading-state="idle">提交</button>

JavaScript 可通过 element.dataset 读写,属性名会由短横线形式转换为驼峰形式:

js
const button = document.querySelector('button');
console.log(button.dataset.userId); // "42"
button.dataset.loadingState = 'pending';

dataset 中的值都是字符串,赋值 null 也会得到字符串 "null";删除应使用 delete button.dataset.userId。CSS 可以用属性选择器匹配,也可用 attr() 在部分属性值中读取。不要把敏感信息、大量结构化数据或纯展示样式塞进 data-*,因为它会暴露在 DOM 中并增加标记体积。

35. script 标签上有那些属性,作用分别是什么? ​

答案:

<script> 常见属性如下:

  • src:外部脚本地址;存在时,标签内脚本内容不会作为普通脚本执行。
  • type:脚本类型。普通 JavaScript 可省略;type="module" 表示 ES Module;其他 MIME/自定义值可作为数据块。
  • async:脚本下载完成后尽快执行,不保证多个脚本的执行顺序,适合彼此独立的统计脚本。
  • defer:并行下载,在 HTML 解析完成后、DOMContentLoaded 前按文档顺序执行;仅对外部经典脚本有效。
  • nomodule:只在不支持 ES Module 的旧浏览器中执行,常用于现代/旧版构建的降级方案。
  • crossorigin:设置跨源请求的 CORS 凭据模式,常用值为 anonymous 和 use-credentials,也影响跨源脚本错误信息及 SRI。
  • integrity:提供资源摘要,浏览器校验不一致就拒绝执行,即 SRI。
  • referrerpolicy:控制请求脚本时发送的 Referer 信息。
  • nonce:与 CSP 配合,允许本次响应中带匹配随机值的内联脚本执行。
  • fetchpriority:提示浏览器该外部脚本请求的相对优先级。

普通脚本若没有 async/defer,下载和执行会阻塞后续 HTML 解析。模块脚本默认具有类似 defer 的行为;给模块脚本加 async 后,则会在依赖加载完成后尽快执行。

36. 全局样式命名冲突和样式覆盖问题怎么解决? ​

答案:

解决全局 CSS 命名冲突,核心是缩小作用域并让覆盖关系可预测:

  • 使用 CSS Modules,让构建工具把局部类名转换成唯一类名;组件中通过导入映射引用。
  • 按 BEM 等命名约定添加组件前缀,适合无需构建工具的项目,但依赖团队纪律。
  • Vue 的 scoped、CSS-in-JS 等方案会为组件生成作用域标识或唯一类名。
  • Web Components 可使用 Shadow DOM 获得真正的样式边界;全局继承属性和 CSS 自定义属性仍可能穿透边界。
  • 用 @layer 明确 reset、基础样式、组件和工具类的级联顺序,减少靠选择器权重和加载顺序碰运气。

同时应保持选择器扁平、避免滥用 ID 和 !important,将主题变量、reset 等确实需要共享的样式集中管理。需要注意:Sass/Less 的嵌套和文件拆分本身不会产生运行时作用域,编译后仍可能是全局 CSS。

答案:

<link> 用于声明当前文档与外部资源或其他文档的关系,常见属性有:

  • rel:关系类型,是语义核心,如 stylesheet、icon、canonical、preload、prefetch。
  • href:目标资源 URL。
  • as:配合 preload 指明资源类型,如 style、script、font、image,用于正确的优先级、CSP 和缓存匹配。
  • type:资源 MIME 类型提示,例如图标类型;浏览器可据此判断是否支持。
  • media:媒体查询,常用于按媒介或视口条件加载/应用样式表。
  • crossorigin:配置跨源请求的 CORS 模式,字体预加载等场景通常需要它。
  • integrity:SRI 摘要,校验外部资源是否被篡改。
  • referrerpolicy:控制请求资源时的 Referer。
  • hreflang:目标文档的语言提示,常与 alternate 一起使用。
  • sizes:图标尺寸;imagesrcset、imagesizes 可为图片预加载描述候选资源。
  • fetchpriority:提示资源请求优先级。

属性是否生效取决于 rel。例如 as 主要服务于 preload,integrity 常用于样式表或预加载资源,不能脱离具体关系类型理解。

答案:

两者都是资源提示,但目标不同:

  • preload 面向当前页面确定很快会用到的关键资源。浏览器会较早、以与资源类型相符的优先级下载,但不会因为 preload 自动执行或应用资源。必须填写正确的 as,跨源模式也要与真正使用资源时一致,否则可能重复请求。
  • prefetch 面向后续导航可能用到的资源,通常以较低优先级在空闲时获取并放入缓存。它只是提示,浏览器可根据网络、缓存和用户设置忽略。
html
<link rel="preload" href="/hero.avif" as="image" fetchpriority="high">
<link rel="prefetch" href="/next-page.js" as="script">

不要把大量资源都设为 preload,否则会与真正关键的 CSS、字体或主图争抢带宽;还应确保预加载资源会在短时间内被实际消费。

39. HTML 部分标签中的 crossorigin 属性,作用是什么? ​

答案:

crossorigin 用来为支持该属性的 HTML 资源请求选择 CORS 模式及凭据策略,常见于 script、link、img、audio、video 等标签。

  • crossorigin="anonymous"(空字符串也等价于它):发起 CORS 请求;跨源请求通常不携带 cookie、HTTP 认证等凭据。服务端需返回允许该源的 Access-Control-Allow-Origin。
  • crossorigin="use-credentials":发起携带凭据的 CORS 请求;服务端必须明确允许该源并返回 Access-Control-Allow-Credentials: true,不能用通配符源。

它不会自动让跨域成功,最终仍由服务端 CORS 响应头决定。典型作用包括:让跨源脚本暴露完整错误信息、允许图片安全绘制到 canvas 后读取像素、让跨源样式或脚本执行 SRI 校验,以及确保字体/预加载请求与实际请求的缓存模式一致。

40. css module 是什么? ​

答案:

CSS Modules 是一种构建期 CSS 局部作用域方案。普通 .css 文件经过构建工具处理后,类名和动画名会被改写成唯一标识,同时导出原类名到生成类名的映射:

css
/* Button.module.css */
.root { color: red; }
js
import styles from './Button.module.css';
button.className = styles.root;

最终可能生成 Button_root__a1b2c,因此不同组件都写 .root 也不会冲突。它通常还支持 composes 组合类,以及用 :global(...) 显式声明全局选择器。

优点是作用域明确、仍使用标准 CSS、静态提取和缓存友好;代价是依赖构建配置,动态拼接类名不方便,覆盖第三方全局样式时需要显式逃逸。CSS Modules 不是浏览器原生的 JavaScript Module,也不是 Shadow DOM;隔离来自编译后的唯一命名。

41. CSS 属性值计算 - calc 怎么使用,具体有哪些使用场景? ​

答案:

calc() 让浏览器在计算样式时执行算术,最大的价值是可以混合百分比、长度、CSS 变量等不同单位:

css
main {
  width: calc(100% - 2rem);
  min-height: calc(100dvh - var(--header-height));
}
.grid {
  grid-template-columns: repeat(3, calc((100% - 2 * 16px) / 3));
}

常见场景包括:视口高度扣除固定头部、流式宽度减去侧栏或间距、基于变量计算尺寸、响应式插值,以及定位时做偏移。

+、- 两侧必须留空格,例如 calc(100% - 20px);乘除法中的单位也必须满足类型规则,最终结果要符合该 CSS 属性接受的值。calc() 不能绕过布局约束,例如元素仍会受到 min-width、盒模型和父容器可用空间影响。纯粹的同单位常量计算通常可在预处理阶段完成,而包含百分比、视口单位或运行时变量的计算应留给浏览器。

42. 怎么给某个元素的背景设置渐变色? ​

答案:

CSS 渐变生成的是 <gradient> 图像,因此通常赋给 background-image 或 background,而不是 background-color:

css
.linear {
  background: linear-gradient(135deg, #1769e0 0%, #21b66f 60%, #ffd166 100%);
}
.radial {
  background-image: radial-gradient(circle at 30% 20%, #fff, #5b7cfa 70%);
}
.conic {
  background: conic-gradient(from 90deg, #e63946, #ffd166, #2a9d8f, #e63946);
}

linear-gradient 是线性渐变,radial-gradient 是径向渐变,conic-gradient 是围绕中心旋转的锥形渐变;都可以设置方向、形状、颜色停止点和透明度,也可以叠加多层背景。应额外提供纯色兜底时,可先写 background-color,再写 background-image。

43. 在 DOM 中,如何判定 a 元素是否是 b 元素的子元素? ​

答案:

判断后代关系最直接的是 Node.contains():

js
function isDescendant(a, b) {
  return a !== b && b.contains(a);
}

这里判断的是“a 是否为 b 的后代”。要排除 a === b,因为 b.contains(b) 也返回 true。如果题目中的“子元素”特指直接子元素,应写:

js
const isDirectChild = a.parentElement === b;

也可以使用 b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_CONTAINED_BY 判断包含关系,但可读性通常不如 contains()。contains() 对已连接或未连接到文档的节点都可用。

44. less 文件中怎么使用函数? ​

答案:

Less 内置了颜色、数学、字符串、列表和类型判断等函数,直接在属性值中调用:

less
@brand: #1677ff;

.button {
  color: contrast(@brand);
  background: lighten(@brand, 12%);
  width: percentage((1 / 3));
  border-radius: unit(8, px);
}

Less 源码中通常用带参数的 mixin封装自定义计算,并通过调用方作用域中的变量返回结果:

less
.to-rem(@px, @base: 16) {
  @result: (@px / @base) * 1rem;
}

.title {
  .to-rem(24);
  font-size: @result;
}

Mixin 还可使用默认参数、条件守卫和模式匹配。若要注册真正的自定义函数,则需要 Less 插件的 JavaScript API,不应把构建期函数与浏览器运行时函数混为一谈。

45. 请使用 css 实现卡片翻转的动画 ​

答案:

关键点是:外层提供透视,内层保留 3D 空间并旋转,正反面隐藏背面。

html
<div class="card" tabindex="0">
  <div class="card__inner">
    <section class="card__face card__front">正面</section>
    <section class="card__face card__back">背面</section>
  </div>
</div>
css
.card {
  width: 240px;
  aspect-ratio: 3 / 2;
  perspective: 900px;
}

.card__inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 500ms ease;
}

.card:hover .card__inner,
.card:focus-visible .card__inner {
  transform: rotateY(180deg);
}

.card__face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  backface-visibility: hidden;
}

.card__back {
  transform: rotateY(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .card__inner { transition: none; }
}

perspective 决定近大远小的深度效果;backface-visibility: hidden 防止旋转后看到镜像背面。生产代码中如果翻转用于展示重要信息,还应提供点击/键盘可操作的按钮和明确状态,不能只依赖 hover。

46. css 中的 animation、transition、transform 有什么区别? ​

答案:

三者处在不同层次:

  • transform 描述元素在当前时刻的几何变换,如 translate、scale、rotate、skew。它本身不产生时间过程,只定义结果,而且通常不改变正常文档流中其他元素的布局位置。
  • transition 定义某个可动画 CSS 属性在两个状态发生变化时如何插值。它需要触发状态变化,如 :hover、类名切换或脚本改样式,适合简单的一进一出。
  • animation 通过 @keyframes 定义一个或多个关键帧,可自动开始、循环、反向、暂停,并控制填充模式,适合多阶段和独立时间线动画。
css
.box {
  transform: translateX(0);
  transition: transform 200ms ease;
}
.box.active { transform: translateX(100px); }

@keyframes pulse {
  50% { transform: scale(1.1); }
}
.badge { animation: pulse 1s ease-in-out infinite; }

transform 经常作为 transition 或 animation 的动画目标。平移、缩放和透明度通常比动画 width/left 更容易避免布局计算,但是否合成仍由浏览器决定,不能绝对认为它们都不会重绘。

47. flex 布局下,怎么改变元素的顺序? ​

答案:

给 Flex 项设置 order。默认值是 0,数值越小越靠前;值相同则保持源文档顺序:

css
.container { display: flex; }
.first  { order: -1; }
.normal { order: 0; }
.last   { order: 2; }

flex-direction: row-reverse/column-reverse 可以整体反转主轴方向,但不适合单独调整某一项。

需要注意,order 主要改变视觉绘制顺序,不会改变 DOM、屏幕阅读器的阅读顺序,键盘焦点顺序通常也仍按 DOM。因此不要用它修补有语义的内容顺序;重要顺序应从 HTML 结构上正确排列。

48. ”flex: auto;“是什么意思? ​

答案:

flex: auto 是简写,展开为:

css
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;

它先以项目的 width/height 或内容尺寸作为弹性基准,然后允许项目分配剩余空间,也允许在空间不足时收缩。因此多个 flex: auto 项目的初始内容尺寸不同,最终尺寸通常也不会相等。

它与常见的 flex: 1 不同:浏览器通常把 flex: 1 展开为 1 1 0%,即先忽略内容基准再分配空间,更适合等分布局。另一个常见边界是 Flex 项默认有 min-width: auto,长内容可能使它看起来无法收缩,此时可按需求设置 min-width: 0 并处理溢出。

49. object-fit 用法 ​

答案:

object-fit 控制图片、视频等可替换元素的内容如何放进已经确定尺寸的内容框,常和 object-position 一起使用:

css
.avatar {
  width: 160px;
  height: 120px;
  object-fit: cover;
  object-position: 50% 30%;
}
  • fill:默认值,拉伸填满,可能改变宽高比。
  • contain:保持宽高比并完整显示,框内可能留空。
  • cover:保持宽高比并铺满,超出部分会被裁切。
  • none:不按容器缩放,使用内容自身尺寸。
  • scale-down:在 none 与 contain 的结果中选择尺寸较小者。

要看到稳定效果,通常需要给元素确定宽高或宽高比。object-fit 处理 <img>/<video> 的内容;普通元素的背景图应使用 background-size: cover/contain。

50. CSS3 中 transition 和 animation 的属性分别有哪些? ​

答案:

transition 的四个核心长属性是:

  • transition-property:参与过渡的属性。
  • transition-duration:持续时间。
  • transition-timing-function:速度曲线。
  • transition-delay:延迟。

简写示例:transition: opacity 200ms ease-out 50ms, transform 300ms ease;。只有属性值发生变化且该属性可动画时才会过渡,避免长期使用 transition: all。

animation 的常用长属性是:

  • animation-name:@keyframes 名称。
  • animation-duration:单轮时长。
  • animation-timing-function:速度曲线。
  • animation-delay:延迟。
  • animation-iteration-count:播放次数或 infinite。
  • animation-direction:normal、reverse、alternate 等方向。
  • animation-fill-mode:动画执行前后是否应用首尾关键帧样式。
  • animation-play-state:running 或 paused。

简写示例:animation: slide-in 500ms ease-out 100ms 1 normal both;。多个动画可用逗号分隔;同一列表中各长属性会按位置配对。

51. 说说你对 SSG 的理解 ​

答案:

SSG(Static Site Generation,静态站点生成)是在构建阶段获取数据并把模板渲染成 HTML、CSS、JS 等静态文件,部署后由对象存储或 CDN 直接响应,而不是每次请求都在服务器现算 HTML。

优势是首屏 HTML 完整、缓存和 CDN 友好、响应快、运行时服务器压力小,通常也利于 SEO 和稳定性。它适合文档、博客、营销页、商品详情等读取多且内容更新频率可控的页面。

边界在于:内容变化后通常需要重新构建和发布;页面数量很大时构建时间会增长;用户私有数据和强实时内容仍需客户端请求或服务端动态渲染。实际项目可以混合 SSG、SSR 和 CSR,也可用增量静态再生成,在过期后按需重新生成部分页面。SSG 不等于“没有后端”,页面构建时和客户端运行后仍可调用 API。

52. 说说你对 CSS 模块化的理解 ​

答案:

CSS 模块化是把样式按页面或组件划分为边界清晰、依赖明确、可复用的模块,主要解决全局命名冲突、隐式覆盖、删除困难和大型样式表难维护的问题。常见手段有:

  • BEM/命名空间:通过命名约定避免冲突,成本低但没有强制隔离。
  • CSS Modules、Vue scoped:构建时改写选择器,实现组件级局部作用域。
  • CSS-in-JS:样式与组件逻辑共置,可基于状态生成样式;运行时方案可能带来执行成本,也有静态提取方案。
  • Shadow DOM:浏览器原生样式封装,适合 Web Components。
  • @layer:明确不同来源和模块的级联优先级,解决“谁覆盖谁”,但不负责类名隔离。

Sass/Less 的变量、mixin、拆文件主要改善组织和复用,编译产物仍是全局 CSS,因此不能单独视为作用域方案。实践中通常保留少量全局 reset、设计令牌和排版基础,其余样式靠组件边界管理,并提供显式的主题与覆盖接口。

53. ::before 和::after 中双冒号和单冒号有什么区别、作用? ​

答案:

单冒号通常表示伪类,如 :hover、:focus、:nth-child(),用于选择某种状态或结构关系中的已有元素;双冒号表示伪元素,如 ::before、::after、::first-line,用于选择元素的一部分或生成一个不在 DOM 中的样式盒。

CSS 为兼容旧代码,仍允许四个早期伪元素 :before、:after、:first-line、:first-letter 使用单冒号,但新代码应统一写双冒号。

::before 和 ::after 分别在元素内容前后生成伪元素,通常必须设置 content 才会生成:

css
.required::after {
  content: "*";
  color: #d00;
}

它们不是真实 DOM 节点,不能直接绑定事件或承载关键语义;在 img、input 等可替换元素上也不能依赖其生成效果。伪类按类选择器计算权重,伪元素按类型选择器计算权重。

54. 说说你对 Dom 树的理解 ​

答案:

DOM 树是浏览器把 HTML 文档解析成的内存对象结构。树的根通常是 Document,下面包含元素节点、文本节点、注释节点等;父子和兄弟关系对应文档结构。JavaScript 通过 DOM API 查询、创建、删除和修改这些节点。

大致过程是:字节按响应声明和探测结果解码成字符,分词器生成标签/文本 token,树构建器依据 HTML 解析规则创建节点并插入树中。HTML 解析具有容错规则,错误嵌套的源码不一定得到直观相同的树。解析遇到普通同步脚本时通常会暂停,因为脚本可能用 document.write 或 DOM API 改变后续结构;defer、async、模块脚本的时机不同。

DOM 树不等于最终画面。浏览器还会解析 CSS,结合 DOM 形成用于渲染的结构,再经历样式计算、布局、绘制和合成;display: none 的元素仍在 DOM 中但不生成常规渲染盒,伪元素可能参与渲染却不是真实 DOM 节点。DOM 变更也不一定都触发布局,代价取决于变更内容。

55. Node 和 Element 是什么关系? ​

答案:

Node 是多种 DOM 节点共享的基础接口,继承自 EventTarget;Element 继承 Node,表示由标签形成的元素节点,并增加属性、类名、选择器匹配等元素专属能力。继承关系可概括为:

text
EventTarget <- Node <- Element <- HTMLElement <- HTMLDivElement

文本 Text、注释 Comment、Document 也都是 Node,但不是 Element。因此:

  • node.childNodes 包含元素、文本、注释等所有子节点;element.children 只包含元素子节点。
  • parentNode 返回任意父节点;parentElement 只在父节点是元素时返回该元素,否则为 null。
  • nodeType === Node.ELEMENT_NODE 可判断节点是否为元素,更直接的跨窗口判断可结合 node.nodeType,而 instanceof Element 可能受不同 iframe 全局对象影响。

56. 如何控制 input 输入框的输入字数? ​

答案:

对文本类 <input>,优先使用原生 maxlength:

html
<input type="text" minlength="2" maxlength="20" required>

它会限制用户输入,并参与约束验证,可通过 input.validity.tooLong 检查。maxlength 适用于 text、search、url、tel、email、password 等文本输入,不适用于 type="number";数字范围应使用 min、max,位数规则可改用文本输入配合 inputmode 和校验。

业务上若要显示剩余字数或按特殊规则截断,可监听 input,但要处理输入法组合事件,并注意 HTML 长度按 UTF-16 代码单元计数,一个 emoji 可能不等于一个用户感知字符。无论前端如何限制,服务端仍必须再次校验长度,因为 DOM 属性和前端脚本都可被绕过。

57. position: fixed 一定是相对于浏览器窗口进行定位吗? ​

答案:

不一定。通常 position: fixed 的包含块是视口,所以元素滚动时保持在窗口固定位置;但某些祖先会为它建立新的固定定位包含块,此时它会相对该祖先定位,并随祖先一起滚动。常见触发条件包括祖先的 transform、perspective、filter 或 backdrop-filter 为非 none,以及相应的 will-change,某些 contain、container-type、content-visibility 设置也可能建立包含块。

css
.wrapper { transform: translateZ(0); }
.fixed { position: fixed; inset: 0 auto auto 0; }

这里 .fixed 相对 .wrapper,不是根视口。排查 fixed 定位异常时,应沿祖先链检查这些属性以及滚动容器。fixed 会脱离正常文档流,并建立新的层叠上下文;移动端还要区分布局视口和缩放、软键盘影响下的可视视口。

58. 假设我要上传图片,怎么在选择图片后,通过浏览器预览待上传的图片? ​

答案:

推荐用 URL.createObjectURL(file) 为选中的 File 建立临时 Blob URL,速度快且不需要把文件整体编码成 Base64:

html
<input id="picker" type="file" accept="image/*">
<img id="preview" alt="待上传图片预览">
<script>
  const picker = document.querySelector('#picker');
  const preview = document.querySelector('#preview');
  let objectURL;

  picker.addEventListener('change', () => {
    const file = picker.files?.[0];
    if (!file) return;
    if (!file.type.startsWith('image/')) {
      picker.value = '';
      return;
    }

    if (objectURL) URL.revokeObjectURL(objectURL);
    objectURL = URL.createObjectURL(file);
    preview.src = objectURL;
  });

  preview.addEventListener('load', () => {
    if (objectURL) {
      URL.revokeObjectURL(objectURL);
      objectURL = undefined;
    }
  });
</script>

也可用 FileReader.readAsDataURL() 得到 Data URL,适合确实需要字符串内容的场景,但会增加编码体积和内存占用。accept 只是文件选择提示,不是安全校验;上传前端可检查类型、大小和图片尺寸,服务端仍必须验证真实文件内容。多文件预览时要为每个对象 URL 分别回收。

59. 渐进式jpg有了解过吗? ​

答案:

渐进式 JPEG(Progressive JPEG)把图像编码为多次扫描。浏览器收到前面一部分数据时,就能先显示整张图的低细节版本,后续扫描逐步补充频率和精度,直到图像清晰。与之相对,基线 JPEG 通常按一次扫描解码,视觉上更像从上到下逐步出现。

它的主要收益是改善大图在慢网络下的感知加载体验:用户较早看到整体构图,而不是长时间空白。但它并不保证文件一定更小,也不会减少实际下载字节或自动改善 LCP;编码参数、解码成本、图片尺寸和服务端传输同样重要。现代浏览器普遍支持渐进式 JPEG。实际项目还应结合响应式图片、合理压缩、懒加载,并评估 WebP/AVIF 等现代格式。

60. 怎么实现“点击回到顶部”的功能? ​

答案:

现代实现可直接调用 window.scrollTo:

html
<button id="backToTop" type="button" aria-label="回到顶部">顶部</button>
<script>
  document.querySelector('#backToTop').addEventListener('click', () => {
    const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
    window.scrollTo({
      top: 0,
      left: 0,
      behavior: reduceMotion ? 'auto' : 'smooth'
    });
  });
</script>

也可以用链接 <a href="#top"> 配合页面顶部锚点,天然支持无 JavaScript 和浏览器历史语义;或对顶部元素调用 scrollIntoView()。若滚动发生在某个容器而非窗口,应调用 container.scrollTo({ top: 0 })。

通常还会监听滚动或使用 IntersectionObserver,仅在离开顶部后显示按钮。避免手写逐帧定时器;原生平滑滚动更简单,并应尊重 prefers-reduced-motion。

61. 单行文本怎么实现两端对齐? ​

答案:

给文本容器确定宽度,并使用 text-align-last: justify 控制最后一行;为兼容多行语义,通常同时写 text-align: justify:

html
<span class="label">用户名称</span>
css
.label {
  display: inline-block;
  width: 8em;
  text-align: justify;
  text-align-last: justify;
}

text-align: justify 默认不会拉伸段落最后一行,text-align-last 正是用来指定最后一行的对齐方式。容器必须有多余水平空间才能看到效果;只有一个字符时也没有字符间隙可分配。

旧方案会用 ::after { content: ""; display: inline-block; width: 100%; } 人为制造下一行,但会带来额外行盒和高度处理问题。若需求是若干独立标签项均匀排布,而不是普通文本排版,应把各项做成独立元素并使用 Flex/Grid。

62. SPA应用怎么进行SEO? ​

答案:

纯 CSR 的 SPA 初始 HTML 内容少,搜索引擎虽然可能执行 JavaScript,但渲染可能延迟、失败或资源受限。最稳妥的方案是让重要路由输出可直接抓取的 HTML:

  • 使用 SSR,在请求时生成 HTML;内容较稳定的页面使用 SSG/预渲染,更新策略可结合增量生成。首屏再水合为 SPA。
  • 每个路由提供独立、准确的 title、description、canonical、Open Graph 等元信息;服务端返回正确的 200、301、404 状态。
  • 用真实 <a href> 建立可爬取导航,避免只有点击事件;提供 sitemap,合理配置 robots.txt,并添加与页面内容一致的结构化数据。
  • 保证重要内容无需用户交互即可出现,避免无限滚动成为唯一入口;分页页面应有稳定 URL。
  • 优化 Core Web Vitals、移动端体验、语义化 HTML、图片替代文本和内部链接,并避免重复或低质量内容。

只向爬虫返回专用快照的“动态渲染”维护成本高,内容不一致还可能被视为 cloaking,通常只适合作为迁移期方案。上线后应通过站长工具检查抓取、渲染和索引结果。

63. SEO的原理是什么? ​

答案:

从搜索引擎工作流程看,SEO 涉及四个核心阶段:

  1. 发现与抓取:爬虫通过链接、sitemap 等发现 URL,依据 robots 规则和抓取预算请求页面。
  2. 渲染与索引:搜索引擎解析 HTML,必要时执行 JavaScript,提取正文、链接、canonical、结构化数据等,判断是否收录及采用哪个规范 URL。
  3. 查询理解与召回:用户搜索时,系统理解意图,从索引中召回相关文档。
  4. 排序与展示:综合内容相关性与质量、链接和站点信誉、时效性、地区语言、页面体验等大量信号排序,并生成搜索结果摘要。

SEO 的作用就是降低搜索引擎发现和理解页面的成本,同时提高页面对真实搜索意图的满足程度。技术上要保证可抓取、可渲染、状态码和 canonical 正确;内容上要原创、准确并覆盖用户需求;站点结构和内部链接要清楚;性能和移动体验要合格。排名算法和权重不是固定公式,SEO 也不能保证某个名次。

64. SEO是什么? ​

答案:

SEO(Search Engine Optimization,搜索引擎优化)是在遵守搜索引擎规则的前提下,持续改进网站的技术基础、信息架构、内容和用户体验,使页面更容易被发现、抓取、理解和索引,并在相关自然搜索中获得更合适的展示与流量。

它通常包括:技术 SEO(可抓取性、渲染、状态码、性能、移动适配)、站内 SEO(内容、标题、语义结构、内部链接)、站外信誉信号,以及对收录、查询和转化数据的监测。SEO 面向的是自然搜索,不等同于付费搜索广告;目标也不应只是堆关键词或追求排名,而是让高质量页面准确满足用户意图。隐藏文字、关键词堆砌、购买垃圾链接等操纵手段可能带来惩罚。

65. 如何实现SEO优化 ​

答案:

SEO 的核心是让搜索引擎能正确发现、理解并评价页面。使用语义化 HTML、唯一且准确的 title/description、合理的 h1-h6 和可访问的图片 alt;规划清晰的 URL、站内链接、sitemap.xml 与 robots.txt;保证移动端适配、加载性能、HTTPS 和 SSR/预渲染。持续产出有价值且原创的内容,并通过可靠外链提升权威性。不要堆砌关键词或批量制造低质外链,meta keywords 基本没有现代搜索价值。

66. 使用css实现一个无限循环动画 ​

答案:

用 @keyframes 定义状态,再把 animation-iteration-count 设为 infinite。例如:```css .box{animation: pulse 1s ease-in-out infinite alternate;} @keyframes pulse{from{transform:scale(1)}to{transform:scale(.85)}}

其中

## 67. 怎么触发BFC,BFC有什么应用场景?

**答案:**

BFC 是独立的块级格式化上下文。常见触发方式包括根元素、float 非 none、position 为 absolute/fixed、overflow 非 visible/clip,以及 display 为 flow-root、flex、grid、inline-block 等。BFC 内部布局与外部隔离,能包含浮动子元素、阻止相邻块的 margin 折叠,也能让文字避开浮动元素。因此可用 `display: flow-root` 清除浮动,或给右栏建立 BFC 实现左浮动右自适应;不要为清浮动随意使用会裁剪内容的 overflow:hidden。

## 68. DNS 预解析是什么?怎么实现?

**答案:**

DNS 预解析是浏览器提前把可能用到的域名解析为 IP,减少真正请求时的 DNS 等待。写在 head 中即可:```html
<link rel="dns-prefetch" href="//cdn.example.com">
```也可对关键跨域源使用 `preconnect`,它还会预先建立连接。只对确实会访问的第三方域名使用,避免无效查询;预解析不等于下载资源,结果仍受浏览器、系统缓存和 DNS TTL 影响。

## 69. HTML5 有哪些 drag 相关的 API ?

**答案:**

HTML5 拖放 API 主要包括元素的 `draggable` 属性,以及拖拽源的 `dragstart`、`drag`、`dragend` 事件;放置目标的 `dragenter`、`dragover`、`dragleave`、`drop` 事件。要允许放置,通常在 `dragover` 中调用 `event.preventDefault()`;通过 `dataTransfer.setData/getData` 传递数据,`effectAllowed` 和 `dropEffect` 控制操作类型。移动端对原生拖放支持不一致,触摸场景应准备 Pointer Events 方案。

## 70. 浏览器乱码的原因是什么?如何解决?

**答案:**

乱码通常是文件实际编码、HTTP 响应头、HTML 声明或解码方式不一致,例如 UTF-8 内容被按 GBK 解读。统一保存为 UTF-8,并在 HTML 写 `<meta charset="UTF-8">`,服务端返回 `Content-Type: text/html; charset=UTF-8`;接口 JSON 也应声明 UTF-8。还要检查数据库连接、模板文件、URL 编码和字体是否正常,不能只靠修改浏览器编码解决。

## 71. Canvas和SVG有什么区别?

**答案:**

Canvas 是基于位图的即时绘制画布,图形绘制后通常只剩像素,适合游戏、图像处理和大量动态图形;放大可能失真,事件命中和无障碍需要自行处理。SVG 是基于 XML 的矢量场景树,每个图形都是 DOM 节点,适合图标、地图和需要清晰缩放、单元素交互的图形,但节点过多会增加 DOM 和样式开销。两者没有绝对优劣,应按交互、缩放和图形数量选择。

## 72. title与h1的区别、b与strong的区别、i与em的区别?

**答案:**

`title` 是页面标题,通常显示在浏览器标签和搜索结果中;`h1` 是页面正文的一级标题,表达内容层级,通常每页应有明确且可见的主标题。`b` 仅表示视觉上的醒目,不表达重要性;`strong` 表示内容重要,默认也常加粗。`i` 是另一种语气或习惯上的斜体表现;`em` 表示语义上的强调,默认斜体。语义标签更利于无障碍和搜索理解,样式应交给 CSS。

## 73. 浏览器是如何对 HTML5 的离线储存资源进行管理和加载?

**答案:**

这里通常指 AppCache:浏览器读取 HTML 的 `manifest`,首次在线访问时下载清单列出的资源并写入对应缓存;之后离线访问优先使用上一版缓存,后台再按 manifest 检查更新,更新完成后下一次加载才切换到新缓存。`NETWORK`、`FALLBACK` 可声明网络和回退规则。AppCache 存在缓存整站、更新时机反直觉等问题,已被废弃,生产项目应使用 Service Worker 配合 Cache Storage,并自行控制版本和更新策略。

## 74. HTML5的离线储存怎么使用,它的工作原理是什么

**答案:**

旧式 HTML5 离线存储使用 AppCache:```html
<html manifest="/app.appcache">
```清单示例:```text
CACHE MANIFEST
/style.css
/app.js
NETWORK:
*
```浏览器在线时按清单缓存资源,离线时从缓存读取;manifest 发生变化才会触发新版本下载,通常下一次打开才生效。它已被废弃,推荐注册 Service Worker,在 `install` 中缓存资源、在 `fetch` 中决定缓存优先或网络优先,并通过版本名和更新流程管理缓存。

## 75. img的srcset属性的作⽤?

**答案:**

`srcset` 为同一图片提供多个候选资源,浏览器结合显示尺寸、像素密度和网络条件选择合适文件,减少小屏下载大图。例如:```html
<img src="small.jpg" srcset="small.jpg 480w, large.jpg 1200w" sizes="(max-width:600px) 100vw, 600px" alt="示例">
````w` 描述资源宽度,`sizes` 描述图片在布局中的预计宽度;若使用 `1x/2x` 则按设备像素比选择。`src` 是不支持或未选择候选时的回退。

## 76. 怎么实现一个宽高自适应的正方形?

**答案:**

最简单的是利用现代 CSS:```css
.square&#123;aspect-ratio:1 / 1;width:100%;&#125;
```这样高度会始终等于宽度。兼容旧浏览器时可用伪元素的 padding:```css
.square{width:100%;height:0;padding-top:100%;position:relative;}
.square>*{position:absolute;inset:0;}
```百分比 padding 按包含块的宽度计算。也可用 JS 监听尺寸,但会引入同步测量和 resize 管理,通常不如 CSS 稳定。

## 77. z-index属性在什么情况下会失效?

**答案:**

`z-index` 只在可比较的同一层叠上下文中决定前后顺序。常见失效原因是元素仍是普通静态定位且旧环境不支持对其生效,或父元素建立了层叠上下文,子元素再大的 z-index 也不能越过父上下文与外部元素比较;`transform`、`opacity<1`、`filter`、`isolation:isolate` 等也可能新建上下文。另外元素被祖先的 `overflow` 裁剪,或实际比较的是伪元素/兄弟层叠顺序。应先检查上下文、定位、裁剪和 DOM 层级。

## 78. 说说对 CSS 工程化的理解

**答案:**

CSS 工程化是用规范、工具和流程管理规模化样式,目标是可维护、可复用、低冲突和可构建。实践包括组件化与设计变量、BEM 或 CSS Modules 等命名/隔离策略,Sass/Less 等预处理,PostCSS、Autoprefixer、Stylelint、格式化和构建压缩;还要处理主题、响应式、按需加载和旧浏览器兼容。关键是统一约定并纳入 CI,避免过度嵌套、全局污染和无依据的抽象。

## 79. Sass、Less 是什么?为什么要使用他们?

**答案:**

Sass、Less 是 CSS 预处理器:先用扩展语法编写源码,再编译成浏览器能直接理解的 CSS。它们通常提供变量、嵌套、混入、函数、模块拆分和运算,适合复用主题值、减少重复并组织大型样式。Sass 生态和能力更成熟,Less 上手简单;代价是增加构建步骤,嵌套过深会生成难维护的选择器。现代 CSS 已支持变量、原生嵌套等能力,应按项目兼容范围决定是否引入。

## 80. 怎么实现单行、多行文本溢出隐藏?

**答案:**

单行省略:```css
.one&#123;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;&#125;
```元素必须有受限宽度。多行可用兼容性较好的 WebKit 方案:```css
.multi{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;}
```表示最多三行。`text-overflow` 本身不会截断,必须配合溢出隐藏和不换行;多行方案对旧浏览器支持有限,严格跨浏览器时可用 JS 按字数/布局截断,并注意中文、长单词和可访问性。

## 81. CSS预处理器/后处理器是什么?为什么要使用它们?

**答案:**

预处理器在构建前扩展 CSS,例如 Sass/Less 将变量、嵌套和 mixin 编译成 CSS;后处理器在 CSS 生成后处理它,例如 PostCSS 配合 Autoprefixer 补前缀、插件转换语法或压缩。它们能提高复用性、兼容性和发布体积,但都增加构建复杂度。选择时应按目标浏览器、团队维护成本和原生 CSS 能力评估,避免同时引入重复功能或生成过于复杂的选择器。

## 82. 为什么有时候⽤translate来改变位置⽽不是使用position进行定位?

**答案:**

`transform: translate()` 只改变元素的视觉变换位置,不改变文档流中占用的空间,适合动画、拖拽和微调;通常由合成层处理,可避免频繁触发布局。`position` 改变的是布局定位关系,absolute/fixed 会脱离文档流,可能影响重排、定位包含块和层叠关系。二者不是互相替代:需要参与布局时用 flex/grid/margin,需独立定位时用 position,动画移动优先用 transform,并注意 transform 可能创建层叠上下文。

## 83. transition和animation的区别

**答案:**

`transition` 描述属性从一个状态到另一个状态的过渡,通常由 hover、class 或脚本触发,不能自行定义关键帧;`animation` 通过 `@keyframes` 定义多个阶段,可自动播放、循环、延迟、反向和暂停。transition 更适合简单交互反馈,animation 适合连续或复杂时间线。两者都应优先使用 `transform`、`opacity` 等易合成属性,并用 `prefers-reduced-motion` 降低对动效敏感用户的影响。

## 84. 在解决动画卡顿问题时,会引导硬件加速,那么硬件加速的原理是什么?

**答案:**

硬件加速通常是把元素的绘制或合成交给 GPU。浏览器会把满足条件的元素栅格化为纹理并在合成阶段移动、缩放,避免每帧重新布局和大面积绘制;`transform: translateZ(0)`、`will-change: transform` 可能促成这一过程,但不是强制命令。GPU 层过多会消耗显存、增加上传和合成成本,反而卡顿,因此只对确有动画收益的元素使用,并用 DevTools 验证。

## 85. 什么是硬件加速?

**答案:**

CSS 硬件加速是浏览器利用 GPU 完成部分绘制或合成,以减少 CPU 参与和主线程布局/绘制压力,常见于 transform、opacity 等动画。它不等于所有 CSS 都交给 GPU,也不会自动解决布局或脚本造成的卡顿。可用 `will-change: transform` 提示浏览器,动画结束后移除;同时控制层数量、避免大面积重绘,并通过性能面板确认是否真的减少了帧耗时。

## 86. 下面代码中,p标签的背景色是什么?

```html
<style type="text/css">
     #parent p { background-color: red;  }
      div .a.b.c.d.e.f.g.h.i.j.k p{ background-color: green;  
</style>
......
<div id="parent">
     <div class="a b c d e f g h i j k">
         <p>xxxx</p>
     </div>
</div>

答案:

在题干样式语法完整、两个规则都匹配的前提下,背景色是绿色。#parent p 的特异性为 1 个 ID 加 1 个元素;div .a.b.c.d.e.f.g.h.i.j.k p 为 10 个 class 加 2 个元素,class 分量更高,所以后者胜出。若题干中确实缺少右花括号,则该规则表面上是无效 CSS;面试题通常应按补齐花括号理解。

87. 假设下面样式都作用于同一个节点元素span,判断下面哪个样式会生效 ​

css
body#god div.dad span.son {width: 200px;}
body#god span#test {width: 250px;}

答案:

第二条规则的特异性更高:body#god div.dad span.son 为 (1,2,3),body#god span#test 为 (2,1,2),比较时先看 ID 数量,因此后者优先,计算出的值是 width:250px。但 span 默认是行内元素,width 对行内非替换元素通常不生效;若要看到宽度,应让它成为 inline-block、block 或其他可设宽度的盒子。

88. 为何CSS不支持父选择器? ​

答案:

传统 CSS 选择器主要从父到子匹配。父选择器会让匹配依赖后代状态:浏览器可能要先扫描、解析并确定整棵子树,再决定祖先是否匹配,动态增删节点还可能导致更大范围的样式失效和重算,影响性能与实现复杂度。过去因此没有通用父选择器;现代 CSS 已提供 :has(),例如 .card:has(.error),但应谨慎使用并注意浏览器兼容性,因为它仍可能扩大匹配范围。

89. 脱离文档流有哪些方法? ​

答案:

常见脱离文档流的方式有 position:absolute、position:fixed(以及通常的 sticky 在达到吸附条件后)、float:left/right,还包括把元素从布局中隐藏的 display:none。绝对定位和 fixed 不再占原位置,位置由包含块和 inset 决定;浮动会脱离普通块流但仍会影响周围文字,并可能造成父元素高度塌陷。transform 只改变视觉位置,不算真正脱离文档流。使用时要补充尺寸、清除浮动和无障碍语义。

90. 第二个子元素的高度是多少 ​

html
<div class="container">
    <div style="height: 100px"></div>
    <div style="min-height: 10px"></div>
</div>
<style>
    .container{
        display: flex;
    }
    .container > div {
        width: 100px;
    }
</style>

答案:

第二个子元素的实际交叉轴高度是 100px。容器是默认 flex-direction: row,高度由第一行内容决定,第一项高度为 100px;align-items 默认是 stretch,第二项没有设定 height,因此会沿交叉轴拉伸到该行高度。min-height:10px 只是最小值,不会阻止拉伸。若设置 align-items:flex-start 或给该项固定 height,则不会得到这个结果。

91. js和css是否阻塞DOM树构建和渲染? ​

答案:

HTML 解析会构建 DOM,CSS 解析会构建 CSSOM。普通外链 CSS 通常不阻塞 DOM 的继续解析,但会阻塞首次渲染,因为渲染树需要样式;位于 CSS 之后的同步脚本还会等待 CSSOM,避免脚本读取到未完成的样式。同步 <script> 会暂停 HTML 解析并阻塞 DOM 构建;defer 下载不阻塞解析,解析完成后按序执行;async 下载不阻塞解析,但下载完立即执行,顺序不确定。

92. CSSOM树和DOM树是同时解析的吗? ​

答案:

DOM 和 CSSOM 可以并行构建,但不是一棵树、也不是严格同步完成。解析 HTML 时遇到 CSS,浏览器可独立下载并解析生成 CSSOM;HTML 遇到同步 JavaScript 会暂停,脚本执行通常要等待其前面的样式表完成,以保证 CSSOM 查询结果可靠。首次渲染要等 DOM 与 CSSOM 都足够完整后生成渲染树,因此 CSS 通常阻塞渲染,而不直接阻塞 HTML 解析。

93. 怎么实现样式隔离? ​

答案:

常用方案有 CSS Modules 或构建工具 scoped CSS,通过编译给类名/选择器加唯一标识;Vue 的 <style scoped> 通过属性选择器限制作用域;Web Components 使用 Shadow DOM 形成原生边界;大型项目也可用 BEM 约定和明确的全局层级。需要跨组件覆盖时应设计显式 token、CSS 变量或穿透接口,避免依赖深层选择器。隔离不能代替合理的公共样式架构,还要考虑 SSR、主题和第三方组件兼容性。

94. position:absolute绝对定位,是相对于谁的定位? ​

答案:

position:absolute 相对于最近的非 static 定位祖先建立的包含块定位,通常是最近的 relative、absolute、fixed 或 sticky 祖先;若没有,则通常相对初始包含块(常表现为页面根部)定位。它会脱离普通文档流,不再占原空间,top/right/bottom/left 以该包含块的 padding box 等规则计算。某些祖先的 transform、filter、perspective 也会建立包含块,需特别检查。

95. 下面这段代码中,class为content的元素,实际高度是100px吗? ​

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Static Template</title>

    <style>
      .parent {
        display: flex;
        flex-direction: column;
        height: 600px;
        width: 300px;
        background: yellow;
      }
      div {
        width: 100%;
      }
      .header {
        height: 200px;
        background: red;
      }
      .content {
        height: 100%;
        background: blue;
      }
      .footer {
        height: 200px;
        background: black;
      }
    </style>
  </head>
  <body>
    <div class="parent">
      <div class="header"></div>
      <div class="content"></div>
      <div class="footer"></div>
    </div>
  </body>
</html>

答案:

不是 100px,而是约 360px。父容器是 600px 高的纵向 flex 容器,三个项目的基准高度分别按 200px、600px、200px 计算,总和 1000px,发生 400px 的收缩;默认 flex-shrink:1 按基准尺寸比例分配,三者最终约为 120px、360px、120px。因此 .content 的 height:100% 是参与 flex 基准尺寸的依据,不会简单等于父高;若设置 flex:none 或改变 shrink,结果会不同。

96. 怎么做移动端的样式适配? ​

答案:

采用移动优先的响应式方案:先写小屏基础样式,再用 media query 为更宽视口增强布局;使用 flex/grid、百分比、min()/max()/clamp() 和合适的 rem、vw 等单位,避免固定宽度导致横向溢出。图片使用 max-width:100%;height:auto,必要时用 picture/srcset;设置正确 viewport,保证触控区域、字体和内容可读。最后在真实设备和不同方向、DPR、浏览器下测试断点与交互。

97. 行内元素和块级元素有什么区别 ​

答案:

行内元素默认不独占一行,宽高主要由内容决定,适合文本级内容;块级元素默认独占一行,可设置宽高、内外边距,也能包含块级和行内子元素。二者只是默认布局表现,display 可以在 inline、block、inline-block 等类型之间切换;实际还要注意 HTML 语义和上下文。

98. 使用原生js实现以下效果:点击容器内的图标,图标边框变成border:1px solid red,点击空白处重置 ​

答案:

可用事件委托处理容器内图标,再在文档上监听空白点击:

js
const box = document.querySelector('#box');
box.addEventListener('click', (e) => {
  const icon = e.target.closest('.icon');
  if (!icon || !box.contains(icon)) return;
  box.querySelectorAll('.icon').forEach(x => x.style.border = '');
  icon.style.border = '1px solid red';
});
document.addEventListener('click', (e) => {
  if (!box.contains(e.target)) box.querySelectorAll('.icon').forEach(x => x.style.border = '');
});

点击图标时只保留当前红框,点击容器外空白时全部重置。

99. CSS 垂直居中有哪些实现方式? ​

答案:

常用方案有:固定尺寸元素可用绝对定位 top:50%;left:50% 配合 transform:translate(-50%,-50%);已知宽高也可用负 margin 或 calc。单行文本可用 line-height,行内块可用 vertical-align:middle;兼容旧布局可用 display:table-cell 与 vertical-align:middle。现代项目优先使用 display:flex;justify-content:center;align-items:center,或 Grid 的 place-items:center,对内容尺寸变化更稳健。

100. 怎么让CSS flex布局最后一行列表左对齐? ​

justify-content对齐问题描述 ​

在CSS flex布局中,justify-content属性可以控制列表的水平对齐方式,例如space-between值可以实现两端对齐。

但是,如果最后一行的列表的个数不满,则就会出现最后一行没有完全垂直对齐的问题。

如下代码:

css
.container {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}
.list {
    width: 24%; height: 100px;
    background-color: skyblue;
    margin-top: 15px;
}
html
<div class="container">
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
    <div class="list"></div>
</div>

image.png

怎么让最后一行左对齐呢?

答案:

固定列数时不要直接依赖 space-between,因为最后一行会把剩余空间重新分配。可改为固定间隙:

css
.container{display:flex;flex-wrap:wrap;gap:15px 1.333%;}
.list{width:24%;}

也可给最后一项补 margin-right:auto,但适用于子项宽度不固定的场景。若 HTML 可调整,用与列表同宽的空占位元素补齐;若列数和宽度都不固定,优先用 Grid:grid-template-columns:repeat(auto-fill,100px);gap:10px,天然保持网格左对齐。

101. 相邻的两个inline-block节点为什么会出现间隔,该如何解决? ​

答案:

原因是 inline-block 按行内格式化上下文排版,HTML 标签之间的换行或空格会被折叠成一个空白字符,因而产生间距。常见解决方式是删除标签间空白、父元素设 font-size:0 再给子元素恢复字号,或改用 Flex/Grid。负 margin、负 letter-spacing 也能消除,但依赖字体和环境,维护性较差。

102. display 有哪些取值? ​

答案:

display 同时决定元素自身的外部显示类型和子元素的内部布局。常用值包括:none(不参与布局)、block、inline、inline-block、table、flex、grid;还可用 list-item、contents、flow-root,以及全局值 inherit、initial、unset、revert。选择时要区分是否需要占行、是否要建立 Flex/Grid 布局,以及是否保留元素盒子。

103. 使用input标签上传图片时,怎样触发默认拍照功能? ​

答案:

给文件输入框添加 accept="image/*" 限定图片,并使用 capture 请求调用摄像头:

html
<input type="file" accept="image/*" capture="environment">

environment 通常请求后置摄像头,user 请求前置摄像头,camera 是部分浏览器支持的写法。capture 只是移动端的提示,浏览器、系统和权限策略都可能忽略它,不能保证一定直接拍照。

104. input上传文件可以同时选择多张吗?怎么设置? ​

答案:

可以,在 <input type="file"> 上添加布尔属性 multiple:

html
<input type="file" name="files" accept="image/*" multiple>

用户即可在文件选择器中选多个文件,提交时会产生多个同名文件项。服务端也必须按数组或多文件字段处理,不能只读取一个文件。

105. 如何禁止input展示输入的历史记录? ​

答案:

在输入框上设置 autocomplete="off",可请求浏览器不展示历史自动完成:

html
<input type="text" autocomplete="off">

它主要控制表单自动填充,不是绝对的安全或隐私保证;部分浏览器会对登录、密码等字段忽略 off,这类场景应使用合适的 autocomplete 语义值,而不是依赖它隐藏敏感内容。

106. 如何从html元素继承box-sizing? ​

答案:

可让根元素定义盒模型,再让所有元素和伪元素继承:

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

这样元素设置宽高时会把 padding 和 border 计入尺寸,子组件仍可显式覆盖自己的 box-sizing。相比直接给所有元素写 border-box,继承方案更容易保留组件的局部配置。

107. 如何使用css来实现禁止移动端页面的左右划动手势? ​

答案:

优先从布局根因修复横向溢出,确保内容宽度不超过视口;确需禁止横向滚动时可写:

css
html, body { max-width:100%; overflow-x:hidden; }

移动端触摸行为可按元素设置 touch-action: pan-y,表示允许纵向平移而不处理横向平移。width:100vw 可能把滚动条宽度也算进去,反而制造溢出;还应检查长文本、绝对定位、负 margin 和图片未设置 max-width:100% 等问题。

108. 如何检测浏览器所支持的最小字体大小? ​

答案:

可以逐步设置一个测试元素的字号,再读取计算样式;若浏览器把它钳制到更大的值,说明该值低于最小字体限制:

js
function minFontSize() {
  const el = document.createElement('span');
  el.style.cssText = 'position:absolute;visibility:hidden;font-size:1px';
  el.textContent = 'x';
  document.body.append(el);
  const size = parseFloat(getComputedStyle(el).fontSize);
  el.remove();
  return size;
}
console.log(minFontSize());

结果受浏览器、系统和缩放设置影响,只代表当前环境。

109. 能否使用自闭合script标签引入脚本文件? ​

答案:

不能把 script 写成 HTML 风格的自闭合标签。HTML 中 <script src="app.js" /> 不会按 XML 规则闭合,可能导致后续内容被当作脚本内容解析。应使用成对标签:

html
<script src="app.js"></script>

自闭合语法只适用于 XML 或 HTML 的 void 元素;script 需要显式结束标签。

110. IconFont 的原理是什么 ​

答案:

IconFont 用 @font-face 加载一个由字形组成的字体文件,每个图标对应一个 Unicode 码位,再通过 font-family 和字符码显示。浏览器按普通文字渲染,因此可用 font-size、color、text-shadow 等 CSS 调整。它本质是矢量字形,不是图片;需处理字体加载失败、码位映射和无障碍文本,复杂多色图标通常更适合 SVG。

111. iconfont是什么?有什么优缺点? ​

答案:

IconFont 是把图标轮廓放进字体文件,用字符码渲染的图标方案。优点是文件通常较小、可缩放、颜色和尺寸可由 CSS 控制,多个图标可合并为一次字体请求。缺点是多色和复杂图形表达弱,依赖字体加载与码位映射,字体基线和抗锯齿可能造成对齐问题;还需补充 aria-label 或隐藏文本,避免只依赖字符语义。

112. css sprites是什么,怎么使用? ​

答案:

CSS Sprites 是把多个小图标合成一张图片,再用背景定位显示指定区域:

css
.icon{width:16px;height:16px;background:url('/sprite.png') no-repeat;}
.icon-search{background-position:-32px 0;}

它能减少请求数和请求头开销,适合稳定的小型位图集合;缺点是制作和定位维护麻烦,修改一个图标可能要重新生成整图,且不如 SVG 适合缩放、主题换色和高分屏。

113. display:none与visibility:hidden 有什么区别? ​

答案:

display:none 会让元素从布局和渲染树中移除,不占空间,也不能获得焦点或响应点击;恢复时通常会触发布局计算。visibility:hidden 保留元素的布局空间,但不可见、不可交互,切换一般只影响绘制,不引起同等范围的回流。前者适合条件渲染或彻底隐藏,后者适合保留布局占位;无障碍语义仍应结合实际需求判断。

114. 你知道哪些css模块化的方案? ​

答案:

常见方案有 CSS Modules、CSS-in-JS,以及命名约定类方案如 BEM。CSS Modules 在构建时为局部类名生成唯一标识,降低全局冲突;CSS-in-JS 把样式与组件绑定,可按 props 动态生成并管理作用域;BEM 依靠规范化命名,不需要特殊运行时。选择时要权衡 SSR、运行时开销、主题能力、调试体验和团队工具链,并明确全局样式入口。

115. 页面统计数据中,常用的 PV、UV 指标分别是什么? ​

答案:

PV(Page View)是页面浏览次数,每次页面被访问或刷新通常计 1 次,同一用户可重复产生多次;UV(Unique Visitor)是一定统计周期内的去重访客数,通常按 Cookie、设备或账号标识估算,同一标识在周期内多次访问只计 1 个。PV 反映访问规模,UV 更接近访客覆盖面,具体口径要以埋点和去重规则为准。

116. 什么是 DOM 和 BOM? ​

答案:

DOM 是文档对象模型,浏览器把 HTML 解析成树,JavaScript 可通过 document 查询、修改节点、属性、文本和事件。BOM 是浏览器对象模型,以 window 为核心,提供 location、history、navigator、screen、定时器等窗口和环境能力。DOM 面向页面文档,BOM 面向浏览器环境;window.document 是二者的连接点。

117. 一台设备的dpr,是否是可变的? ​

答案:

DPR 是设备物理像素与 CSS 逻辑像素的比值,并非永远固定。系统显示缩放、浏览器缩放、外接屏切换、窗口跨屏移动以及部分设备方向变化,都可能让 window.devicePixelRatio 改变;同一设备在不同环境中可能得到不同值。不要把 DPR 写死,应在运行时读取,并用 resolution 媒体查询处理变化。

118. html和css中的图片加载与渲染规则是什么样的? ​

答案:

浏览器先解析 HTML,遇到 <img>、CSS background-image 等资源时按需发起请求;资源下载完成后解码,结合尺寸、CSS 和布局计算决定绘制。img 是 DOM 内容,默认参与布局,未明确尺寸时加载后可能引起布局偏移;背景图不创建独立 DOM 盒子,通常在元素需要绘制且样式生效时加载。图片加载通常不阻塞 HTML 解析,但会影响相关内容的绘制,失败则触发错误状态。

119. meta 标签中的viewport 有什么用? ​

答案:

meta viewport 用于控制移动端布局视口宽度和初始缩放,常用写法是:

html
<meta name="viewport" content="width=device-width, initial-scale=1">

width=device-width 让 CSS 视口与设备宽度匹配,initial-scale=1 设置初始缩放为 1,使媒体查询、vw 和响应式布局按预期工作。应谨慎限制用户缩放,不能为了视觉固定而破坏无障碍放大。

120. CSS中的 “flex:1;” 是什么意思? ​

答案:

flex 是 flex-grow flex-shrink flex-basis 的简写。单值非负数 flex:1 通常等价于 1 1 0%:各子项先按 0 基准尺寸,再按 grow 比例分配容器剩余空间,并允许收缩。它不同于 flex:auto(1 1 auto,基准取自身尺寸),所以多个 flex:1 项通常等宽,但仍受 min-width:auto、内容最小尺寸和容器空间影响,必要时设置 min-width:0。

121. 分析比较 opacity: 0、visibility: hidden、display: none 优劣和适用场景 ​

答案:

display:none 不生成布局盒子,不占空间,也不能点击;切换可能引起回流,适合彻底隐藏。visibility:hidden 保留空间但不可见、不可交互,适合保留布局占位,且该属性可被子元素用 visible 覆盖。opacity:0 保留空间并参与绘制流程,默认仍可点击和获得焦点,适合淡入淡出;需同时处理 pointer-events:none、焦点和无障碍状态。

122. Atom CSS 是什么? ​

答案:

Atom CSS(原子 CSS)把样式拆成职责单一的工具类,一个类通常只负责一个属性或紧密相关的值,例如 .w-full{width:100%}、.text-center{text-align:center}。优点是复用率高、命名冲突少、样式体积和维护范围可控;缺点是 HTML 类名变多、需要记忆约定,复杂组件可读性和调试体验下降。Tailwind CSS 是这类思想的典型实现。

123. CSS中的1像素问题是什么?有哪些解决方案? ​

答案:

高 DPR 屏幕中,一个 CSS 1px 可能对应多个物理像素,边框看起来比设计稿粗,这就是常说的 1px 问题。可用 transform:scale(.5) 缩放伪元素边框,或用 @media (min-resolution:2dppx) 针对 DPR 调整;也可用 border-image、渐变或 box-shadow。伪元素方案通用,但要注意定位、圆角和自身已有伪元素的冲突。

124. css加载会造成阻塞吗? ​

答案:

CSS 下载不会阻塞 HTML/DOM 的继续解析,但渲染树依赖 CSSOM,因此会阻塞页面首次绘制;在其后的同步脚本执行前,浏览器通常也会等待相关样式表完成,以保证脚本读取样式时结果一致。优化可用压缩、缓存、CDN、减少请求和关键 CSS 内联,并避免无关样式阻塞首屏。media 不匹配的样式表通常不阻塞当前渲染,但仍可能下载。

125. CSS 中有哪几种定位方式? ​

答案:

CSS 定位包括:static 正常文档流默认值;relative 相对原位置偏移且仍占位;absolute 脱离文档流,相对最近的非 static 祖先定位;fixed 通常相对视口定位并随页面固定,但祖先的 transform 等可能建立新的定位上下文;sticky 在阈值前像相对定位,滚动到阈值后在容器范围内吸附。z-index 只在合适的定位或布局上下文中控制层叠。

126. 什么是CSS Sprites? ​

答案:

CSS Sprites 是将多个小图标合并成一张图片,通过 background-image、background-repeat:no-repeat 和 background-position 截取显示。例如 .search{width:16px;height:16px;background:url(sprite.png) no-repeat -32px 0}。它能减少请求数,适合固定的位图图标;代价是合图、定位和维护较麻烦,高清缩放、主题换色和动态图标场景通常更适合 SVG 或 IconFont。

127. style标签写在body后与body前有什么区别? ​

答案:

样式应放在 <head> 中。浏览器按文档顺序解析,若把 <style> 或样式表放到 body 后,前面的内容可能先进入解析流程,但渲染仍要等待 CSSOM,样式到达后可能重新计算和绘制,造成首屏闪烁或无样式内容短暂出现。HTML 规范也不鼓励在 body 中放 style;把关键样式放头部、非关键资源延后,更利于稳定首屏。

128. 两个同级的相邻元素之间,有看不见的空白间隔,是什么原因引起的?有什么解决办法? ​

答案:

相邻元素若按行内或 inline-block 排版,HTML 中的换行、空格会被折叠为空白字符,并按当前字体占据宽度,所以出现间隔。可靠方案是使用 Flex/Grid,或删除标签间空白;传统写法可给父元素设置 font-size:0,再给子元素恢复实际字号。也可用负 margin,但数值受字体和浏览器影响,不建议作为通用方案。

129. 如果需要手动写动画,你认为最小时间间隔是多久,为什么? ​

答案:

通常按 60Hz 屏幕计算,动画帧的理论最小间隔约为 1000/60=16.7ms,也就是一帧。实际应使用 requestAnimationFrame,让浏览器按刷新节奏调度;高刷新率设备可能是 8.3ms(120Hz),后台页面还可能被限频,因此不能把 16.7ms 当成绝对定时精度。

130. ::before 和 :after中双冒号和单冒号有什么区别?解释一下这2个伪元素的作用 ​

答案:

单冒号是 CSS2 时代的伪类写法,双冒号是 CSS3 为区分伪元素引入的规范写法;:before 与 ::before、:after 与 ::after 在现代浏览器中通常等价。它们生成不在真实 DOM 树中的可渲染子内容,分别位于元素内容前后,常需配合 content,并可用于装饰,但不能替代语义内容。

131. 元素竖向的百分比设定是相对于容器的高度吗? ​

答案:

不一定。width 的百分比通常相对包含块的宽度;而 height、top、bottom 的百分比通常相对包含块的高度,但前提是包含块高度已明确。padding-top/bottom 和 margin-top/bottom 的百分比在 CSS 中仍按包含块的宽度计算,这是容易混淆的例外。

132. CSS优化、提高性能的方法有哪些? ​

答案:

减少无效样式和重复规则,避免过深的选择器、通配符和不必要的 !important;按组件拆分并复用公共样式,使用语义化类名。动画优先使用 transform、opacity,避免频繁修改会触发大范围布局的属性;批量更新 DOM、减少强制同步布局,并用 DevTools 查看重排、重绘和合成情况。

133. margin和padding分别适合什么场景使用? ​

答案:

margin 表示边框外的间距,用于控制元素与相邻元素或父容器的距离,背景不会延伸到这一区域,垂直外边距还可能发生折叠。padding 表示边框内的内边距,用于拉开内容与边框的距离,背景会覆盖该区域;需要让容器背景或点击区域随间距延伸时应使用它。

134. 什么是CSS媒体查询? ​

答案:

媒体查询是用 @media 根据视口尺寸、分辨率、方向、输入方式等媒体特征有条件地应用 CSS,例如 @media (max-width: 768px) { ... }。它是响应式布局的基础,可按断点调整布局、字号或显示状态;断点应依据内容和布局需求设置,而不是机械套用设备型号。

135. 为什么会出现浮动?什么时候需要清除浮动?清除浮动的方式有哪些? ​

答案:

浮动元素会脱离普通文档流并向左或右排列,后续内容可能环绕它;若父元素只包含浮动子元素,父高度还可能塌陷。因此在需要让父容器包住浮动内容、避免后续布局受影响时清除浮动。常用做法是父元素 display: flow-root,或 ::after { content: ''; display: block; clear: both; };overflow: auto 也可用但要注意裁剪。

136. 什么是BFC? ​

答案:

BFC(Block Formatting Context)是独立的块级格式化上下文。其内部布局与外部隔离,浮动子元素会参与 BFC 高度计算,BFC 不会与浮动盒重叠,同一 BFC 内相邻块的垂直 margin 仍可能折叠。常见触发方式有 display: flow-root、overflow 非 visible、display: flex/grid、浮动或绝对定位;推荐优先用 flow-root 表达意图。

137. CSS3新增伪类有那些? ​

答案:

常见新增伪类包括结构选择的 :first-of-type、:last-of-type、:nth-of-type()、:only-of-type、:nth-child()、:only-child,表单状态的 :enabled、:disabled、:checked、:required、:valid、:invalid,以及交互相关的 :placeholder-shown、:focus-within。要注意 :nth-child() 按所有兄弟元素计数,而 :nth-of-type() 只按同标签类型计数。

138. CSS中,box-sizing属性值有什么用? ​

答案:

box-sizing 决定 width 和 height 的计算范围。默认 content-box 只包含内容,最终占用尺寸还要加上 padding 和 border;border-box 则让指定尺寸包含 content、padding 和 border,更适合表单和响应式布局。常见初始化是 *, *::before, *::after { box-sizing: border-box; },但仍需留意百分比尺寸、最小尺寸和溢出。

139. 前端该如何选择图片的格式? ​

答案:

先按内容和透明需求选择:照片、渐变等真彩图片通常用 JPEG/WebP/AVIF;需要透明、文字或清晰边缘时用 PNG,现代项目优先考虑 WebP/AVIF;简单图标、可缩放图形优先 SVG;动画可选 GIF,但通常 WebP/视频更高效。还应结合浏览器兼容性、尺寸、压缩率和 srcset/picture 做响应式加载,不能只按文件后缀决定。

140. 什么是渐进增强和优雅降级? ​

答案:

渐进增强以基础功能为起点:先用语义 HTML 和可用的基础 CSS,支持能力足够时再增加高级样式和交互。优雅降级则先按现代浏览器实现完整体验,再为旧环境提供可接受的简化版本。前者更稳健、可访问性和兼容性通常更好;两者都应通过能力检测和渐进式特性使用,而不是按浏览器名称硬编码。

141. 前端项目中为什么要初始化CSS样式? ​

答案:

初始化 CSS 是为了消除浏览器默认样式差异,建立统一的盒模型、边距、字体和表单基础,使页面在不同浏览器中有稳定起点。常见内容包括 box-sizing: border-box、清理标题和段落默认 margin、图片 max-width: 100% 等。应按项目需要做小而明确的 reset,避免粗暴清除焦点样式或破坏可访问性。

142. 什么是HTML5,以及和HTML的区别是什么? ​

答案:

HTML5 是 HTML 的现代标准版本,新增语义元素如 header、nav、main、article、section、footer,多媒体 audio、video、canvas,更丰富的表单控件与校验,以及本地存储、离线和 Web API 等能力。它还简化了文档声明并强化语义和可访问性;HTML 是持续演进的标准,HTML5 这个称呼更多是历史版本概念。

143. 说说 HTML、XML、XHTML 的区别 ​

答案:

HTML 是网页标记语言,浏览器按其规范解析并容错;XML 是通用数据标记语言,强调自定义标签、严格嵌套和良构性,不负责页面展示;XHTML 是用 XML 语法约束 HTML 的写法,要求标签闭合、属性加引号且大小写规范。现代网页通常使用 HTML,而不是把 XHTML 当成独立的新渲染技术。

144. 标签上title属性与alt属性的区别是什么? ​

答案:

title 通常提供元素的补充说明,鼠标悬停时可能显示提示,但不应承担关键内容。alt 是图片的替代文本:图片加载失败时显示,并由屏幕阅读器读取;装饰性图片应使用空 alt="",而不是省略。alt 只适用于替代图像内容,不能把两者混为通用提示字段。

145. 页面导入样式时,使用link和@import有什么区别? ​

答案:

<link rel="stylesheet"> 是 HTML 资源关系声明,样式表可并行下载,通常更利于缓存、性能和动态控制;@import 是 CSS 内部规则,往往要先下载并解析外层 CSS 后再发现子样式,可能增加加载链。实际项目优先使用 link;@import 适合构建工具拆分或确有需要的样式组织,且必须放在其他规则之前。

146. CSS匹配规则顺序是怎么样的? ​

答案:

先按来源和重要性分层:浏览器默认样式、用户样式、作者样式,!important 会改变优先级;同一层中再比较选择器的层叠顺序。现代 CSS 还要依次考虑 @layer 层级、选择器优先级、源码顺序,后声明者胜出。优先级通常按 ID、类/属性/伪类、标签/伪元素比较,继承权重最低;不是简单按选择器字符串长度判断。

147. 简单描述从输入网址到页面显示的过程 ​

答案:

输入网址后,浏览器先解析 URL、检查缓存并通过 DNS 将域名解析为 IP;随后建立 TCP 连接,HTTPS 还会进行 TLS 握手,再发送 HTTP 请求。服务器返回响应后,浏览器解析 HTML、CSS 和 JavaScript,构建 DOM、CSSOM,执行脚本并生成渲染树,经过布局、绘制和合成显示。过程中可能复用连接、缓存资源或发生重定向。

148. 简述 html 页面渲染过程 ​

答案:

浏览器先将 HTML 解析为 DOM,将 CSS 解析为 CSSOM;两者结合形成渲染树,通常不包含 display: none 节点。随后进行样式计算和布局,确定每个盒子的几何位置与尺寸,再绘制文字、背景和边框,最后由合成线程合成图层并提交到屏幕。JavaScript、图片加载或字体变化可能触发重新计算、回流或重绘。

149. HTML5 有哪些新特性? ​

答案:

HTML5 常见新特性包括语义化结构标签、audio/video、canvas、SVG 支持、更丰富的表单类型与校验,以及 Web Storage、IndexedDB、Web Worker、地理定位、拖放等 Web API。还支持更简洁的 <!doctype html> 和字符集声明。具体 API 的兼容性并不完全一致,应按目标浏览器做能力检测和降级。

150. <!DOCTYPE html> 标签有什么用? ​

答案:

<!DOCTYPE html> 是文档类型声明,不是普通 HTML 元素。它告诉浏览器按现代标准模式解析页面,避免进入兼容模式;现代 HTML5 写法只需这一行。它不会创建 DOM 节点,也不负责引入脚本、样式或指定字符集。

151. script 标签为什么建议放在 body 标签的底部(defer、async) ​

答案:

普通外链脚本默认会阻塞 HTML 解析,因此常放在 body 底部,让主要 DOM 先生成。更推荐根据依赖关系使用属性:defer 下载不阻塞解析,解析完成后按文档顺序执行,适合依赖 DOM 的脚本;async 也不阻塞下载,但加载完成即执行、顺序不保证,适合彼此独立的统计脚本。内联脚本和动态脚本需另行判断。

152. HTML 标签中的 src 和 href 有什么区别 ​

答案:

src 表示当前元素要加载并嵌入的资源,浏览器通常会发起请求,例如 <script src>、<img src>;缺少资源时元素可能无法正常工作。href 表示当前文档与目标资源或地址之间的引用关系,例如 <a href> 跳转、<link href> 引入样式。两者都能出现 URL,但语义、加载时机和元素行为不同。

153. iframe是什么?有哪些优缺点? ​

答案:

iframe 用于在当前页面嵌入另一个独立浏览上下文,可展示外部页面、地图或视频。优点是内容、脚本和样式隔离,集成第三方功能方便;缺点是额外请求和资源开销、响应式处理麻烦,跨源页面受同源策略限制,SEO、无障碍和安全也需关注。生产环境应配置 sandbox、allow、referrerpolicy,并谨慎允许脚本和权限。

154. canvas在标签上设置宽高,与在style中设置宽高有什么区别? ​

答案:

<canvas width="300" height="150"> 设置的是画布的内部像素缓冲区尺寸,决定绘图坐标系和清晰度;CSS 或 style 设置的是元素在页面中的显示尺寸。只改 CSS 会对已有画布进行缩放,可能造成模糊或比例失真。高 DPI 屏幕通常按 CSS 尺寸 × devicePixelRatio 设置属性尺寸,再用 CSS 控制显示大小。

155. 如何禁用a标签跳转页面或定位链接? ​

答案:

如果链接不承担导航语义,优先改用 button。必须保留 a 时,可在点击处理器中调用 event.preventDefault(),阻止默认跳转;不要依赖 href="javascript:void(0)"。pointer-events: none 只是让鼠标事件穿透,键盘、辅助技术和语义仍可能有问题,因此不能作为通用禁用方案。若是阻止定位,也要避免无意义的 href="#" 改变历史或滚动位置。

156. 行内元素有哪些?块级元素有哪些? 空(void)元素有那些? ​

答案:

行内元素在同一行排列,常见有 span、a、strong、em、img、input;块级元素通常独占一行,如 div、p、h1-h6、ul、ol、li、section。void 元素没有结束标签和子内容,常见有 br、img、input、meta、link、hr。分类是默认 display 行为,CSS 可以改变显示类型。

157. label标签有什么用? ​

答案:

label 用来为表单控件提供可见文本和语义关联。使用 for 指向控件的 id,或把控件嵌套在 label 中;用户点击文字时,浏览器会把焦点交给对应控件,并可触发复选框或单选框切换。这样能扩大点击区域、改善键盘和屏幕阅读器体验;for 的值必须唯一匹配目标控件的 id。

158. 什么是 HTML 语义化? ​

答案:

HTML 语义化是根据内容含义选择合适标签,而不是全部使用 div,例如用 nav 表示导航、main 表示主内容、article 表示独立文章、button 表示操作。它能改善文档结构、可访问性、SEO 和团队维护,并在样式或脚本失效时保留基本语义。语义标签不能自动替代正确的标题层级、键盘交互和 ARIA。

159. script 标签中, async 和 defer 两个属性有什么用途和区别? ​

答案:

defer 和 async 都让外部脚本在 HTML 解析时并行下载。defer 在文档解析完成后执行,多个脚本按出现顺序执行,并在 DOMContentLoaded 前完成,适合依赖 DOM 或彼此有依赖的脚本。async 下载完成后立即执行,执行顺序不保证,可能打断解析,适合独立脚本如统计代码。两者对内联脚本通常没有实际效果。

160. 常用的 meta 元素有哪些? ​

答案:

常用的有 <meta charset="utf-8"> 指定编码,name="viewport" 配置移动端视口,name="description" 提供页面摘要,name="robots" 控制爬虫行为,以及 http-equiv="refresh" 等兼容性声明。社交分享可用 property="og:title"、og:description、og:image。meta 提供机器可读元数据,不会直接显示为页面内容;缓存和安全策略应优先用 HTTP 响应头。

161. grid网格布局是什么? ​

答案:

Grid 是 CSS 的二维布局模型,同时按行和列组织容器及其直接子项,适合页面区域、表格和规则网格。容器使用 display:grid 或 inline-grid,通过 grid-template-columns/rows 定义轨道,gap 设置间距,grid-column/grid-row 或 grid-template-areas 定位项目;fr、repeat()、minmax() 可表达弹性尺寸。它与主要处理一维排列的 Flex 互补。

162. CSS3新增了哪些特性? ​

答案:

CSS3 在兼容 CSS2 的基础上增加了更丰富的选择器(如 :nth-child、:not、属性匹配)、圆角、阴影、渐变、rgba/hsla、background-size,以及 transition、transform、animation 等动画能力;还引入 Flex、Grid、媒体查询、多列布局和 box-sizing 等。实际项目中应注意浏览器兼容性,并用特性检测或降级方案处理旧环境。

163. 怎么使用 CSS3 实现动画? ​

答案:

CSS3 动画主要有两种:transition 适合状态变化,例如 :hover,写明属性、时长、缓动和延迟;animation 配合 @keyframes 定义多阶段、可循环的动画。transform 可完成 translate、scale、rotate、skew,通常与 transition/animation 配合。优先动画 transform 和 opacity,避免频繁改变会触发布局的 width、top 等属性;需要考虑 prefers-reduced-motion。

164. 怎么理解回流跟重绘?什么场景下会触发? ​

答案:

回流(重排)是元素几何信息变化后,浏览器重新计算布局及受影响后代的位置尺寸;重绘是几何不变时重新绘制颜色、阴影等外观。修改 width、height、margin、padding、font-size、DOM 结构或读取 offsetHeight 等布局信息后再写入,可能触发回流;修改 color、background、visibility 常触发重绘。回流通常会连带重绘,批量读写、使用 class、transform/opacity 可降低成本。

165. 什么是响应式设计?响应式设计的基本原理是什么?如何进行实现? ​

答案:

响应式设计是让同一套页面根据视口、设备能力和方向自动适配布局、字号及交互。基本原理是流式布局、弹性尺寸、可伸缩媒体与断点规则结合。实现时使用 flex/grid、百分比、rem、vw/vh,图片设置 max-width:100%,通过 @media 查询在断点调整列数和间距,并在 head 中设置 viewport。断点应按内容需要确定,同时兼顾触控、可读性和性能。

166. 如果使用CSS提高页面性能? ​

答案:

CSS 性能优化可从资源、选择器和渲染三方面入手:压缩并拆分 CSS,删除未使用规则,减少 @import 和重复样式,启用缓存;选择器保持简单,避免过深后代和通配符;优先使用 class,减少频繁改动 DOM。动画尽量只改 transform、opacity,批量读写避免强制同步布局,非首屏样式可延后加载。优化后应结合真实设备的加载、渲染指标验证。

167. 如何实现单行/多行文本溢出的省略样式? ​

答案:

单行省略需限定宽度并隐藏溢出:white-space: nowrap; overflow: hidden; text-overflow: ellipsis;。多行通常使用:display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;,其中 2 是行数。单行省略必须有可计算的宽度,多行方案依赖浏览器支持;若要求跨环境一致,可在业务层按字符或实际高度截断,并注意无障碍文本不能只剩省略号。

168. 如何使用css完成视差滚动效果? ​

答案:

常见纯 CSS 视差做法是让背景相对视口固定或以不同速度移动,例如:.hero{height:100vh;background:url(bg.jpg) center/cover fixed;},滚动时背景相对内容产生错位。也可用多层元素配合 transform: translateZ()、perspective 实现不同深度。background-attachment: fixed 在移动端支持和性能不稳定,复杂场景宜用 IntersectionObserver 或 requestAnimationFrame 控制 transform,并尊重 prefers-reduced-motion。

169. 怎么使用 CSS 如何画一个三角形 ​

答案:

经典做法是利用边框相交:元素宽高设为 0,四条 border 设为透明,只保留目标方向的边框颜色。例如向上三角形:.triangle{width:0;height:0;border-left:20px solid transparent;border-right:20px solid transparent;border-bottom:30px solid #333;}。三角形底边为左右边框之和,高度由可见边框决定;若需要可缩放、渐变或圆角,优先使用 clip-path: polygon() 或 SVG。

170. 怎么让Chrome支持小于12px 的文字? ​

答案:

Chrome 等浏览器通常不会按 CSS 直接显示小于 12px 的中文字体,可通过 transform: scale() 缩放元素实现视觉上的更小文字,例如:.small{font-size:12px;transform:scale(.8);transform-origin:left top;}。缩放会同时影响元素占位和点击区域的视觉关系,需配合固定宽高或布局调整;现代浏览器还应优先确认字体本身和平台渲染效果,避免仅为追求极小字号损害可读性。

171. 说说对 CSS 预编语言的理解,以及它们之间的区别 ​

答案:

CSS 预处理器是在 CSS 之上提供变量、嵌套、函数、混入、模块等能力,编译后生成普通 CSS。Sass/SCSS 功能完整、生态成熟,SCSS 语法接近 CSS;Less 语法简单、与前端工具结合方便;Stylus 语法更自由,可省略括号和分号。它们都需要构建阶段编译,不能直接替代运行时主题能力;若只需变量和嵌套,原生 CSS 自定义属性及新语法也可满足。

172. flexbox(弹性盒布局模型)是什么,适用什么场景? ​

答案:

Flexbox 是 CSS 的一维弹性布局模型,容器沿主轴排列子项,并可在交叉轴对齐、换行和分配剩余空间。display:flex 后,用 flex-direction 定主轴,justify-content 控制主轴分布,align-items 控制交叉轴对齐,flex 设置项目伸缩比例。它适合导航、工具栏、表单行、垂直居中和一维列表;需要同时精确控制行列时更适合 Grid。

173. 如何实现两栏布局,右侧自适应?三栏布局中间自适应呢? ​

答案:

两栏布局可用 Flex:.layout{display:flex}.left{width:240px;flex:none}.right{flex:1;min-width:0},右侧会占据剩余空间,min-width:0 可避免长内容撑破。三栏同理,固定两侧:.main{display:flex}.side{flex:0 0 200px}.center{flex:1;min-width:0}。也可用 Grid:grid-template-columns:200px minmax(0,1fr) 200px。若兼容旧浏览器,还可采用浮动或绝对定位,但维护成本更高。

174. CSS中,有哪些方式可以隐藏页面元素?有什么区别? ​

答案:

display:none 会从布局树移除元素,不占空间,也不能响应事件;visibility:hidden 仍占空间,不响应自身事件,但子元素可单独设为 visible,且可参与过渡;opacity:0 仍占空间,通常仍可响应点击和键盘事件,适合淡出但要同步处理 pointer-events 和可访问性。移出屏幕、裁剪或缩为 0 也能隐藏,但可能仍占布局或影响辅助技术。隐藏内容应根据布局、交互和无障碍目的选择。

175. 设备像素、css像素、设备独立像素、dpr、ppi 之间有什么区别? ​

答案:

设备像素是屏幕硬件的物理像素;CSS 像素是浏览器布局使用的抽象单位;设备独立像素(DIP)是操作系统和设备使用的逻辑像素,Web 中通常与 CSS 像素对应。DPR 为设备像素/CSS 像素,例如 DPR=2 时一个 CSS 像素通常由 2×2 个设备像素绘制。PPI 是屏幕每英寸包含的物理像素数,表示像素密度;它不等同于 DPR,分辨率和屏幕尺寸共同决定 PPI。

176. em/px/rem/vh/vw 这些单位有什么区别? ​

答案:

px 是 CSS 像素,尺寸不随父元素字体变化;em 相对当前元素的字体大小,设置 font-size 时常以父元素为基准,容易层层累积;rem 始终相对根元素 html 的 font-size,适合统一缩放。vw 和 vh 分别等于视口宽、高的 1%,适合响应式尺寸。百分比通常相对父元素,不能简单与 vw/vh 等同;移动端还需注意动态视口和地址栏变化。

177. css选择器有哪些?优先级分别是什么?哪些属性可以继承? ​

答案:

常见选择器有通配、标签、类、ID、属性、后代/子代/兄弟组合器、伪类和伪元素。优先级可按 (内联,ID,类/属性/伪类,标签/伪元素) 比较,逐位比较,后定义只在权重相同时覆盖;!important 会改变正常优先级,应少用。可继承的典型属性是 color、font、line-height、text-align、visibility、list-style;盒模型、定位、背景、边框、宽高、margin/padding 等通常不继承,具体以属性默认的 inherit 规则为准。

178. 说说你对盒子模型的理解 ​

答案:

CSS 盒模型把元素分为 content、padding、border、margin 四层。默认 box-sizing:content-box 时,width/height 只指内容区,实际占用尺寸还要加 padding 和 border,外部间距再加 margin;box-sizing:border-box 时,width/height 包含 padding 和 border,布局更易控制。常用全局设置是 *,*::before,*::after{box-sizing:border-box},但要注意百分比尺寸、滚动条和内容溢出。

基于 VitePress 构建的个人学习文档知识库