best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBest practices
最佳实践
Modern web development standards based on Lighthouse best practices audits. Covers security, browser compatibility, and code quality patterns.
基于Lighthouse最佳实践审计的现代Web开发标准,涵盖安全、浏览器兼容性和代码质量规范。
Security
安全
HTTPS everywhere
全面启用HTTPS
Enforce HTTPS:
html
<!-- ❌ Mixed content -->
<img src="http://example.com/image.jpg">
<script src="http://cdn.example.com/script.js"></script>
<!-- ✅ HTTPS only -->
<img src="https://example.com/image.jpg">
<script src="https://cdn.example.com/script.js"></script>
<!-- ✅ Protocol-relative (will use page's protocol) -->
<img src="//example.com/image.jpg">HSTS Header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload强制使用HTTPS:
html
<!-- ❌ Mixed content -->
<img src="http://example.com/image.jpg">
<script src="http://cdn.example.com/script.js"></script>
<!-- ✅ HTTPS only -->
<img src="https://example.com/image.jpg">
<script src="https://cdn.example.com/script.js"></script>
<!-- ✅ Protocol-relative (will use page's protocol) -->
<img src="//example.com/image.jpg">HSTS 响应头:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadContent Security Policy (CSP)
内容安全策略(CSP)
html
<!-- Basic CSP via meta tag -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;">
<!-- Better: HTTP header -->CSP Header (recommended):
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123' https://trusted.com;
style-src 'self' 'nonce-abc123';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'self';
base-uri 'self';
form-action 'self';Using nonces for inline scripts:
html
<script nonce="abc123">
// This inline script is allowed
</script>html
<!-- Basic CSP via meta tag -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;">
<!-- Better: HTTP header -->推荐的CSP响应头:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123' https://trusted.com;
style-src 'self' 'nonce-abc123';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'self';
base-uri 'self';
form-action 'self';为内联脚本使用随机数(nonce):
html
<script nonce="abc123">
// This inline script is allowed
</script>Security headers
安全响应头
undefinedundefinedPrevent clickjacking
Prevent clickjacking
X-Frame-Options: DENY
X-Frame-Options: DENY
Prevent MIME type sniffing
Prevent MIME type sniffing
X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
Enable XSS filter (legacy browsers)
Enable XSS filter (legacy browsers)
X-XSS-Protection: 1; mode=block
X-XSS-Protection: 1; mode=block
Control referrer information
Control referrer information
Referrer-Policy: strict-origin-when-cross-origin
Referrer-Policy: strict-origin-when-cross-origin
Permissions policy (formerly Feature-Policy)
Permissions policy (formerly Feature-Policy)
Permissions-Policy: geolocation=(), microphone=(), camera=()
undefinedPermissions-Policy: geolocation=(), microphone=(), camera=()
undefinedNo vulnerable libraries
避免使用存在漏洞的库
bash
undefinedbash
undefinedCheck for vulnerabilities
Check for vulnerabilities
npm audit
yarn audit
npm audit
yarn audit
Auto-fix when possible
Auto-fix when possible
npm audit fix
npm audit fix
Check specific package
Check specific package
npm ls lodash
**Keep dependencies updated:**
```json
// package.json
{
"scripts": {
"audit": "npm audit --audit-level=moderate",
"update": "npm update && npm audit fix"
}
}Known vulnerable patterns to avoid:
javascript
// ❌ Prototype pollution vulnerable patterns
Object.assign(target, userInput);
_.merge(target, userInput);
// ✅ Safer alternatives
const safeData = JSON.parse(JSON.stringify(userInput));npm ls lodash
**保持依赖更新:**
```json
// package.json
{
"scripts": {
"audit": "npm audit --audit-level=moderate",
"update": "npm update && npm audit fix"
}
}需要避免的已知易受攻击模式:
javascript
// ❌ Prototype pollution vulnerable patterns
Object.assign(target, userInput);
_.merge(target, userInput);
// ✅ Safer alternatives
const safeData = JSON.parse(JSON.stringify(userInput));Input sanitization
输入净化
javascript
// ❌ XSS vulnerable
element.innerHTML = userInput;
document.write(userInput);
// ✅ Safe text content
element.textContent = userInput;
// ✅ If HTML needed, sanitize
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);javascript
// ❌ XSS vulnerable
element.innerHTML = userInput;
document.write(userInput);
// ✅ 安全文本内容
element.textContent = userInput;
// ✅ 若需使用HTML,先净化
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);Secure cookies
安全Cookie
javascript
// ❌ Insecure cookie
document.cookie = "session=abc123";
// ✅ Secure cookie (server-side)
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/javascript
// ❌ 不安全的Cookie
document.cookie = "session=abc123";
// ✅ 安全Cookie(服务端设置)
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/Browser compatibility
浏览器兼容性
Doctype declaration
文档类型声明
html
<!-- ❌ Missing or invalid doctype -->
<HTML>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<!-- ✅ HTML5 doctype -->
<!DOCTYPE html>
<html lang="en">html
<!-- ❌ 缺失或无效的文档类型 -->
<HTML>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<!-- ✅ HTML5文档类型 -->
<!DOCTYPE html>
<html lang="en">Character encoding
字符编码
html
<!-- ❌ Missing or late charset -->
<html>
<head>
<title>Page</title>
<meta charset="UTF-8">
</head>
<!-- ✅ Charset as first element in head -->
<html>
<head>
<meta charset="UTF-8">
<title>Page</title>
</head>html
<!-- ❌ 缺失或晚声明的字符编码 -->
<html>
<head>
<title>Page</title>
<meta charset="UTF-8">
</head>
<!-- ✅ 在head最顶部声明字符编码 -->
<html>
<head>
<meta charset="UTF-8">
<title>Page</title>
</head>Viewport meta tag
视口元标签
html
<!-- ❌ Missing viewport -->
<head>
<title>Page</title>
</head>
<!-- ✅ Responsive viewport -->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page</title>
</head>html
<!-- ❌ 缺失视口标签 -->
<head>
<title>Page</title>
</head>
<!-- ✅ 响应式视口 -->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page</title>
</head>Feature detection
特性检测
javascript
// ❌ Browser detection (brittle)
if (navigator.userAgent.includes('Chrome')) {
// Chrome-specific code
}
// ✅ Feature detection
if ('IntersectionObserver' in window) {
// Use IntersectionObserver
} else {
// Fallback
}
// ✅ Using @supports in CSS
@supports (display: grid) {
.container {
display: grid;
}
}
@supports not (display: grid) {
.container {
display: flex;
}
}javascript
// ❌ 浏览器检测(不稳定)
if (navigator.userAgent.includes('Chrome')) {
// 仅Chrome可用的代码
}
// ✅ 特性检测
if ('IntersectionObserver' in window) {
// 使用IntersectionObserver
} else {
// 降级方案
}
// ✅ 在CSS中使用@supports
@supports (display: grid) {
.container {
display: grid;
}
}
@supports not (display: grid) {
.container {
display: flex;
}
}Polyfills (when needed)
必要时使用Polyfill
html
<!-- Load polyfills conditionally -->
<script>
if (!('fetch' in window)) {
document.write('<script src="/polyfills/fetch.js"><\/script>');
}
</script>
<!-- Or use polyfill.io -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver"></script>html
<!-- 按需加载Polyfill -->
<script>
if (!('fetch' in window)) {
document.write('<script src="/polyfills/fetch.js"><\/script>');
}
</script>
<!-- 或使用polyfill.io -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver"></script>Deprecated APIs
已废弃API
Avoid these
避免使用以下API
javascript
// ❌ document.write (blocks parsing)
document.write('<script src="..."></script>');
// ✅ Dynamic script loading
const script = document.createElement('script');
script.src = '...';
document.head.appendChild(script);
// ❌ Synchronous XHR (blocks main thread)
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false); // false = synchronous
// ✅ Async fetch
const response = await fetch(url);
// ❌ Application Cache (deprecated)
<html manifest="cache.manifest">
// ✅ Service Workers
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}javascript
// ❌ document.write(阻塞解析)
document.write('<script src="..."></script>');
// ✅ 动态加载脚本
const script = document.createElement('script');
script.src = '...';
document.head.appendChild(script);
// ❌ 同步XHR(阻塞主线程)
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false); // false = 同步
// ✅ 异步fetch
const response = await fetch(url);
// ❌ Application Cache(已废弃)
<html manifest="cache.manifest">
// ✅ Service Workers
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}Event listener passive
被动事件监听器
javascript
// ❌ Non-passive touch/wheel (may block scrolling)
element.addEventListener('touchstart', handler);
element.addEventListener('wheel', handler);
// ✅ Passive listeners (allows smooth scrolling)
element.addEventListener('touchstart', handler, { passive: true });
element.addEventListener('wheel', handler, { passive: true });
// ✅ If you need preventDefault, be explicit
element.addEventListener('touchstart', handler, { passive: false });javascript
// ❌ 非被动触摸/滚轮事件(可能阻塞滚动)
element.addEventListener('touchstart', handler);
element.addEventListener('wheel', handler);
// ✅ 被动监听器(支持流畅滚动)
element.addEventListener('touchstart', handler, { passive: true });
element.addEventListener('wheel', handler, { passive: true });
// ✅ 若需要preventDefault,显式声明
element.addEventListener('touchstart', handler, { passive: false });Console & errors
控制台与错误处理
No console errors
避免控制台错误
javascript
// ❌ Errors in production
console.log('Debug info'); // Remove in production
throw new Error('Unhandled'); // Catch all errors
// ✅ Proper error handling
try {
riskyOperation();
} catch (error) {
// Log to error tracking service
errorTracker.captureException(error);
// Show user-friendly message
showErrorMessage('Something went wrong. Please try again.');
}javascript
// ❌ 生产环境中的错误
console.log('Debug info'); // 生产环境需移除
throw new Error('Unhandled'); // 捕获所有错误
// ✅ 正确的错误处理
try {
riskyOperation();
} catch (error) {
// 记录到错误追踪服务
errorTracker.captureException(error);
// 显示友好的用户提示
showErrorMessage('出现错误,请重试。');
}Error boundaries (React)
React错误边界
jsx
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
errorTracker.captureException(error, { extra: info });
}
render() {
if (this.state.hasError) {
return <FallbackUI />;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<App />
</ErrorBoundary>jsx
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
errorTracker.captureException(error, { extra: info });
}
render() {
if (this.state.hasError) {
return <FallbackUI />;
}
return this.props.children;
}
}
// 使用方式
<ErrorBoundary>
<App />
</ErrorBoundary>Global error handler
全局错误处理器
javascript
// Catch unhandled errors
window.addEventListener('error', (event) => {
errorTracker.captureException(event.error);
});
// Catch unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
errorTracker.captureException(event.reason);
});javascript
// 捕获未处理的错误
window.addEventListener('error', (event) => {
errorTracker.captureException(event.error);
});
// 捕获未处理的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
errorTracker.captureException(event.reason);
});Source maps
源映射
Production configuration
生产环境配置
javascript
// ❌ Source maps exposed in production
// webpack.config.js
module.exports = {
devtool: 'source-map', // Exposes source code
};
// ✅ Hidden source maps (uploaded to error tracker)
module.exports = {
devtool: 'hidden-source-map',
};
// ✅ Or no source maps in production
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
};javascript
// ❌ 生产环境暴露源映射
// webpack.config.js
module.exports = {
devtool: 'source-map', // 会暴露源代码
};
// ✅ 隐藏源映射(上传至错误追踪服务)
module.exports = {
devtool: 'hidden-source-map',
};
// ✅ 或生产环境不生成源映射
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
};Performance best practices
性能最佳实践
Avoid blocking patterns
避免阻塞模式
javascript
// ❌ Blocking script
<script src="heavy-library.js"></script>
// ✅ Deferred script
<script defer src="heavy-library.js"></script>
// ❌ Blocking CSS import
@import url('other-styles.css');
// ✅ Link tags (parallel loading)
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="other-styles.css">javascript
// ❌ 阻塞脚本
<script src="heavy-library.js"></script>
// ✅ 延迟脚本
<script defer src="heavy-library.js"></script>
// ❌ 阻塞CSS导入
@import url('other-styles.css');
// ✅ 链接标签(并行加载)
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="other-styles.css">Efficient event handlers
高效事件处理器
javascript
// ❌ Handler on every element
items.forEach(item => {
item.addEventListener('click', handleClick);
});
// ✅ Event delegation
container.addEventListener('click', (e) => {
if (e.target.matches('.item')) {
handleClick(e);
}
});javascript
// ❌ 为每个元素绑定处理器
items.forEach(item => {
item.addEventListener('click', handleClick);
});
// ✅ 事件委托
container.addEventListener('click', (e) => {
if (e.target.matches('.item')) {
handleClick(e);
}
});Memory management
内存管理
javascript
// ❌ Memory leak (never removed)
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);
// ✅ Cleanup when done
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);
// Later, when component unmounts:
window.removeEventListener('resize', handler);
// ✅ Using AbortController
const controller = new AbortController();
window.addEventListener('resize', handler, { signal: controller.signal });
// Cleanup:
controller.abort();javascript
// ❌ 内存泄漏(未移除监听器)
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);
// ✅ 完成后清理
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);
// 组件卸载时执行清理:
window.removeEventListener('resize', handler);
// ✅ 使用AbortController
const controller = new AbortController();
window.addEventListener('resize', handler, { signal: controller.signal });
// 清理:
controller.abort();Code quality
代码质量
Valid HTML
有效的HTML
html
<!-- ❌ Invalid HTML -->
<div id="header">
<div id="header"> <!-- Duplicate ID -->
<ul>
<div>Item</div> <!-- Invalid child -->
</ul>
<a href="/"><button>Click</button></a> <!-- Invalid nesting -->
<!-- ✅ Valid HTML -->
<header id="site-header">
</header>
<ul>
<li>Item</li>
</ul>
<a href="/" class="button">Click</a>html
<!-- ❌ 无效HTML -->
<div id="header">
<div id="header"> <!-- 重复ID -->
<ul>
<div>Item</div> <!-- 无效子元素 -->
</ul>
<a href="/"><button>Click</button></a> <!-- 无效嵌套 -->
<!-- ✅ 有效HTML -->
<header id="site-header">
</header>
<ul>
<li>Item</li>
</ul>
<a href="/" class="button">Click</a>Semantic HTML
语义化HTML
html
<!-- ❌ Non-semantic -->
<div class="header">
<div class="nav">
<div class="nav-item">Home</div>
</div>
</div>
<div class="main">
<div class="article">
<div class="title">Headline</div>
</div>
</div>
<!-- ✅ Semantic HTML5 -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Headline</h1>
</article>
</main>html
<!-- ❌ 非语义化标签 -->
<div class="header">
<div class="nav">
<div class="nav-item">Home</div>
</div>
</div>
<div class="main">
<div class="article">
<div class="title">Headline</div>
</div>
</div>
<!-- ✅ 语义化HTML5 -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Headline</h1>
</article>
</main>Image aspect ratios
图片宽高比
html
<!-- ❌ Distorted images -->
<img src="photo.jpg" width="300" height="100">
<!-- If actual ratio is 4:3, this squishes the image -->
<!-- ✅ Preserve aspect ratio -->
<img src="photo.jpg" width="300" height="225">
<!-- Actual 4:3 dimensions -->
<!-- ✅ CSS object-fit for flexibility -->
<img src="photo.jpg" style="width: 300px; height: 200px; object-fit: cover;">html
<!-- ❌ 图片变形 -->
<img src="photo.jpg" width="300" height="100">
<!-- 若实际比例为4:3,会导致图片被压缩 -->
<!-- ✅ 保持宽高比 -->
<img src="photo.jpg" width="300" height="225">
<!-- 实际4:3尺寸 -->
<!-- ✅ 使用CSS object-fit实现灵活适配 -->
<img src="photo.jpg" style="width: 300px; height: 200px; object-fit: cover;">Permissions & privacy
权限与隐私
Request permissions properly
合理请求权限
javascript
// ❌ Request on page load (bad UX, often denied)
navigator.geolocation.getCurrentPosition(success, error);
// ✅ Request in context, after user action
findNearbyButton.addEventListener('click', async () => {
// Explain why you need it
if (await showPermissionExplanation()) {
navigator.geolocation.getCurrentPosition(success, error);
}
});javascript
// ❌ 页面加载时请求(用户体验差,常被拒绝)
navigator.geolocation.getCurrentPosition(success, error);
// ✅ 用户操作后,在合适场景请求
findNearbyButton.addEventListener('click', async () => {
// 说明权限用途
if (await showPermissionExplanation()) {
navigator.geolocation.getCurrentPosition(success, error);
}
});Permissions policy
权限策略
html
<!-- Restrict powerful features -->
<meta http-equiv="Permissions-Policy"
content="geolocation=(), camera=(), microphone=()">
<!-- Or allow for specific origins -->
<meta http-equiv="Permissions-Policy"
content="geolocation=(self 'https://maps.example.com')">html
<!-- 限制高权限特性 -->
<meta http-equiv="Permissions-Policy"
content="geolocation=(), camera=(), microphone=()">
<!-- 或允许特定源使用 -->
<meta http-equiv="Permissions-Policy"
content="geolocation=(self 'https://maps.example.com')">Audit checklist
审计检查清单
Security (critical)
安全(关键)
- HTTPS enabled, no mixed content
- No vulnerable dependencies ()
npm audit - CSP headers configured
- Security headers present
- No exposed source maps
- 已启用HTTPS,无混合内容
- 无存在漏洞的依赖()
npm audit - 已配置CSP响应头
- 存在安全响应头
- 未暴露源映射
Compatibility
兼容性
- Valid HTML5 doctype
- Charset declared first in head
- Viewport meta tag present
- No deprecated APIs used
- Passive event listeners for scroll/touch
- 有效的HTML5文档类型
- 字符编码声明在head最顶部
- 存在视口元标签
- 未使用已废弃API
- 为滚动/触摸事件使用被动监听器
Code quality
代码质量
- No console errors
- Valid HTML (no duplicate IDs)
- Semantic HTML elements used
- Proper error handling
- Memory cleanup in components
- 无控制台错误
- 有效的HTML(无重复ID)
- 使用了语义化HTML元素
- 正确的错误处理
- 组件中存在内存清理逻辑
UX
用户体验
- No intrusive interstitials
- Permission requests in context
- Clear error messages
- Appropriate image aspect ratios
- 无侵入式插屏
- 在合适场景请求权限
- 清晰的错误提示
- 图片宽高比合理
Tools
工具
| Tool | Purpose |
|---|---|
| Dependency vulnerabilities |
| SecurityHeaders.com | Header analysis |
| W3C Validator | HTML validation |
| Lighthouse | Best practices audit |
| Observatory | Security scan |
| 工具 | 用途 |
|---|---|
| 检测依赖漏洞 |
| SecurityHeaders.com | 响应头分析 |
| W3C Validator | HTML验证 |
| Lighthouse | 最佳实践审计 |
| Observatory | 安全扫描 |
References
参考资料
- MDN Web Security
- OWASP Top 10
- Web Quality Audit
- MDN Web Security
- OWASP Top 10
- Web Quality Audit