1. 如何实现H5手机端适配?
核心三板斧:viewport + 布局方案 + 屏幕密度处理
html
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
这行代码让浏览器按设备宽度渲染,避免自动缩放。
然后选择布局方案:
方案一:rem
适配(推荐)
rem
是相对于根元素(html)字体大小的单位。我们通过 JS 动态设置 html 的 font-size
,实现等比缩放。
javascript
// 简化版 flexible.js 核心逻辑
function setRootFontSize() {
const designWidth = 375; // 设计稿宽度
const root = document.documentElement;
const width = root.clientWidth; // 设备实际宽度
const fontSize = width * 100 / designWidth; // 按比例缩放
root.style.fontSize = fontSize + 'px';
}
window.addEventListener('resize', setRootFontSize);
setRootFontSize();
👉设计稿 750px?那我们按 375px 为基准,1rem = 100px,写样式时 width: 2rem
就是 200px。
方案二:flex
布局
flex
是弹性布局,适合动态分配空间,但不解决整体缩放问题。
css
.container {
display: flex;
justify-content: space-between;
align-items: center;
}
⚠️flex 是"内部弹性",rem 是"全局缩放"------两者常结合使用!
方案三:vw
单位(现代方案)
1vw = 1% 视口宽度,无需 JS,直接 CSS 控制:
css
html {
font-size: 4.166vw; /* 100px / 24rem ≈ 4.166vw */
}
👉继续看?「Q1: rem 和 vw 哪个更适合复杂项目?」
2. rem、em、px 的区别?
单位 | 基准 | 特点 |
---|---|---|
px |
像素(绝对) | 固定大小,不随缩放变化 |
em |
父元素 font-size | 层层继承,易失控(1.2em 的 1.2em = 1.44em) |
rem |
根元素 html font-size | 统一控制,适合响应式 |
css
html { font-size: 16px; }
.parent { font-size: 20px; }
.child {
font-size: 2em; /* 40px (20 * 2) */
width: 2rem; /* 32px (16 * 2) */
}
🤯你以为懂了?「Q2: 如果用户系统字体放大,rem 会受影响吗?」
A2: 不会!rem 只认 html 的 font-size,JS 设置后就固定了,除非用户禁用 JS。
3. 如何去除 URL 中的 #
号?
#
是 hash 模式,用于前端路由。要去除它,必须使用 History 模式。
javascript
// Vue Router 示例
const router = new VueRouter({
mode: 'history', // 默认是 'hash'
routes: [...]
})
但注意:服务端必须配置 fallback!
nginx
# Nginx 配置
location / {
try_files $uri $uri/ /index.html;
}
否则用户刷新 /user/123
会 404 ❌
💥面试官偷笑😏:你上线后出现白屏,怎么排查?
A3: 检查服务端是否返回 index.html,而不是 404。可以用 curl 测试:
curl -I http://yourdomain.com/user/123
4. webpack 和 gulp 的优缺点?
工具 | 类型 | 优点 | 缺点 |
---|---|---|---|
webpack |
模块打包器 | 自动依赖分析、代码分割、HMR | 配置复杂、学习曲线陡 |
gulp |
构建流工具 | 流式处理、任务自动化 | 不解决模块化,需配合其他工具 |
javascript
// gulpfile.js 示例
const gulp = require('gulp');
const sass = require('gulp-sass');
gulp.task('sass', () => {
return gulp.src('src/scss/*.scss')
.pipe(sass()) // 编译
.pipe(gulp.dest('dist/css'));
});
👉webpack 是"智能打包",gulp 是"流水线工人"。
「Q4: 如果你有 100 个静态 HTML 页面,用哪个更合适?」
A4: gulp!webpack 适合 SPA,多页静态站用 gulp 做压缩、雪碧图更轻量。
5. 如何实现异步加载?
JS 异步加载方式:
async
:下载不阻塞,下载完立即执行defer
:下载不阻塞,DOM 解析完再执行- 动态 import:
import('./module.js').then(...)
javascript
// 动态加载组件(React/Vue 都支持)
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
CSS 异步加载:
javascript
// 动态插入 link
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/async.css';
document.head.appendChild(link);
「Q5: defer 和 async 的执行顺序能保证吗?」
A5:
defer
保证顺序,async
不保证!多个 async 脚本谁先下载完谁执行。
6. 如何实现分模块打包(多入口)?
webpack 支持多入口配置:
javascript
// webpack.config.js
module.exports = {
entry: {
home: './src/home.js',
user: './src/user.js',
admin: './src/admin.js'
},
output: {
filename: '[name].[contenthash].js', // home.abc123.js
path: __dirname + '/dist'
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
👉生成:home.js、user.js、admin.js + 公共 vendors.js
「Q6: 如果 home 和 user 都用了 lodash,怎么避免重复打包?」
A6: 用
splitChunks
提取公共模块,或externals
外链 CDN。
7. 前端性能优化六大方向
1️⃣ JS/CSS 优化
- 压缩混淆(Terser/Uglify)
- Tree Shaking(移除未使用代码)
- 代码分割(Code Splitting)
2️⃣ 图片优化
- WebP/AVIF 格式
- 懒加载:
<img loading="lazy">
- 响应式图片:
srcset
3️⃣ 缓存 & 预加载
- 强缓存:
Cache-Control: max-age=31536000
- 协商缓存:
ETag
- 预加载:
<link rel="preload">
4️⃣ SSR(服务端渲染)
- Next.js/Nuxt.js
- 首屏快、SEO 友好
5️⃣ 多域名加载
- 浏览器对单域名并发请求数有限制(通常 6 个)
- 用
static1.domain.com
、static2.domain.com
绕过限制
6️⃣ 负载均衡
- CDN 分发静态资源
- Nginx 反向代理 + 轮询
「Q7: 为什么并发请求上限是6个?能突破吗?」
A7: HTTP/1.1 限制,浏览器为避免拥塞。突破方式:HTTP/2 多路复用,或域名分片。
8. base64 为什么能提升性能?缺点?
优点:
- 减少 HTTP 请求(小图标内联)
- 避免雪碧图复杂定位
css
.icon {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...);
}
缺点:
- 体积增大约 33%(Base64 编码)
- 无法被浏览器缓存
- 阻塞 CSS 解析(大文件慎用)
「Q8: 什么时候该用 base64?什么时候不该?」
A8: ≤2KB 小图标可用,大文件必须外链!否则首屏卡死。
连环追问链(5连炸💥)
「Q1: rem 和 vw 哪个更适合复杂项目?」
A1: rem 更可控(JS 可干预),vw 更现代(纯 CSS),推荐 vw + rem
混合方案。
「Q2: 如果用户系统字体放大,rem 会受影响吗?」
A2: 不会,rem 只认 html 的 font-size,JS 设置后固定。
「Q3: History 模式上线后白屏,怎么排查?」
A3: 检查服务端是否 fallback 到 index.html,用 curl 测试路径。
「Q4: 100 个静态页用 webpack 还是 gulp?」
A4: gulp 更轻量,适合批量处理静态资源。
「Q5: defer 和 async 执行顺序能保证吗?」
A5: defer 保证,async 不保证!多个 async 脚本执行顺序不确定。
「Q6: lodash 重复打包怎么解决?」
A6: splitChunks 提取公共模块,或 externals 外链。
「Q7: 并发上限6个,能突破吗?」
A7: 用 HTTP/2 多路复用,或域名分片(static1/static2)。
「Q8: base64 什么时候该用?」
A8: ≤2KB 小图标可用,大文件必须外链!👉继续看?「Q9: 如何自动判断图片是否转 base64?」
A9: webpack 的
url-loader
可配置limit
,超限自动发请求。
「Q10: 移动端 1px 边框怎么实现?💥」
A10: transform: scale(0.5)
或 border-image
,rem 方案需结合设备像素比!