stencil 组件样式必须与 .tsx 文件同目录,编译器仅识别同目录下的 .scss/.css 并内联或打包;跨目录样式不被识别,会导致未注入、:host 失效或全局污染。

Stencil 组件样式必须和 .tsx 放在同一目录下
Stencil 编译器在构建时会自动收集同目录下的 .scss 或 .css 文件,并将其内联或打包进组件的 CSS bundle。如果把样式文件放到别处(比如统一放在 src/styles/),即使你手动 import,Stencil 也不会识别为该组件的“专属样式”,最终导致:样式未注入、:host 作用域失效、或者被抽成全局 CSS。
正确结构示例:
card/ ├── card.tsx ├── card.scss ├── card.ios.scss └── card.md.scss
-
card.scss是默认样式,会被所有平台加载 -
card.ios.scss和card.md.scss是平台条件样式,需在@Component中通过styleUrl动态指定 - 不要用
import './card.scss'在.tsx里显式引入 —— Stencil 不处理这种写法
styleUrl 必须是相对路径字符串,不能是变量或表达式
Stencil 的编译期静态分析只识别字面量字符串,比如 styleUrl: 'card.scss'。若写成 styleUrl: platform === 'ios' ? 'card.ios.scss' : 'card.md.scss',构建会失败或降级为无样式。
实操方式是使用 mode 配置 + 条件样式文件命名:
- 在
stencil.config.ts中配置outputTargets: [{ type: 'www', ... }, { type: 'dist', ... }]同时启用buildEs5: true和enableCache: true - 组件中写死多个
styleUrl:styleUrl: ['card.scss', 'card.ios.scss'],Stencil 会按需合并 - 更推荐方式:用
mode属性控制样式加载逻辑,例如<my-card mode="ios"></my-card>,然后在componentWillLoad()中动态import()对应样式模块(需配合defineCustomElements()的异步加载机制)
H5 端引入外部 CSS(如 swiper、hls.js)要走 globalStyle 或 external 配置
像 Swiper 这类依赖全局 CSS 的第三方库,不能靠组件内部 styleUrl 加载。否则会出现样式未生效、重复插入、或与 Shadow DOM 冲突的问题。
正确做法分两类:
- 全局依赖:在
stencil.config.ts中配置globalStyle: 'src/global.css',把第三方 CSS 提前注入 - 按需注入:对特定组件(如
swiper),在componentDidLoad()中动态创建<link rel="stylesheet">标签并 append 到document.head,同时注意避免重复加载(加标记 class 或检查document.querySelector) - 禁止在
render()中import外部 CSS —— 它不会触发样式注入,且破坏 SSR 友好性
构建产物中 CSS 分发路径容易被忽略
Stencil 默认产出的 CSS 文件名是 my-component.css,但实际加载时依赖 defineCustomElements() 注入的 <link> 标签或内联 <style></style>。如果你用 CDN 分发,必须确保 my-component.css 和 JS 文件在同一路径层级,否则 404。
常见坑点:
- Webpack/Vite 构建项目里直接
import '@company/my-components',但没配public/或assets/映射,导致 CSS 请求 404 - 自定义
outputTargets时改了dir,但忘了同步更新index.html中的<script type="module"></script>路径 - 开启
shadow: true后,外部覆盖样式失效,误以为是 CSS 没加载,其实是作用域隔离导致
最稳妥的做法:始终用 defineCustomElements() 启动组件,它会自动处理 CSS 加载时机和路径解析;手动管理 <link> 只适用于极简场景或调试阶段。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











