动态 import() 是唯一可行方式,静态 import './style.css' 在所有浏览器中均失败;需 HTTP(S) 服务、text/css 响应头、CORS 头,并手动注入 document.adoptedStyleSheets。

动态 import() 是唯一可行入口
静态 import './style.css' 在任何浏览器里都会失败,不是语法报错,而是加载阶段直接中断:TypeError: Failed to fetch dynamically imported module 或 MIME type ('text/css') is not executable。规范明确禁止在静态 import 语句中使用 assert,哪怕写了 assert: { type: 'css' } 也会被忽略。真正能走通的只有 import() 动态调用 —— 这是 Chrome 124+、Firefox 125+、Safari 17.4+ 唯一实现的路径。
服务端响应头和协议是硬门槛
即使代码写对,import('./style.css', { assert: { type: 'css' } }) 仍会挂掉,常见原因就两个:
- HTML 页面用
file://协议打开:CORS 和 MIME 校验全崩,必须走http://或https://(比如http://localhost:5173) - CSS 文件响应头缺失:
Content-Type: text/css和Access-Control-Allow-Origin: *(或具体域名)缺一不可
Vite / Webpack 开发服务器默认满足这两点;但用 python3 -m http.server 或 Nginx 静态托管时,得手动配好头,否则白忙活。
加载后必须手动注入 adoptedStyleSheets
成功调用后返回的不是 JS 模块对象,而是一个 CSSStyleSheet 实例,挂载在 default 属性上。它不会自动生效,必须显式写入 document.adoptedStyleSheets:
立即学习“前端免费学习笔记(深入)”;
const styleSheet = await import('./style.css', { assert: { type: 'css' } });
document.adoptedStyleSheets = [...document.adoptedStyleSheets, styleSheet.default];
注意点:
- 别直接赋值
document.adoptedStyleSheets = [styleSheet.default],会覆盖已有样式表(比如框架注入的) - 多次调用需用展开运算符合并数组,不能用
push()(adoptedStyleSheets是只读属性) -
styleSheet没有命名导出,只有default;写styleSheet.foo会是undefined
替代方案比硬啃原生更实际
如果你不是为写 Demo 或验证浏览器能力,真没必要卡在这条路上:
- 开发阶段直接用 Vite:
import './style.css'开箱即用,连type="module"都不用手写 - 想零构建又不想配服务?把
@import './reset.css';写进主 CSS 文件里——这是 CSS 原生支持的,无兼容性问题,也不挑协议 - 生产环境一律走构建工具提取 CSS 到
<link>,性能、缓存、预加载都更可控
真正容易被忽略的是:服务端配置和协议限制不是“可选优化”,而是运行前提。代码写得再漂亮,没 text/css 响应头或还在双击打开 HTML,就永远停在报错那一步。


















