前端高频面试题之HTML&CSS篇

150 阅读24分钟

HTML最热门高频30道面试题

前言

HTML、CSS作为前端核心技术之一,在面试中经常被重点考察。本文整理了30道高频HTML、CSS面试题及详细解答,并补充了实用最佳实践,帮助大家备战前端面试。

1. DOCTYPE有什么作用?

答案:DOCTYPE是"Document Type Declaration"的缩写,它告诉浏览器当前HTML文档使用的是什么版本的HTML规范。在HTML5中,只需简单声明<!DOCTYPE html>。不声明DOCTYPE会导致浏览器进入怪异模式(quirks mode),可能导致页面渲染异常。

2. 语义化标签有哪些,有什么作用?

答案:语义化标签包括<header>, <nav>, <main>, <article>, <section>, <aside>, <footer>等。

作用:

  • 增强代码可读性和维护性
  • 有利于SEO优化
  • 提升无障碍访问体验
  • 便于不同设备解析页面结构

3. HTML5新增了哪些特性和API?

答案

  • 语义化标签:<header>, <footer>, <nav>, <section>
  • 音频视频API:<audio>, <video>
  • Canvas和WebGL绘图
  • 本地存储:localStorage, sessionStorage
  • Web Workers多线程处理
  • Geolocation地理位置
  • 拖放API
  • WebSocket通信协议
  • 表单控件:date, time, email, url等
  • History API

4. <script>标签的defer和async有什么区别?

答案

  • 普通<script>:加载和执行都会阻塞HTML解析
  • <script defer>:异步加载,等DOM解析完成后执行,多个defer脚本按照在文档中出现的顺序执行
  • <script async>:异步加载,加载完成后立即执行,执行时会阻塞HTML解析,多个async脚本执行顺序不确定

5. 行内元素和块级元素有什么区别?常见的有哪些?

答案: 区别:

  • 块级元素:独占一行,可设置宽高
  • 行内元素:与其他元素共享一行,不可设置宽高

常见块级元素:<div>, <p>, <h1>~<h6>, <ul>, <li>, <table>等 常见行内元素:<span>, <a>, <strong>, <em>, <img>, <input>

6. 如何理解HTML语义化?

答案:HTML语义化是指使用恰当的HTML标签来表达内容的结构和含义,而不仅仅是视觉效果。好的语义化有助于:

  • 代码可读性和可维护性
  • 搜索引擎优化
  • 屏幕阅读器等辅助技术的支持
  • 不同设备和浏览器的适配

7. meta标签有哪些常见用法?

答案

<!-- 字符编码 -->
<meta charset="UTF-8">

<!-- 视口设置,用于响应式布局 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- 页面描述,利于SEO -->
<meta name="description" content="网站描述内容">

<!-- 关键词,利于SEO -->
<meta name="keywords" content="关键词1,关键词2">

<!-- 页面重定向 -->
<meta http-equiv="refresh" content="3;url=https://www.example.com">

<!-- 禁止缓存 -->
<meta http-equiv="cache-control" content="no-cache">

8. HTML5的离线存储怎么使用?

答案:HTML5离线存储(Application Cache)使用manifest文件实现,但已被弃用,现代浏览器推荐使用Service Worker代替:

旧方式(不推荐):

<!DOCTYPE html>
<html manifest="example.appcache">
...
</html>

现代方式(Service Worker):

// 注册Service Worker
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
  .then(function(registration) {
    console.log('ServiceWorker注册成功');
  })
  .catch(function(err) {
    console.log('ServiceWorker注册失败', err);
  });
}

9. 常见的浏览器内核有哪些?

答案

  • Trident (IE内核)
  • Gecko (Firefox内核)
  • WebKit (Safari内核)
  • Blink (Chrome, Opera, Edge新版内核,基于WebKit分支)

10. 常见的网页图片格式有哪些?如何选择?

答案

  • JPG:有损压缩,适合照片等复杂色彩的图像
  • PNG:无损压缩,支持透明度,适合图标、插图等
  • GIF:支持简单动画,最多256色,适合简单动画
  • SVG:矢量图形,缩放不失真,适合图标和简单图形
  • WebP:Google开发的格式,同时支持有损和无损压缩,支持动画和透明度
  • AVIF:更新的格式,比WebP更好的压缩效果

选择原则:根据图片内容和使用场景选择合适格式,平衡质量和文件大小。

11. HTML表单提交的方式有哪些?

答案

  • GET:参数拼接在URL上,有长度限制,不安全,幂等性操作
  • POST:参数在请求体中,更安全,无长度限制,适合发送敏感数据
  • PUT:更新资源
  • DELETE:删除资源
<form method="post" action="/submit">
  <!-- 表单内容 -->
</form>

12. HTML5中的Canvas和SVG有什么区别?

答案

  • Canvas是基于像素的即时绘图API,使用JavaScript绘制,适合复杂动画和像素处理
  • SVG是基于XML的矢量图形,可缩放不失真,DOM可操作,适合静态图形和交互式图表

Canvas优势:渲染性能高,适合游戏和复杂动画 SVG优势:矢量可缩放,DOM可操作,适合需要交互的图表

13. 如何实现无障碍访问(Accessibility)?

答案

  • 使用语义化标签
  • 为图片添加alt属性
  • 使用适当的表单标签和label
  • 确保键盘可导航
  • 使用ARIA(Accessible Rich Internet Applications)属性
  • 适当的色彩对比度
  • 确保可读的字体大小
<!-- 好的实践 -->
<img src="logo.png" alt="公司Logo">
<label for="username">用户名</label>
<input type="text" id="username">

14. 什么是data-*属性?

答案:data-*属性允许在标准标签上存储额外信息,不会对页面展示产生影响,可通过JavaScript的dataset属性获取。

<div id="user" data-id="123" data-role="admin">用户信息</div>

<script>
  const el = document.getElementById('user');
  console.log(el.dataset.id);  // "123"
  console.log(el.dataset.role); // "admin"
</script>

15. 如何理解HTML的可访问性?

答案:HTML可访问性是指让各类用户(包括残障用户)都能无障碍地访问和使用网站。实现方式包括:

  • 使用语义化标签
  • 为非文本内容提供替代文本
  • 使内容易于导航
  • 确保表单易于使用
  • 提供足够的对比度
  • 遵循WCAG (Web Content Accessibility Guidelines)准则

16. 谈谈你对HTML5 Web Workers的理解?

答案:Web Workers提供了在后台线程运行JavaScript的能力,不会阻塞主线程(UI线程)。主要用于处理耗时计算,提高web应用性能。

// 创建Worker
const worker = new Worker('worker.js');

// 发送消息到Worker
worker.postMessage({data: '发送数据到Worker'});

// 接收Worker消息
worker.onmessage = function(e) {
  console.log('接收到Worker消息:', e.data);
};

17. 如何在HTML中嵌入音频和视频?

答案:HTML5提供了<audio><video>标签:

<!-- 音频 -->
<audio controls>
  <source src="audio.mp3" type="audio/mpeg">
  <source src="audio.ogg" type="audio/ogg">
  您的浏览器不支持音频标签
</audio>

<!-- 视频 -->
<video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  您的浏览器不支持视频标签
</video>

18. HTML5拖放API如何使用?

答案

<!-- 拖动元素 -->
<div id="draggable" draggable="true">拖我</div>

<!-- 放置区域 -->
<div id="droptarget">放置区域</div>

<script>
  const draggable = document.getElementById('draggable');
  const droptarget = document.getElementById('droptarget');
  
  // 拖动开始
  draggable.addEventListener('dragstart', (e) => {
    e.dataTransfer.setData('text/plain', e.target.id);
  });
  
  // 阻止默认行为以允许放置
  droptarget.addEventListener('dragover', (e) => {
    e.preventDefault();
  });
  
  // 处理放置
  droptarget.addEventListener('drop', (e) => {
    e.preventDefault();
    const id = e.dataTransfer.getData('text/plain');
    e.target.appendChild(document.getElementById(id));
  });
</script>

19. iframe的优缺点?

答案: 优点:

  • 加载第三方内容而不影响主页面
  • 沙箱隔离,提高安全性
  • 实现跨域通信

缺点:

  • 阻塞页面加载
  • SEO不友好
  • 安全隐患(点击劫持等)
  • 不适合响应式设计

20. HTML5的地理位置API如何使用?

答案

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(
    // 成功回调
    (position) => {
      const latitude = position.coords.latitude;
      const longitude = position.coords.longitude;
      console.log(`纬度: ${latitude}, 经度: ${longitude}`);
    },
    // 失败回调
    (error) => {
      console.error('获取位置失败:', error.message);
    },
    // 选项
    {
      enableHighAccuracy: true, // 高精度
      timeout: 5000, // 超时时间
      maximumAge: 0 // 缓存时间
    }
  );
} else {
  console.error('浏览器不支持地理位置API');
}

21. LocalStorage和SessionStorage有什么区别?

答案: 共同点:

  • 都是客户端存储,容量约5MB
  • 只能存储字符串数据
  • 同源策略限制

区别:

  • LocalStorage:永久存储,除非手动清除
  • SessionStorage:会话级存储,关闭页面/浏览器后清除
// LocalStorage
localStorage.setItem('key', 'value');
const value = localStorage.getItem('key');
localStorage.removeItem('key');

// SessionStorage
sessionStorage.setItem('key', 'value');
const value = sessionStorage.getItem('key');
sessionStorage.removeItem('key');

22. 什么是HTML的事件委托?

答案:事件委托是利用事件冒泡机制,将事件处理器添加到父元素而不是每个子元素上。优点是减少事件处理器数量,提高性能,并能处理动态添加的元素。

// 不使用事件委托
document.querySelectorAll('li').forEach(item => {
  item.addEventListener('click', function() {
    console.log('点击了:', this.textContent);
  });
});

// 使用事件委托
document.querySelector('ul').addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    console.log('点击了:', e.target.textContent);
  }
});

23. 什么是WebSocket?

答案:WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许服务器与客户端之间持久连接并进行双向通信。

// 创建WebSocket连接
const ws = new WebSocket('wss://example.com/socket');

// 连接建立时触发
ws.onopen = function() {
  console.log('连接已建立');
  ws.send('Hello Server!');
};

// 接收消息时触发
ws.onmessage = function(evt) {
  console.log('接收到消息:', evt.data);
};

// 连接关闭时触发
ws.onclose = function() {
  console.log('连接已关闭');
};

24. HTML5中如何实现客户端存储?

答案:HTML5提供多种客户端存储方式:

  • localStorage:持久化存储
  • sessionStorage:会话级存储
  • IndexedDB:客户端数据库,可存储复杂数据结构
  • Cache API:与Service Worker结合使用
  • Web SQL:已废弃

25. 如何进行HTML的性能优化?

答案

  • 减少HTTP请求(合并CSS/JS,使用CSS Sprite)
  • 压缩CSS、JavaScript和图片
  • 使用CDN加载资源
  • 异步加载JavaScript(async/defer)
  • 延迟加载非关键资源
  • 减少DOM操作和重绘/回流
  • 使用适当的图片格式和大小
  • 启用Gzip压缩
  • 使用浏览器缓存
  • 减少重定向

26. 如何处理HTML表单的跨站请求伪造(CSRF)?

答案

  • 使用CSRF令牌:服务器生成令牌,客户端提交时验证
  • 检查Referer头
  • 使用SameSite Cookie属性
  • 双重Cookie验证
<form method="post" action="/submit">
  <!-- CSRF令牌 -->
  <input type="hidden" name="csrf_token" value="随机生成的令牌">
  <!-- 其他表单字段 -->
</form>

27. 说说对于HTML5的离线应用缓存的理解?

答案:HTML5的离线应用缓存(AppCache)已被弃用,现代浏览器更推荐使用Service Worker实现离线功能。Service Worker提供更精细的缓存控制,可以拦截网络请求并使用缓存响应,实现离线应用、推送通知等功能。

// 注册Service Worker
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
  .then(function(registration) {
    console.log('ServiceWorker注册成功');
  });
}

// sw.js中缓存资源
self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/app.js',
        '/image.jpg'
      ]);
    })
  );
});

28. HTML中的attribute和property有什么区别?

答案

  • attribute:HTML标签上定义的属性,是DOM元素的初始值
  • property:DOM对象属性,是元素在JavaScript中的属性值
<input id="myInput" type="text" value="初始值">

<script>
  const input = document.getElementById('myInput');
  
  // attribute
  console.log(input.getAttribute('value')); // "初始值"
  
  // 修改输入框的值
  input.value = "新值";
  
  // attribute保持不变
  console.log(input.getAttribute('value')); // 仍然是"初始值"
  
  // property已经改变
  console.log(input.value); // "新值"
</script>

29. HTML5中的WebStorage和Cookie有什么区别?

答案

  • 存储大小:Cookie约4KB,WebStorage约5MB
  • 请求携带:Cookie每次请求都会携带,WebStorage不会
  • 操作方式:Cookie操作复杂,WebStorage API简单
  • 有效期:Cookie可设置过期时间,localStorage永久,sessionStorage会话期间
  • 作用域:Cookie可跨域设置,localStorage和sessionStorage同源限制

30. HTML中的块级元素、行内元素、行内块元素有什么区别?

答案

  1. 块级元素(block):

    • 独占一行
    • 可设置宽高、边距
    • 例如:div, p, h1-h6, ul, li, table
  2. 行内元素(inline):

    • 与其他元素共享一行
    • 不可设置宽高
    • 水平方向margin/padding有效,垂直方向无效
    • 例如:span, a, strong, em
  3. 行内块元素(inline-block):

    • 与其他元素共享一行
    • 可设置宽高、边距
    • 例如:img, input, button
.block {
  display: block;
}
.inline {
  display: inline;
}
.inline-block {
  display: inline-block;
}

CSS基础概念题

1. CSS选择器优先级如何计算?

答案:CSS选择器优先级按照权重计算:

  • !important 优先级最高

  • 内联样式(1000)

  • ID选择器(100)

  • 类选择器/属性选择器/伪类选择器(10)

  • 标签选择器/伪元素选择器(1)

  • 通配符选择器(0)

优先级相同时,后声明的样式覆盖先声明的样式。

最佳实践

  • 避免使用!important,会破坏选择器优先级规则

  • 减少ID选择器使用,优先使用类选择器

  • 选择器不要超过3层,减少特异性冲突

  • 使用BEM等命名规范减少选择器嵌套

2. CSS盒模型有哪几种?区别是什么?

答案:CSS盒模型分为标准盒模型和IE盒模型:

  • 标准盒模型(content-box):width/height只包含内容区域,不包含padding和border

  • IE盒模型(border-box):width/height包含内容区域、padding和border

通过box-sizing属性可以切换盒模型。

最佳实践


/* 全局应用border-box */

html {

  box-sizing: border-box;

}

*, *:before, *:after {

  box-sizing: inherit;

}

3. 什么是BFC?如何触发BFC?

答案:BFC(Block Formatting Context)是块级格式化上下文,是CSS渲染的一部分,具有独立的渲染区域。

触发BFC的方法:

  • float值不为none

  • position值为absolute或fixed

  • display值为inline-block、table-cell、table-caption、flex、grid

  • overflow值不为visible

  • contain值为layout、content或strict

BFC特性:

  • 内部元素不会影响外部元素

  • 不会与浮动元素重叠

  • 可以包含浮动元素

  • 可以阻止外边距折叠

最佳实践

  • 清除浮动:overflow: hidden

  • 防止外边距折叠:给父元素设置overflow: hidden

  • 自适应两栏布局:一栏浮动,一栏触发BFC

4. 解释CSS中的继承和层叠

答案

  • 继承:子元素自动获取父元素的某些CSS属性(如color、font-size等)

  • 层叠:当多个规则应用于同一元素时,根据优先级和出现顺序决定最终样式

不可继承的属性包括:width、height、margin、padding、border等。

5. display的常见属性值及作用

答案

  • block:块级元素,占据一整行

  • inline:行内元素,不会独占一行

  • inline-block:行内块元素,不会独占一行但可设置宽高

  • none:元素不显示且不占位置

  • flex:弹性布局

  • grid:网格布局

  • table:表格布局

布局相关题

6. CSS实现水平垂直居中的方法有哪些?

答案

  1. flex布局

.parent {

  display: flex;

  justify-content: center;

  align-items: center;

}

  1. grid布局

.parent {

  display: grid;

  place-items: center;

}

  1. 绝对定位 + transform

.parent {

  position: relative;

}

.child {

  position: absolute;

  top: 50%;

  left: 50%;

  transform: translate(-50%, -50%);

}

  1. 绝对定位 + margin: auto

.parent {

  position: relative;

}

.child {

  position: absolute;

  top: 0;

  left: 0;

  right: 0;

  bottom: 0;

  margin: auto;

  height: 100px;

  width: 100px;

}

最佳实践

  • 对于现代浏览器,优先使用flex或grid布局

  • 当不确定子元素尺寸时,使用transform方案

  • 需要兼容旧浏览器时,可结合多种方案

7. Flex布局中的主要属性及作用

答案

容器属性:

  • display: flex

  • flex-direction: 主轴方向

  • justify-content: 主轴对齐方式

  • align-items: 交叉轴对齐方式

  • flex-wrap: 是否换行

  • align-content: 多行对齐方式

项目属性:

  • order: 排列顺序

  • flex-grow: 放大比例

  • flex-shrink: 缩小比例

  • flex-basis: 初始大小

  • flex: 上面三个属性的简写

  • align-self: 单独对齐方式

最佳实践

  • 尽量使用简写属性flex: 1替代分开写法

  • 设置flex-wrap: wrap防止内容溢出

  • 使用gap属性设置间距,替代margin

8. 如何实现两栏布局和三栏布局?

答案

两栏布局:

  1. float + margin-left

  2. position + margin-left

  3. flex布局


.container {

  display: flex;

}

.left {

  width: 200px;

}

.right {

  flex: 1;

}

三栏布局:

  1. 圣杯布局

  2. 双飞翼布局

  3. flex布局


.container {

  display: flex;

}

.left, .right {

  width: 200px;

}

.middle {

  flex: 1;

}

最佳实践

  • 优先使用flex布局实现多栏布局

  • 考虑移动端优先,使用媒体查询实现响应式布局

  • 使用CSS变量控制侧栏宽度,方便统一修改

9. 解释CSS Grid布局的基本概念

答案:CSS Grid是二维布局系统,可同时处理行和列。

主要属性:

  • display: grid

  • grid-template-columns/grid-template-rows: 定义列/行大小

  • grid-gap: 行列间距

  • grid-template-areas: 区域命名和布局

项目属性:

  • grid-column/grid-row: 指定项目位置

  • grid-area: 指定项目放在哪个区域

最佳实践


/* 使用fr单位创建灵活的列宽 */

.grid {

  display: grid;

  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

  gap: 20px;

}
 


/* 命名区域创建复杂布局 */

.layout {

  display: grid;

  grid-template-areas:

    "header header header"

    "sidebar content content"

    "footer footer footer";

  grid-template-rows: auto 1fr auto;

  grid-template-columns: 200px 1fr 1fr;

}

10. 如何实现固定页脚?

答案

  1. flex方案

body {

  display: flex;

  flex-direction: column;

  min-height: 100vh;

}

main {

  flex: 1;

}

  1. grid方案

body {

  display: grid;

  grid-template-rows: auto 1fr auto;

  min-height: 100vh;

}

最佳实践

  • 设置html, bodyheight: 100%确保全屏高度

  • 使用CSS变量控制页眉页脚高度,便于统一维护

定位与浮动

11. position属性的值及其区别

答案

  • static:默认值,按文档流定位

  • relative:相对定位,相对于自身原位置

  • absolute:绝对定位,相对于最近的非static祖先元素

  • fixed:固定定位,相对于视口

  • sticky:粘性定位,基于用户滚动位置

最佳实践

  • 使用relative创建定位上下文,不要过度依赖absolute

  • sticky定位需设置至少一个方向的偏移量值(top/right/bottom/left)

  • 避免使用fixed在移动端,会有兼容性问题

12. 清除浮动的方法有哪些?

答案

  1. 父元素设置overflow

.parent {

  overflow: hidden; /* 或auto/scroll */

}

  1. 使用伪元素

.clearfix::after {

  content: "";

  display: block;

  clear: both;

}

  1. 父元素也浮动

  2. 父元素设置高度

最佳实践


/* 现代化清除浮动方案 */

.clearfix::after {

  content: "";

  display: table;

  clear: both;

}

  


/* 或使用display: flow-root(IE不支持) */

.modern-clearfix {

  display: flow-root;

}

13. z-index属性如何影响元素层叠顺序?

答案

  • 只对定位元素(position非static)生效

  • 数值越大,层叠顺序越高

  • 父元素z-index会影响子元素层叠顺序

  • 形成层叠上下文的元素会限制其子元素的z-index作用范围

最佳实践

  • 使用CSS变量管理z-index值,便于维护

:root {

  --z-header: 100;

  --z-modal: 200;

  --z-tooltip: 300;

}

.header { z-index: var(--z-header); }

.modal { z-index: var(--z-modal); }

  • 避免不必要的z-index,只在必要时设置

  • 使用合理的步进值(如10,100)便于后续插入新值

响应式设计

14. 如何实现响应式设计?

答案

  1. 媒体查询(Media Query)

  2. 百分比布局

  3. rem/em等相对单位

  4. flex/grid布局

  5. viewport设置

基本媒体查询示例:


@media screen and (max-width: 768px) {

  .container {

    width: 100%;

  }

}

最佳实践


/* 使用变量定义断点 */

:root {

  --breakpoint-sm: 576px;

  --breakpoint-md: 768px;

  --breakpoint-lg: 992px;

  --breakpoint-xl: 1200px;

}

  


/* 移动优先设计 */

.container {

  width: 100%;

  padding: 0 15px;

}

  


@media (min-width: 768px) {

  .container {

    max-width: 720px;

    margin: 0 auto;

  }

}

  


/* 使用容器查询(Container Query)更精确控制布局 */

.card-container {

  container-type: inline-size;

}

  


@container (min-width: 400px) {

  .card {

    display: flex;

  }

}

15. rem、em、px、vw/vh有什么区别?

答案

  • px:绝对长度单位,不会缩放

  • em:相对于父元素字体大小

  • rem:相对于根元素(html)字体大小

  • vw/vh:视口宽度/高度的1%

  • vmin/vmax:视口较小/较大尺寸的1%

最佳实践


/* 使用rem实现全局缩放 */

html {

  font-size: 62.5%; /* 10px = 1rem */

}

  


body {

  font-size: 1.6rem; /* 16px */

}

  


/* 结合使用不同单位 */

.container {

  width: 90%; /* 相对父元素 */

  max-width: 1200px; /* 最大宽度 */

  padding: 2rem; /* 相对于根元素字体大小 */

  margin-bottom: 5vh; /* 相对视口高度 */

}

16. 如何处理Retina屏幕的图片模糊问题?

答案

  1. 使用2x或3x图片,设置img尺寸为1x

  2. 使用媒体查询识别高DPI屏幕


@media (min-device-pixel-ratio: 2) {

  .logo {

    background-image: url(logo@2x.png);

  }

}

  1. 使用SVG图片

  2. 使用CSS3的transform:scale()放大

最佳实践


/* 使用现代CSS属性 */

.image {

  background-image: image-set(

    url("image.png") 1x,

    url("image@2x.png") 2x,

    url("image@3x.png") 3x

  );

}

  


/* 使用picture元素 */

<picture>

  <source srcset="image@2x.png 2x, image@3x.png 3x" />

  <img src="image.png" alt="高清图片" />

</picture>

  


/* 优先使用SVG图标 */

.icon {

  background-image: url(icon.svg);

  background-size: contain;

}

动画与过渡

17. transition和animation的区别

答案

  • transition:过渡效果,需要触发事件,只有开始和结束两个状态

  • animation:动画效果,可自动播放,可设置多个关键帧

最佳实践


/* 合理使用简写属性 */

.button {

  transition: all 0.3s ease-in-out;

}

  


/* 显式指定所有值,提高性能 */

.button-optimized {

  transition: transform 0.3s ease-in-out, background-color 0.3s linear;

}

18. 如何优化CSS动画性能?

答案

  1. 使用transform和opacity属性(不会触发重排)

  2. 使用will-change提示浏览器

  3. 使用GPU加速:transform: translateZ(0)

  4. 减少同时执行的动画数量

  5. 避免使用JavaScript频繁修改样式

最佳实践


/* 性能优化动画示例 */

.optimized-animation {

  /* 使用transform替代left/top */

  transform: translateX(100px);

  

  /* 使用opacity替代display或visibility */

  opacity: 0;

  

  /* 提前告知浏览器优化 */

  will-change: transform, opacity;

  

  /* 在动画不活跃时移除will-change */

}

  


/* JavaScript添加移除will-change */

const el = document.querySelector('.animation');

  


el.addEventListener('mouseenter', () => {

  el.style.willChange = 'transform';

});

  


el.addEventListener('animationEnd', () => {

  el.style.willChange = 'auto';

});

19. @keyframes规则的使用方法

答案


@keyframes bounce {

  0% {

    transform: translateY(0);

  }

  50% {

    transform: translateY(-20px);

  }

  100% {

    transform: translateY(0);

  }

}

  


.element {

  animation: bounce 2s infinite;

}

最佳实践


/* 使用CSS变量控制动画 */

:root {

  --animation-distance: 20px;

  --animation-duration: 2s;

}

  


@keyframes bounce {

  0%, 100% { transform: translateY(0); }

  50% { transform: translateY(calc(-1 * var(--animation-distance))); }

}

  


.element {

  animation: bounce var(--animation-duration) infinite;

}

  


/* 响应式动画 */

@media (prefers-reduced-motion: reduce) {

  :root {

    --animation-duration: 0s; /* 禁用动画 */

  }

}

预处理器与架构

20. 谈谈CSS预处理器(SASS/LESS)的优缺点

答案

优点:

  • 变量定义和使用

  • 嵌套规则减少重复代码

  • 混合(Mixins)复用代码

  • 函数和运算能力

  • 模块化开发

缺点:

  • 需要编译工具

  • 调试困难

  • 团队需要统一学习成本

最佳实践


// 变量使用一致命名规范

$color-primary: #4CAF50;

$color-secondary: #FFC107;

$spacing-sm: 8px;

$spacing-md: 16px;

$spacing-lg: 24px;

  


// 使用mixins复用代码

@mixin flex-center {

  display: flex;

  justify-content: center;

  align-items: center;

}

  


// 控制嵌套深度不超过3层

.card {

  border: 1px solid $color-primary;

  padding: $spacing-md;

  

  &__header {

    @include flex-center;

    margin-bottom: $spacing-sm;

    

    &-title {

      font-size: 18px;

    }

  }

  

  // 使用BEM避免深层嵌套

  &__body-text {

    line-height: 1.5;

  }

}

21. CSS架构方法论(BEM/OOCSS/SMACSS)的特点

答案

  • BEM(Block-Element-Modifier):强调模块独立性和可重用性

  - .block__element--modifier

  • OOCSS(Object Oriented CSS):分离结构和皮肤,容器和内容

  • SMACSS(Scalable and Modular Architecture for CSS):将CSS分为基础、布局、模块、状态、主题5类

  • Atomic CSS:原子化CSS,每个类只做一件事

最佳实践


/* BEM命名方式 */

.card {}

.card__title {}

.card__image {}

.card--featured {}

  


/* OOCSS分离结构和皮肤 */

.btn {} /* 结构 */

.btn-primary {} /* 皮肤 */

.btn-large {} /* 尺寸修饰符 */

  


/* SMACSS分类示例 */

/* 基础样式 */

body, h1, p {}

  


/* 布局样式 */

.l-header, .l-sidebar, .l-content {}

  


/* 模块样式 */

.modal {}

.modal-title {}

  


/* 状态样式 */

.is-active, .is-hidden {}

  


/* 结合使用原子CSS加速开发 */

.mt-10 { margin-top: 10px; }

.flex { display: flex; }

.items-center { align-items: center; }

高级技巧

22. 如何实现一个三角形?

答案


.triangle {

  width: 0;

  height: 0;

  border-left: 50px solid transparent;

  border-right: 50px solid transparent;

  border-bottom: 100px solid red;

}

最佳实践


/* 使用伪元素创建三角形 */

.tooltip {

  position: relative;

}

.tooltip::after {

  content: "";

  position: absolute;

  top: 100%;

  left: 50%;

  transform: translateX(-50%);

  border-left: 8px solid transparent;

  border-right: 8px solid transparent;

  border-top: 8px solid black;

}

  


/* CSS变量控制三角形 */

:root {

  --triangle-size: 10px;

  --triangle-color: #333;

}

  


.triangle {

  --half-size: calc(var(--triangle-size) / 2);

  border-left: var(--half-size) solid transparent;

  border-right: var(--half-size) solid transparent;

  border-bottom: var(--triangle-size) solid var(--triangle-color);

}

23. CSS中如何实现溢出文本显示省略号?

答案

单行文本:


.ellipsis {

  white-space: nowrap;

  overflow: hidden;

  text-overflow: ellipsis;

}

多行文本:


.multi-ellipsis {

  display: -webkit-box;

  -webkit-line-clamp: 2;

  -webkit-box-orient: vertical;

  overflow: hidden;

}

最佳实践


/* 创建可重用的工具类 */

.text-ellipsis {

  white-space: nowrap;

  overflow: hidden;

  text-overflow: ellipsis;

  max-width: 100%;

}

  


/* 可配置多行省略 */

.line-clamp {

  display: -webkit-box;

  -webkit-box-orient: vertical;

  overflow: hidden;

}

.line-clamp-2 { -webkit-line-clamp: 2; }

.line-clamp-3 { -webkit-line-clamp: 3; }

  


/* 添加兼容性回退 */

.multi-ellipsis {

  display: -webkit-box;

  -webkit-line-clamp: 2;

  -webkit-box-orient: vertical;

  overflow: hidden;

  /* 回退方案 */

  max-height: 3em; /* 约等于2行 */

}

24. 如何实现自适应正方形?

答案

方法1:vw单位


.square {

  width: 50vw;

  height: 50vw;

}

方法2:padding撑开


.square {

  width: 100%;

  padding-bottom: 100%;

  height: 0;

  position: relative;

}

.content {

  position: absolute;

  width: 100%;

  height: 100%;

}

最佳实践


/* 使用aspect-ratio属性(现代浏览器) */

.modern-square {

  width: 100%;

  aspect-ratio: 1 / 1;

}

  


/* 自定义比例组件 */

.aspect-ratio {

  position: relative;

  width: 100%;

}

.aspect-ratio::before {

  content: "";

  display: block;

  padding-bottom: var(--aspect-ratio, 100%);

}

.aspect-ratio > * {

  position: absolute;

  top: 0;

  left: 0;

  width: 100%;

  height: 100%;

}

  


/* 使用 */

.square { --aspect-ratio: 100%; }

.video { --aspect-ratio: 56.25%; /* 16:9 */ }

25. CSS如何实现一个自定义复选框?

答案


.custom-checkbox {

  position: relative;

  padding-left: 30px;

  cursor: pointer;

}

.custom-checkbox input {

  position: absolute;

  opacity: 0;

}

.checkmark {

  position: absolute;

  top: 0;

  left: 0;

  height: 20px;

  width: 20px;

  background-color: #eee;

}

.custom-checkbox input:checked ~ .checkmark {

  background-color: #2196F3;

}

.checkmark:after {

  content: "";

  position: absolute;

  display: none;

}

.custom-checkbox input:checked ~ .checkmark:after {

  display: block;

  left: 7px;

  top: 3px;

  width: 5px;

  height: 10px;

  border: solid white;

  border-width: 0 2px 2px 0;

  transform: rotate(45deg);

}

最佳实践


/* 现代方法:使用:has伪类 */

input[type="checkbox"] {

  appearance: none;

  width: 20px;

  height: 20px;

  border: 2px solid #555;

  border-radius: 3px;

  position: relative;

}

  


input[type="checkbox"]:checked {

  background-color: #4CAF50;

  border-color: #4CAF50;

}

  


input[type="checkbox"]:checked::after {

  content: "";

  position: absolute;

  left: 6px;

  top: 2px;

  width: 5px;

  height: 10px;

  border: solid white;

  border-width: 0 2px 2px 0;

  transform: rotate(45deg);

}

  


/* 无障碍优化 */

input[type="checkbox"]:focus-visible {

  outline: 2px solid #4CAF50;

  outline-offset: 2px;

}

兼容性与优化

26. 如何处理CSS浏览器兼容性问题?

答案

  1. 使用CSS Reset或Normalize.css统一默认样式

  2. 添加浏览器前缀(-webkit-, -moz-, -ms-, -o-)

  3. 使用Autoprefixer等自动添加前缀工具

  4. 避免使用新特性或提供降级方案

  5. 使用@supports检测特性支持情况

最佳实践


/* 使用@supports检测功能支持 */

.card {

  display: block; /* 回退方案 */

}

@supports (display: flex) {

  .card {

    display: flex;

  }

}

  


/* 渐进增强 */

.gradient-bg {

  background-color: #3498db; /* 回退颜色 */

  background-image: linear-gradient(to right, #3498db, #2ecc71);

}

  


/* 使用现代工具链 */

/* postcss.config.js */

module.exports = {

  plugins: [

    require('autoprefixer'),

    require('postcss-preset-env')({

      stage: 3,

      features: {

        'nesting-rules': true

      }

    })

  ]

}

27. CSS性能优化的方法有哪些?

答案

  1. 减少选择器复杂度

  2. 避免使用通配符和属性选择器

  3. 避免使用!important

  4. 压缩CSS文件

  5. 合理使用CSS继承

  6. 使用CSS预处理器组织代码

  7. CSS精灵图减少HTTP请求

  8. 按需加载CSS

最佳实践


/* 避免过度嵌套和低效选择器 */

/* 不推荐 */

body div.container ul li a.link { color: red; }

  


/* 推荐 */

.link { color: red; }

  


/* 利用继承减少重复声明 */

/* 不推荐 */

.button, .btn-primary, .btn-secondary {

  font-family: Arial;

  font-size: 14px;

  text-transform: uppercase;

}

  


/* 推荐 */

.button {

  font-family: Arial;

  font-size: 14px;

  text-transform: uppercase;

}

.btn-primary { color: blue; }

.btn-secondary { color: gray; }

  


/* 按需加载CSS */

<!-- 关键CSS内联 -->

<style>

  /* 关键渲染路径CSS */

</style>

  


<!-- 非关键CSS异步加载 -->

<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

<noscript><link rel="stylesheet" href="styles.css"></noscript>

28. 什么是CSS Containment?

答案

CSS Containment(CSS包含)是通过contain属性将元素和它的内容与文档其余部分隔离,提升性能。

主要值:

  • layout:元素外部布局不受其内部影响

  • paint:元素后代不会绘制到元素边界之外

  • size:元素大小不受其后代影响

  • content:包含layout和paint

  • strict:包含layout、paint和size


.container {

  contain: layout paint;

}

最佳实践


/* 长列表优化 */

.item-list {

  contain: content;

}

  


/* 独立小部件优化 */

.widget {

  contain: strict;

  /* 当strict可能导致问题时,使用更具体的值 */

}

  


/* 结合使用will-change和contain */

.animated-container {

  contain: layout paint;

  will-change: transform;

}

29. 解释CSS变量(自定义属性)及其应用

答案

CSS变量是由开发者定义的实体,包含可重用的值:


:root {

  --main-color: #4CAF50;

  --secondary-color: #FFC107;

}

  


.button {

  background-color: var(--main-color);

  border: 2px solid var(--secondary-color);

}

优点:

  • 减少重复值

  • 方便主题切换

  • 可通过JS动态修改

  • 支持继承和层叠

最佳实践


/* 创建设计系统 */

:root {

  /* 颜色系统 */

  --color-primary: #4CAF50;

  --color-primary-light: #81C784;

  --color-primary-dark: #388E3C;

  

  /* 间距系统 */

  --space-unit: 8px;

  --space-xs: calc(0.5 * var(--space-unit));

  --space-sm: var(--space-unit);

  --space-md: calc(2 * var(--space-unit));

  --space-lg: calc(3 * var(--space-unit));

  --space-xl: calc(4 * var(--space-unit));

  

  /* 字体系统 */

  --font-size-base: 16px;

  --font-size-sm: calc(var(--font-size-base) * 0.875);

  --font-size-lg: calc(var(--font-size-base) * 1.25);

}

  


/* JavaScript操作CSS变量 */

document.documentElement.style.setProperty('--color-primary', '#ff0000');

  


/* 组件级作用域变量 */

.card {

  --card-padding: var(--space-md);

  padding: var(--card-padding);

}

30. 如何实现暗黑模式切换?

答案

使用CSS变量+媒体查询:


:root {

  --bg-color: white;

  --text-color: black;

}

  


@media (prefers-color-scheme: dark) {

  :root {

    --bg-color: #333;

    --text-color: white;

  }

}

  


/* 手动切换 */

.dark-theme {

  --bg-color: #333;

  --text-color: white;

}

  


body {

  background-color: var(--bg-color);

  color: var(--text-color);

}

JavaScript实现切换:


const toggleBtn = document.getElementById('theme-toggle');

toggleBtn.addEventListener('click', () => {

  document.body.classList.toggle('dark-theme');

});

最佳实践


/* 完整的暗黑模式方案 */

:root {

  --color-bg: #ffffff;

  --color-text: #333333;

  --color-primary: #4361ee;

  --color-secondary: #3f37c9;

  --color-accent: #f72585;

  --color-muted: #f8f9fa;

  --color-border: #e9ecef;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.12);

  --shadow-md: 0 4px 6px rgba(0,0,0,0.1);

  

  /* 过渡效果 */

  --transition-theme: background-color 0.3s ease, color 0.3s ease;

}

  


/* 系统偏好 */

@media (prefers-color-scheme: dark) {

  :root:not([data-theme]) {

    --color-bg: #121212;

    --color-text: #f8f9fa;

    --color-primary: #a5b4fc;

    --color-secondary: #818cf8;

    --color-accent: #f472b6;

    --color-muted: #27272a;

    --color-border: #3f3f46;

    --shadow-sm: 0 1px 3px rgba(0,0,0,0.35);

    --shadow-md: 0 4px 6px rgba(0,0,0,0.4);

  }

}



/* 手动设置 */

[data-theme="dark"] {

  --color-bg: #121212;

  --color-text: #f8f9fa;

  --color-primary: #a5b4fc;

  --color-secondary: #818cf8;

  --color-accent: #f472b6;

  --color-muted: #27272a;

  --color-border: #3f3f46;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.35);

  --shadow-md: 0 4px 6px rgba(0,0,0,0.4);

}



/* 应用 */

body {

  background-color: var(--color-bg);

  color: var(--color-text);

  transition: var(--transition-theme);

}

  

/* JavaScript存储用户偏好 */

function setTheme(theme) {

  document.documentElement.setAttribute('data-theme', theme);

  localStorage.setItem('theme', theme);

}

  

// 检查用户偏好

const savedTheme = localStorage.getItem('theme');

if (savedTheme) {

  setTheme(savedTheme);

}