2322 字
12 分钟
前端面试知识点总结
HTML 篇
1. 设备的 DPR 是否可变
DPR(Device Pixel Ratio,设备像素比) 在某些情况下是可变的,具体取决于以下几个因素:
固定的情况
- 物理设备本身:对于单一设备来说,其物理屏幕的像素密度是固定的。比如 iPhone 14 Pro 的 DPR 固定为 3。
可变的情况
-
浏览器缩放
- 用户使用浏览器缩放功能(Ctrl/Cmd + +/-)时,
window.devicePixelRatio会动态变化 - 缩放到 110% 时,DPR 会相应增加
- 用户使用浏览器缩放功能(Ctrl/Cmd + +/-)时,
-
外接显示器
- 笔记本电脑连接不同显示器时,DPR 会根据当前显示器改变
- 从 Retina 屏幕(DPR=2)拖动窗口到普通显示器(DPR=1)
-
操作系统缩放设置
- Windows 的显示缩放(125%、150% 等)
- macOS 的缩放显示选项
- 这些设置会影响浏览器报告的 DPR 值
-
响应式测试工具
- Chrome DevTools 的设备模拟器可以模拟不同 DPR
- 开发时可以动态切换测试不同的像素密度
监听 DPR 变化
// 监听 DPR 变化window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`) .addEventListener('change', () => { console.log('DPR changed to:', window.devicePixelRatio); });因此,虽然设备的物理像素密度是固定的,但浏览器环境中的 DPR 值确实可以动态变化,开发时需要考虑这些场景以确保界面正确显示。
2. 前端如何选择图片格式
前端选择图片格式需要根据具体场景和需求来决定。以下是各种格式的特点和选择策略:
常见图片格式对比
JPEG/JPG
特点:
- 有损压缩,文件小
- 支持数百万种颜色
- 不支持透明度
- 不支持动画
适用场景:
- 适合:照片、复杂色彩的图像
- 不适合:图标、文字、线条图
PNG
特点:
- 无损压缩,质量高
- 支持透明度(PNG-24 支持半透明)
- 文件体积较大
- 不支持动画
适用场景:
- PNG-8:简单图形、图标、logo
- PNG-24:需要透明背景的复杂图像
WebP
特点:
- Google 开发,体积比 JPEG 小 25-35%
- 支持有损和无损压缩
- 支持透明度和动画
- 兼容性需要考虑(Safari 14+ 才支持)
适用场景:
- 现代浏览器的最佳选择
- 可替代 JPEG 和 PNG
AVIF
特点:
- 最新格式,压缩率最高
- 比 WebP 还小 20%
- 支持 HDR
- 兼容性较差
适用场景:
- 追求极致性能的场景
- 需要做好降级处理
SVG
特点:
- 矢量图,无限缩放不失真
- 文件小(简单图形)
- 可编程、可动画
- 不适合照片
适用场景:
- 图标、logo、简单插画
- 需要缩放的图形
选择决策流程
function chooseImageFormat(imageType) { // 1. 是否需要动画? if (需要动画) { return 'GIF' || 'WebP' || 'APNG'; }
// 2. 是否是矢量图形? if (简单图形 || 图标 || Logo) { return 'SVG'; }
// 3. 是否需要透明度? if (需要透明背景) { return 'PNG' || 'WebP'; }
// 4. 是否是照片? if (照片 || 复杂图像) { return 'JPEG' || 'WebP' || 'AVIF'; }}实践建议
1. 响应式图片策略
<!-- 使用 picture 元素提供多种格式 --><picture> <source srcset="image.avif" type="image/avif"> <source srcset="image.webp" type="image/webp"> <img src="image.jpg" alt="描述"></picture>
<!-- 使用 srcset 提供不同分辨率 --><img src="image-400.jpg" srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w" sizes="(max-width: 768px) 100vw, 50vw" alt="响应式图片">2. 懒加载优化
// 原生懒加载<img src="image.jpg" loading="lazy" alt="懒加载图片">
// Intersection Observer 实现const lazyImages = document.querySelectorAll('img[data-src]');const imageObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; imageObserver.unobserve(img); } });});
lazyImages.forEach(img => imageObserver.observe(img));3. 图片优化工具配置
// webpack 配置示例module.exports = { module: { rules: [ { test: /\.(png|jpg|gif|webp|avif)$/, use: [ { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true, quality: 65 }, optipng: { enabled: false, }, pngquant: { quality: [0.65, 0.90], speed: 4 }, webp: { quality: 75 } } } ] } ] }};4. CDN 图片处理
// 使用 CDN 的图片处理功能function getOptimizedImageUrl(url, options = {}) { const { width, format = 'auto', quality = 85 } = options;
// 阿里云 OSS 示例 return `${url}?x-oss-process=image/format,${format}/quality,q_${quality}${ width ? `/resize,w_${width}` : '' }`;}
// 使用const imageUrl = getOptimizedImageUrl('image.jpg', { width: 800, format: 'webp', quality: 80});5. 性能监控
// 监控图片加载性能const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.initiatorType === 'img') { console.log(`图片加载:${entry.name}`); console.log(`耗时:${entry.duration}ms`); console.log(`大小:${entry.transferSize} bytes`); } }});
observer.observe({ entryTypes: ['resource'] });最佳实践总结
- 渐进式增强:优先使用新格式,提供降级方案
- 适量压缩:平衡质量和体积(JPEG 85% 质量通常足够)
- 按需加载:使用懒加载减少初始加载
- 响应式图片:根据设备提供合适尺寸
- CDN 加速:使用 CDN 的图片处理和缓存功能
- 预加载关键图片:
<link rel="preload" as="image" href="hero.webp" type="image/webp">选择图片格式时,要综合考虑图片类型、浏览器兼容性、加载性能和用户体验,通过渐进式增强策略提供最佳方案。
CSS 篇
1. CSS 单位详解:rem/em/px/rpx 的区别
px(像素)
- 类型:绝对单位
- 特点:固定大小,1px 就是屏幕上 1 个物理像素点
- 应用:不会随着父元素或根元素变化而变化
- 使用场景:边框、精确控制的小元素
.border { border: 1px solid #ccc;}em
- 类型:相对单位
- 特点:相对于父元素的字体大小
- 计算:如果父元素 font-size: 16px,那么 1em = 16px
- 注意:会叠加计算,嵌套时会累积
.parent { font-size: 16px;}.child { font-size: 1.5em; /* 24px */ padding: 2em; /* 48px (基于自身的 24px) */}rem(root em)
- 类型:相对单位
- 特点:相对于根元素(html)的字体大小
- 计算:如果根元素 font-size: 16px,那么 1rem = 16px
- 优势:不会叠加计算,只参考根元素
html { font-size: 16px;}.element { width: 20rem; /* 320px */ font-size: 1rem; /* 16px */}rpx(responsive pixel)
- 类型:响应式单位
- 使用:主要用于小程序开发(如微信小程序)
- 特点:自动适配不同屏幕宽度
- 规则:规定屏幕宽度为 750rpx,在 iPhone6 上 1rpx = 0.5px
/* 小程序中的使用 */.container { width: 750rpx; /* 占满整个屏幕宽度 */ height: 100rpx; /* 高度自动适配 */}单位选择建议
// 单位选择策略const chooseCSSUnit = (scenario) => { switch(scenario) { case '边框': return 'px'; // 边框通常使用 px case '响应式布局': return 'rem'; // 整体布局使用 rem case '组件内部间距': return 'em'; // 组件内部可以使用 em case '小程序开发': return 'rpx'; // 小程序使用 rpx case '视口相关': return 'vw/vh'; // 基于视口的布局 default: return 'rem'; }};浏览器篇
1. 浏览器缓存机制:强缓存与协商缓存
强缓存
强缓存不会向服务器发送请求,而是直接从缓存中读取资源。
相关 HTTP 头部
1. Expires (HTTP/1.0)
Expires: Wed, 08 Jul 2025 07:09:08 GMT- 指定资源过期的绝对时间
- 缺点:依赖本地时间,如果本地时间被修改,可能导致缓存失效
2. Cache-Control (HTTP/1.1,优先级更高)
Cache-Control: max-age=86400 # 86400秒 = 1天Cache-Control: no-cache # 需要协商缓存验证Cache-Control: no-store # 不缓存Cache-Control: public # 可以被任何缓存存储Cache-Control: private # 只能被当前用户缓存工作原理
浏览器请求 → 检查缓存是否过期 → ├─ 未过期 → 直接使用缓存(状态码 200 from cache) └─ 已过期 → 发起新请求协商缓存
协商缓存会向服务器发送请求,验证缓存是否是最新的。
相关 HTTP 头部
1. Last-Modified / If-Modified-Since
# 服务器响应Last-Modified: Wed, 08 Jul 2025 07:09:08 GMT
# 下次请求头If-Modified-Since: Wed, 08 Jul 2025 07:09:08 GMT- 基于文件修改时间判断
- 精度只到秒级
- 文件内容没变但修改时间变了也会重新请求
2. ETag / If-None-Match(优先级更高)
# 服务器响应ETag: "1234567890"
# 下次请求头If-None-Match: "1234567890"- 基于文件内容生成的哈希值
- 更准确,内容不变则 ETag 不变
工作流程
浏览器请求(带验证头) → 服务器验证 → ├─ 资源未修改 → 返回 304 Not Modified(使用缓存) └─ 资源已修改 → 返回 200 OK + 新资源缓存策略实践
// Express 服务器设置缓存示例app.use((req, res, next) => { const url = req.url;
if (url.match(/\.(js|css|jpg|png|gif)$/)) { const oneDay = 86400; const oneYear = oneDay * 365;
// 静态资源强缓存一年 if (url.includes('static')) { res.setHeader('Cache-Control', `public, max-age=${oneYear}`); } // HTML 文件不缓存 else if (url.endsWith('.html')) { res.setHeader('Cache-Control', 'no-cache'); } // 其他资源缓存一天 else { res.setHeader('Cache-Control', `public, max-age=${oneDay}`); } }
next();});
// 前端缓存控制const fetchWithCache = async (url, options = {}) => { const defaultOptions = { cache: 'default', // default | no-store | reload | no-cache | force-cache ...options };
try { const response = await fetch(url, defaultOptions); return response; } catch (error) { console.error('Fetch error:', error); throw error; }};缓存优化建议
- HTML 文件:使用协商缓存或不缓存
- CSS/JS 文件:使用强缓存 + 文件指纹(hash)
- 图片资源:长期强缓存
- API 请求:根据业务需求设置
// Webpack 配置文件指纹module.exports = { output: { filename: '[name].[contenthash:8].js', chunkFilename: '[name].[contenthash:8].chunk.js' }, optimization: { moduleIds: 'deterministic', runtimeChunk: 'single', splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: -10, reuseExistingChunk: true } } } }};总结
前端面试涉及的知识点广泛,从基础的 HTML/CSS 到复杂的浏览器机制都需要深入理解。掌握这些知识点不仅有助于面试,更重要的是能在实际开发中做出正确的技术决策,优化用户体验。建议在学习时结合实践,通过实际项目加深理解。