2322 字
12 分钟
前端面试知识点总结

HTML 篇#

1. 设备的 DPR 是否可变#

DPR(Device Pixel Ratio,设备像素比) 在某些情况下是可变的,具体取决于以下几个因素:

固定的情况#

  1. 物理设备本身:对于单一设备来说,其物理屏幕的像素密度是固定的。比如 iPhone 14 Pro 的 DPR 固定为 3。

可变的情况#

  1. 浏览器缩放

    • 用户使用浏览器缩放功能(Ctrl/Cmd + +/-)时,window.devicePixelRatio 会动态变化
    • 缩放到 110% 时,DPR 会相应增加
  2. 外接显示器

    • 笔记本电脑连接不同显示器时,DPR 会根据当前显示器改变
    • 从 Retina 屏幕(DPR=2)拖动窗口到普通显示器(DPR=1)
  3. 操作系统缩放设置

    • Windows 的显示缩放(125%、150% 等)
    • macOS 的缩放显示选项
    • 这些设置会影响浏览器报告的 DPR 值
  4. 响应式测试工具

    • 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'] });

最佳实践总结#

  1. 渐进式增强:优先使用新格式,提供降级方案
  2. 适量压缩:平衡质量和体积(JPEG 85% 质量通常足够)
  3. 按需加载:使用懒加载减少初始加载
  4. 响应式图片:根据设备提供合适尺寸
  5. CDN 加速:使用 CDN 的图片处理和缓存功能
  6. 预加载关键图片
<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;
}
};

缓存优化建议#

  1. HTML 文件:使用协商缓存或不缓存
  2. CSS/JS 文件:使用强缓存 + 文件指纹(hash)
  3. 图片资源:长期强缓存
  4. 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 到复杂的浏览器机制都需要深入理解。掌握这些知识点不仅有助于面试,更重要的是能在实际开发中做出正确的技术决策,优化用户体验。建议在学习时结合实践,通过实际项目加深理解。

前端面试知识点总结
https://fuwari.vercel.app/posts/interview/
作者
Lorem Ipsum
发布于
2025-11-03
许可协议
CC BY-NC-SA 4.0