将全局样式应用到 Shadow 的正确方法 DOM
Correct way to apply global styles into Shadow DOM
这个问题与 Whosebug 上的其他一些问题类似,但我找不到任何描述适用于我的情况和未弃用方法的答案(我开始考虑可能没有任何好的解决方案)情况)。
假设我们有一些 main.css 文件,其中包含按钮、列表、链接等的常用样式。所以它只是一些标准的 .css 文件,其中包含我们希望在整个应用程序中重用的常用样式。我们希望将相同的样式应用于带有阴影的 Web 组件 DOM。
据我所知,有几种方法可以做到这一点:
- 使用一种已弃用的方法:::shadow、>>>、/deep/ 选择器。但是这些选择器现在已经被弃用了,所以我想这不是继续前进的好方法。
- 使用 css 个变量。如果我们需要设置一些属性,这种方法非常适合定制目的。但是如果我们想从 main.css 文件中迁移 10-20 个常用样式,那就太复杂了。
- 在 Shadow DOM 中使用 @import 语句或 "link" 标签。它会工作,但它会复制每个组件的所有样式。如果我们有 10 个 Web 组件,我们最终会得到 10 个完全相同样式的副本。这听起来也不是足够好的解决方案。特别是如果我们有很多通用样式,从性能的角度来看,这听起来可能不是一个好的解决方案。
- 根本不要使用 Shadow DOM 并使用全局样式:)但这不是当前问题的解决方案。
我还查看了 Angular 框架中如何解决相同的问题(我查看了 Angular 的第 5 版)。当我将封装行为设置为 Native 时,它实际上只是在复制样式(如上述 #3 中所述),我认为这不是最好的方式(但可能是目前最好的方式)。
那么,有没有人知道是否有任何其他方法可以解决这个问题而没有上述缺点?听起来 Shadow DOM 当前的缺点带来的问题比它试图解决的问题还要多。
解决方案 3 没有真正的缺点:
无论是将 CSS 样式应用到主文档中的 n 个元素,还是应用到 n 个 Shadow 中的 1 个元素 DOM,样式都会复制到整个 n无论如何元素。
如果在 n Shadow DOM 中导入文档 n 次,il 实际上只会加载一次并通过浏览器缓存重复使用。
之后,将取决于 Shadow DOM 和 CSS 样式的浏览器实现,您应该只会看到数千个 Shadow DOM.
2019 年更新 Chrome 73+ 和 Opera 60+
现在您可以直接实例化一个CSSStyleSheet
对象并将其分配给不同的阴影DOM。
这样 HTML 就不会重复了。
var css = new CSSStyleSheet()
css.replaceSync( "@import url( main.css )" )
host.shadowRoot.adoptedStyleSheets = [css]
host2.shadowRoot.adoptedStyleSheets = [css]
您也可以将其应用于全局文档:
document.adoptedStyleSheets = [css]
另一个优点是样式表的更新将应用于所有采用它的 Shadow DOM(和文档)。
css.replaceSync( '.color { color: red }' )
我设法使用 javascript 模块做到了,但我怀疑这是最干净的解决方案。
您可以创建一个 GlobalStyles.js 文件,其中将包含在各种组件中通用的 css 样式。将编辑器的语言模式更改为 'html' 将为 css.
提供语法高亮显示
const GlobalStyles = {
main: `
<style>
body {
overflow: hidden;
margin: 0;
font-family: 'Poppins';
}
h3 {
font-size: 39px;
}
</style>
`,
button: `
<style>
button {
display: block;
cursor: pointer;
outline: none;
font-family: 'Poppins Medium';
line-height: 17px;
padding: 9px 13px;
font-size: 15px;
background-color: #9f28d8;
color: white;
border: 2px solid;
border-radius: 5px;
border-color: #9f28d8;
width: max-content;
}
</style>
`
}
export default GlobalStyles;
之后,您可以将其导入另一个包含自定义元素阴影 dom 代码的 js 文件。
import GlobalStyles from './GlobalStyles.js';
const template = document.createElement('template');
template.innerHTML = `
${GlobalStyles.button}
<style>
ul {
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
width: 20em;
list-style-type: none;
}
</style>
<ul></ul>
<button>Click me</button>
`;
export class CustomList extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(document.importNode(template.content, true));
}
}
这种方法的缺点是它只适用于纯粹使用 js 文件的情况。
这个问题与 Whosebug 上的其他一些问题类似,但我找不到任何描述适用于我的情况和未弃用方法的答案(我开始考虑可能没有任何好的解决方案)情况)。
假设我们有一些 main.css 文件,其中包含按钮、列表、链接等的常用样式。所以它只是一些标准的 .css 文件,其中包含我们希望在整个应用程序中重用的常用样式。我们希望将相同的样式应用于带有阴影的 Web 组件 DOM。
据我所知,有几种方法可以做到这一点:
- 使用一种已弃用的方法:::shadow、>>>、/deep/ 选择器。但是这些选择器现在已经被弃用了,所以我想这不是继续前进的好方法。
- 使用 css 个变量。如果我们需要设置一些属性,这种方法非常适合定制目的。但是如果我们想从 main.css 文件中迁移 10-20 个常用样式,那就太复杂了。
- 在 Shadow DOM 中使用 @import 语句或 "link" 标签。它会工作,但它会复制每个组件的所有样式。如果我们有 10 个 Web 组件,我们最终会得到 10 个完全相同样式的副本。这听起来也不是足够好的解决方案。特别是如果我们有很多通用样式,从性能的角度来看,这听起来可能不是一个好的解决方案。
- 根本不要使用 Shadow DOM 并使用全局样式:)但这不是当前问题的解决方案。
我还查看了 Angular 框架中如何解决相同的问题(我查看了 Angular 的第 5 版)。当我将封装行为设置为 Native 时,它实际上只是在复制样式(如上述 #3 中所述),我认为这不是最好的方式(但可能是目前最好的方式)。
那么,有没有人知道是否有任何其他方法可以解决这个问题而没有上述缺点?听起来 Shadow DOM 当前的缺点带来的问题比它试图解决的问题还要多。
解决方案 3 没有真正的缺点:
无论是将 CSS 样式应用到主文档中的 n 个元素,还是应用到 n 个 Shadow 中的 1 个元素 DOM,样式都会复制到整个 n无论如何元素。
如果在 n Shadow DOM 中导入文档 n 次,il 实际上只会加载一次并通过浏览器缓存重复使用。
之后,将取决于 Shadow DOM 和 CSS 样式的浏览器实现,您应该只会看到数千个 Shadow DOM.
2019 年更新 Chrome 73+ 和 Opera 60+
现在您可以直接实例化一个CSSStyleSheet
对象并将其分配给不同的阴影DOM。
这样 HTML 就不会重复了。
var css = new CSSStyleSheet()
css.replaceSync( "@import url( main.css )" )
host.shadowRoot.adoptedStyleSheets = [css]
host2.shadowRoot.adoptedStyleSheets = [css]
您也可以将其应用于全局文档:
document.adoptedStyleSheets = [css]
另一个优点是样式表的更新将应用于所有采用它的 Shadow DOM(和文档)。
css.replaceSync( '.color { color: red }' )
我设法使用 javascript 模块做到了,但我怀疑这是最干净的解决方案。 您可以创建一个 GlobalStyles.js 文件,其中将包含在各种组件中通用的 css 样式。将编辑器的语言模式更改为 'html' 将为 css.
提供语法高亮显示const GlobalStyles = {
main: `
<style>
body {
overflow: hidden;
margin: 0;
font-family: 'Poppins';
}
h3 {
font-size: 39px;
}
</style>
`,
button: `
<style>
button {
display: block;
cursor: pointer;
outline: none;
font-family: 'Poppins Medium';
line-height: 17px;
padding: 9px 13px;
font-size: 15px;
background-color: #9f28d8;
color: white;
border: 2px solid;
border-radius: 5px;
border-color: #9f28d8;
width: max-content;
}
</style>
`
}
export default GlobalStyles;
之后,您可以将其导入另一个包含自定义元素阴影 dom 代码的 js 文件。
import GlobalStyles from './GlobalStyles.js';
const template = document.createElement('template');
template.innerHTML = `
${GlobalStyles.button}
<style>
ul {
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
width: 20em;
list-style-type: none;
}
</style>
<ul></ul>
<button>Click me</button>
`;
export class CustomList extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(document.importNode(template.content, true));
}
}
这种方法的缺点是它只适用于纯粹使用 js 文件的情况。