纯前端无构建时唯一可行方案是 fetch 动态加载 HTML 片段,需等 DOMContentLoaded 后执行、显式调用 response.text()、用 insertAdjacentHTML 插入,并配 whatwg-fetch polyfill 兼容 IE11。

纯前端无构建时用 fetch 动态加载 HTML 片段
浏览器原生不支持 <include> 或 <!--#include-->,双击打开 index.html 时所有服务端或模板语法都失效。此时唯一可行的轻量方案是 JS 运行时加载。
常见错误现象:404 加载 nav.html;document.getElementById 返回 null(脚本执行太早);插入后 <script> 标签不执行;IE11 报 fetch is not defined。
- 必须等
DOMContentLoaded触发后再 fetch,不能放在<head>里裸写script -
fetch('nav.html')返回的是文本,要显式调用response.text(),不能直接当 HTML 解析 - 插入推荐用
insertAdjacentHTML('beforeend', htmlString),比innerHTML =更安全(不销毁已绑定事件) - 需配
whatwg-fetchpolyfill 才兼容 IE11;CSP 策略若限制script-src 'self',则内联脚本可能被拦截
Webpack/Vite 构建阶段注入 HTML 片段
这是现代前端项目最稳的路径:所有复用逻辑在打包时完成,最终输出静态 HTML 文件,无运行时依赖、无白屏风险、SEO 友好。
关键不是“往 HTML 里塞字符串”,而是让构建插件把内容作为变量传入模板引擎上下文。
立即学习“前端免费学习笔记(深入)”;
- Webpack +
html-webpack-plugin:启用templateParameters,用require('raw-loader!./src/partials/header.html')读取片段(Webpack 5+ 需单独装raw-loader) - Vite +
vite-plugin-html:配置inject: { data: { header: '<nav>...</nav>' } },模板中用<%= header %>插值(注意后缀得是.html或.ejs) - 所有被引入的片段(如
header.html)不能含<html>、<body>标签,否则生成 HTML 会结构嵌套错乱 - 路径必须相对于
require调用位置(Webpack)或项目根目录(Vite),写错直接报Module not found
Web Components 封装可复用的自定义元素
如果你需要真正隔离样式与行为、跨框架复用、且能响应属性变化,CustomElement 是目前唯一的原生方案。它不是“注入 HTML”,而是注册新标签。
容易踩的坑:IE 完全不支持;<template> 必须放在 document.body 外层;connectedCallback 里操作全局 DOM 会破坏封装性。
-
<template id="navbar"><nav><slot></slot></nav></template>——<slot>支持外部传内容 - JS 中用
customElements.define('my-navbar', class extends HTMLElement { ... })注册,之后直接写<my-navbar></my-navbar> - Shadow DOM 默认关闭样式穿透,若需继承页面字体/颜色,得在
:host里手动声明或用inherit - 注册前必须确保 class 已定义,否则
customElements.define()报TypeError: Class constructor cannot be invoked without 'new'
服务端渲染或静态站点生成器的 include 语法
有后端或使用 SSG(如 Hugo、Jekyll、Eleventy)时,{% include 'header.html' %} 这类语法才真正有效——它由服务端或构建工具在生成 HTML 时展开,不是浏览器解析的。
常见错误:本地双击打开显示原始注释文字;Nginx/Apache 未开启 SSI 模块;Jinja2 模板里 {% extends %} 前有空格导致报错。
- SSI(
<!--#include file="nav.html" -->)仅在服务器启用模块、文件后缀为.shtml、且走 HTTP 协议时生效 - Jinja2/
extends:{% extends "base.html" %}必须是模板第一行,子模板变量需加with context才能透传 - Eleventy 的
{% include 'nav.njk' %}路径相对于_includes/目录,不是当前文件位置 - 所有服务端方案都要求部署环境配合,本地
python -m http.server不支持 SSI,得换ssi-server或 Nginx
template 标签本身不能跨文件复用,iframe 会带来样式隔离和 SEO 损失,document.write 已被弃用。真正能兼顾开发效率、维护性和运行时表现的,只有构建阶段注入和 Web Components 两条路——前者适合已有工程化流程的项目,后者适合需要强封装的 UI 组件库。



















