最佳实践Skill best-practices

这个技能用于应用现代网页开发的最佳实践,专注于安全、浏览器兼容性和代码质量改进。关键词:网页开发、前端安全、兼容性优化、代码审核、HTTPS、CSP、语义HTML、错误处理、性能优化。

前端开发 0 次安装 0 次浏览 更新于 3/15/2026

name: 最佳实践 description: 应用现代网页开发最佳实践,涵盖安全、兼容性和代码质量。 license: MIT metadata: author: web-quality-skills version: ‘1.0’

最佳实践

基于Lighthouse最佳实践审核的现代网页开发标准。涵盖安全、浏览器兼容性和代码质量模式。

安全

HTTPS无处不在

强制执行HTTPS:

<!-- ❌ 混合内容 -->
<img src="http://example.com/image.jpg" />
<script src="http://cdn.example.com/script.js"></script>

<!-- ✅ 仅HTTPS -->
<img src="https://example.com/image.jpg" />
<script src="https://cdn.example.com/script.js"></script>

<!-- ✅ 协议相对(使用页面协议) -->
<img src="//example.com/image.jpg" />

HSTS头:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

内容安全策略 (CSP)

<!-- 通过meta标签的基本CSP -->
<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;"
/>

<!-- 更好:HTTP头 -->

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处理内联脚本:

<script nonce="abc123">
  // 这个内联脚本被允许
</script>

安全头

# 防止点击劫持
X-Frame-Options: DENY

# 防止MIME类型嗅探
X-Content-Type-Options: nosniff

# 启用XSS过滤器(旧浏览器)
X-XSS-Protection: 1; mode=block

# 控制引用信息
Referrer-Policy: strict-origin-when-cross-origin

# 权限策略(原Feature-Policy)
Permissions-Policy: geolocation=(), microphone=(), camera=()

无漏洞库

# 检查漏洞
npm audit
yarn audit

# 自动修复可能的问题
npm audit fix

# 检查特定包
npm ls lodash

保持依赖更新:

// package.json
{
  "scripts": {
    "audit": "npm audit --audit-level=moderate",
    "update": "npm update && npm audit fix"
  }
}

避免已知漏洞模式:

// ❌ 原型污染漏洞模式
Object.assign(target, userInput)
_.merge(target, userInput)

// ✅ 更安全的替代方法
const safeData = JSON.parse(JSON.stringify(userInput))

输入消毒

// ❌ XSS漏洞
element.innerHTML = userInput
document.write(userInput)

// ✅ 安全文本内容
element.textContent = userInput

// ✅ 如果需要HTML,消毒
import DOMPurify from 'dompurify'
element.innerHTML = DOMPurify.sanitize(userInput)

安全cookie

// ❌ 不安全cookie
document.cookie = "session=abc123";

// ✅ 安全cookie(服务器端)
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/

浏览器兼容性

文档类型声明

<!-- ❌ 缺少或无效doctype -->
<html>
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">

  <!-- ✅ HTML5 doctype -->
  <!DOCTYPE html>
  <html lang="en"></html>
</html>

字符编码

<!-- ❌ 缺少或延迟字符集 -->
<html>
  <head>
    <title>页面</title>
    <meta charset="UTF-8" />
  </head>

  <!-- ✅ 字符集作为head中第一个元素 -->
  <html>
    <head>
      <meta charset="UTF-8" />
      <title>页面</title>
    </head>
  </html>
</html>

视口meta标签

<!-- ❌ 缺少视口 -->
<head>
  <title>页面</title>
</head>

<!-- ✅ 响应式视口 -->
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>页面</title>
</head>

功能检测

// ❌ 浏览器检测(脆弱)
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;
  }
}

补丁(如果需要)

<!-- 有条件加载补丁 -->
<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>

已弃用API

避免这些

// ❌ 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);

// ❌ 应用缓存(已弃用)
<html manifest="cache.manifest">

// ✅ 服务工作者
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

事件监听器被动模式

// ❌ 非被动触摸/滚轮(可能阻塞滚动)
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.log('调试信息') // 在生产环境中移除
throw new Error('未处理') // 捕获所有错误

// ✅ 适当错误处理
try {
  riskyOperation()
} catch (error) {
  // 记录到错误跟踪服务
  errorTracker.captureException(error)
  // 显示用户友好消息
  showErrorMessage('出错了。请重试。')
}

错误边界(React)

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>

全局错误处理程序

// 捕获未处理错误
window.addEventListener('error', (event) => {
  errorTracker.captureException(event.error)
})

// 捕获未处理的promise拒绝
window.addEventListener('unhandledrejection', (event) => {
  errorTracker.captureException(event.reason)
})

源映射

生产配置

// ❌ 生产环境中暴露源映射
// 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',
}

性能最佳实践

避免阻塞模式

// ❌ 阻塞脚本
<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">

高效事件处理程序

// ❌ 每个元素上的处理程序
items.forEach((item) => {
  item.addEventListener('click', handleClick)
})

// ✅ 事件委托
container.addEventListener('click', (e) => {
  if (e.target.matches('.item')) {
    handleClick(e)
  }
})

内存管理

// ❌ 内存泄漏(从未移除)
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()

代码质量

有效HTML

<!-- ❌ 无效HTML -->
<div id="header">
  <div id="header">
    <!-- 重复ID -->

    <ul>
      <div>项目</div>
      <!-- 无效子元素 -->
    </ul>

    <a href="/"><button>点击</button></a>
    <!-- 无效嵌套 -->

    <!-- ✅ 有效HTML -->
    <header id="site-header"></header>

    <ul>
      <li>项目</li>
    </ul>

    <a href="/" class="button">点击</a>
  </div>
</div>

语义HTML

<!-- ❌ 非语义 -->
<div class="header">
  <div class="nav">
    <div class="nav-item">首页</div>
  </div>
</div>
<div class="main">
  <div class="article">
    <div class="title">标题</div>
  </div>
</div>

<!-- ✅ 语义HTML5 -->
<header>
  <nav>
    <a href="/">首页</a>
  </nav>
</header>
<main>
  <article>
    <h1>标题</h1>
  </article>
</main>

图像宽高比

<!-- ❌ 扭曲图像 -->
<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;" />

权限和隐私

正确请求权限

// ❌ 页面加载时请求(不良UX,常被拒绝)
navigator.geolocation.getCurrentPosition(success, error)

// ✅ 在上下文中请求,用户操作后
findNearbyButton.addEventListener('click', async () => {
  // 解释为何需要
  if (await showPermissionExplanation()) {
    navigator.geolocation.getCurrentPosition(success, error)
  }
})

权限策略

<!-- 限制强大功能 -->
<meta http-equiv="Permissions-Policy" content="geolocation=(), camera=(), microphone=()" />

<!-- 或允许特定源 -->
<meta http-equiv="Permissions-Policy" content="geolocation=(self 'https://maps.example.com')" />

审核清单

安全(关键)

  • [ ] HTTPS启用,无混合内容
  • [ ] 无漏洞依赖(npm audit
  • [ ] CSP头配置
  • [ ] 安全头存在
  • [ ] 无暴露源映射

兼容性

  • [ ] 有效HTML5 doctype
  • [ ] 字符集在head中首先声明
  • [ ] 视口meta标签存在
  • [ ] 无使用已弃用API
  • [ ] 滚动/触摸事件使用被动事件监听器

代码质量

  • [ ] 无控制台错误
  • [ ] 有效HTML(无重复ID)
  • [ ] 使用语义HTML元素
  • [ ] 适当错误处理
  • [ ] 组件中内存清理

UX

  • [ ] 无侵入性插页
  • [ ] 权限请求在上下文中
  • [ ] 清晰错误消息
  • [ ] 适当图像宽高比

工具

工具 用途
npm audit 依赖漏洞检查
SecurityHeaders.com 头分析
W3C Validator HTML验证
Lighthouse 最佳实践审核
Observatory 安全扫描

参考