Web Components详解-Shadow DOM样式控制

简介: Web Components详解-Shadow DOM样式控制

前言

本文继续Web Components系列文章,介绍一下Shadow DOM的样式及选择器。

Shadow DOM的样式与外界是隔离的,即自定义元素的样式只会影响到Shadow DOM内部,不会影响到外部的页面元素,这点在之前有说到过。那么有什么办法可以在Shadow DOM中使用全局样式?样式选择器又有什么异同呢?请跟着本篇文章一起探究

:host伪类

作为伪类使用

:host一般在Shadow DOM中使用,代指宿主标签(自定义标签)使用它可以在Shadow DOM内部为自定义元素定义样式,host伪类的语法是::host { /* 样式规则 */ },例如

<body>
    <host-element></host-element>
 
    <script>
        class HostElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: "open" })
                this.shadowRoot.textContent = "host-element"
                this.addStyle()
            }
            addStyle() {
                const styleEle = document.createElement("style");
                // 加点样式
                styleEle.textContent = `
            :host {
                font-size:20px;
                color:lightblue;
                border: 1px solid black;
            }`
                this.shadowRoot.appendChild(styleEle)
            }
        }
        customElements.define("host-element", HostElement)
    </script>
</body>

作为选择器使用

除了使用:host伪类外,:host还提供了selector的选择器使用方式,用于过滤某个条件下的宿主标签,比如我们选择属性为isHost的标签、class为isHost的标签以及id为isHost的标签并分别设置不同的样式进行区分

<body>
    <host-element></host-element>
    <host-element isHost></host-element>
    <host-element class="isHost"></host-element>
    <host-element id="isHost"></host-element>
    <script>
        class HostElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: "open" })
                this.shadowRoot.textContent = "host-element"
                this.addStyle()
            }
            addStyle() {
                const styleEle = document.createElement("style");
                // 加点样式
                styleEle.textContent = `
            :host {
                font-size:20px;
                color:lightcoral;
                border: 1px solid black;
            }
            :host([isHost]) {
                background:lightgreen;
            }
            :host(.isHost) {
                background:lightblue;
            }
            :host(#isHost) {
                background:green;
            }`
                this.shadowRoot.appendChild(styleEle)
            }
        }
        customElements.define("host-element", HostElement)
    </script>
</body>

效果如下

::part伪元素

::part伪元素选择器是Shadow DOM中的选择器之一,它可以为自定义元素内部的特定部分(一般是子元素)定义样式,结合上面的伪类选择器host我们可以使用它选择当前宿主标签下的某个部分的子元素,并设置该部分独有的样式,思考下面的代码:

<body>
    <part-element></part-element>
    <script>
        class PartElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: "open" })
                this.addStyle()
                this.addTreeElems()
            }
            addTreeElems() {
                this.shadowRoot.innerHTML += `
                    <div part="part1 part3">part1</div>
                    <div part="part2">part2</div>
                    <div part="part3">part3</div>`
            }
            addStyle() {
                const styleEle = document.createElement("style");
                // 加点样式
                styleEle.textContent = `
            :host {
                font-size:20px;
                display:flex;
                justify-content: space-evenly;
                border: 1px solid black;
            }
            :host::part(part1) {
                color: lightcoral;
            }
            :host::part(part2) {
                color: lightblue;
            }
            :host::part(part3) {
                background: lightgreen;
            }`
                this.shadowRoot.appendChild(styleEle)
            }
        }
        customElements.define("part-element", PartElement)
    </script>
</body>

我们将div分成3个part(tips:part用法和class相似,一个part属性可以设置多个值,使用空格隔开),分别为三者设置不同的样式,在css中同样针对不同part设置了不同的样式,效果如下

::slotted伪元素

使用::slotted可以对Shadow DOM中的绑定了插槽的元素设置样式,并且它只能给外层元素设置样式,无法选择到子元素,参考下面的代码

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <slotted-element>
        <header slot="header">header</header>
        <main class="main" slot="content">
            <span>content</span>
        </main>
        <footer slot="footer">footer</footer>
    </slotted-element>
    <div id="slots">
        <slot name="header"></slot>
        <slot name="content"></slot>
        <slot name="footer"></slot>
    </div>
    <script>
        class SlottedElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: "open" })
                this.addStyle()
                this.shadowRoot.appendChild(slots)
            }
            addStyle() {
                const styleEle = document.createElement("style");
                // 加点样式
                styleEle.textContent = `
                #slots{
                    /* 根标签 */
                    background: lightblue;
                }
                ::slotted(header) {
                    /* 标签选择器 */
                    background: lightcoral;
                }
                ::slotted(.main) {
                    /* 类选择器 */
                    color: lightcoral;
                }
                ::slotted(.main) span{
                    /* 无效的选择器,只能选择插槽元素,选不到子元素 */
                    color: red;
                }
                ::slotted([slot="footer"]) {
                    /* 属性选择器 */
                    background: lightcoral;
                    color: lightseagreen;
                }
                `
                this.shadowRoot.appendChild(styleEle)
            }
        }
        customElements.define("slotted-element", SlottedElement)
    </script>
</body>
 
</html>

效果如下:

:host-context伪类

host-context表示宿主外部祖先节点满足某个选择器时生效对应样式,比如下面代码:

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <div>
        <host-element></host-element>
    </div>
    <div isHost>
        <host-element></host-element>
    </div>
    <div class="isHost">
        <host-element></host-element>
    </div>
    <div id="isHost">
        <host-element></host-element>
    </div>
 
    <script>
        class HostElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: "open" })
                this.shadowRoot.textContent = "host-element"
                this.addStyle()
            }
            addStyle() {
                const styleEle = document.createElement("style");
                // 加点样式
                styleEle.textContent = `
            :host-context(div) {
                font-size:20px;
                color:lightcoral;
                border: 1px solid black;
            }
            :host-context([isHost]) {
                background:lightgreen;
            }
            :host-context(.isHost) {
                background:lightblue;
            }
            :host-context(#isHost) {
                background:green;
            }`
                this.shadowRoot.appendChild(styleEle)
            }
        }
        customElements.define("host-element", HostElement)
    </script>
</body>
 
</html>

上面的代码中,我们分别对div标签,isHost属性,类名为isHost,id为isHost这四类选择器生效时其子标签展示出不同的的样式效果做了一个示例,效果如下

样式变量

在影子DOM中使用全局样式可以通过CSS的样式变量的形式来实现,在CSS样式变量的文章中,我们探讨了CSS样式var关键字的用法,我们可以在全局定义变量,然后在阴影DOM中使用对应变量的方式实现全局样式的引用:

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
    <style>
        /* 可以在shadowDom中使用 */
        [theme="theme1"] {
            --primary-color: lightblue;
            --primary-font-size: 20px;
        }
 
        /* 只能作用于自定义标签上 */
        variable-element {
            background: lightcoral;
        }
    </style>
</head>
 
<body theme="theme1">
    <div>
        <variable-element></variable-element>
    </div>
    <script>
        class VariableElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: "open" })
                this.shadowRoot.textContent = "variable-element"
                this.addStyle()
                this.addElem()
            }
            addElem() {
                const divEle = document.createElement("div")
                divEle.textContent = "divEle"
                this.shadowRoot.appendChild(divEle)
            }
            addStyle() {
                const styleEle = document.createElement("style");
                // 加点样式
                styleEle.textContent = `
            :host {
                color: var(--primary-color);
                font-size: var(--primary-font-size);
            }
            `
                this.shadowRoot.appendChild(styleEle)
            }
        }
        customElements.define("variable-element", VariableElement)
    </script>
</body>
 
</html>

总结

本文介绍了在Web Components中使用Shadow DOM的样式及选择器的相关知识点,其中:host伪类用于在Shadow DOM内部为自定义元素定义样式;::part伪元素选择器可以为Shadow DOM内部的特定部分(一般是子元素)定义样式;::slotted伪元素选择器用于选择插槽中的元素;:host-context(selector)则是用于选择满足特定选择器条件的宿主外部祖先节点,并为宿主标签设置样式;最后是全局样式的使用途径:CSS变量。

以上就是文章的全部内容了,如果觉得文章不错的话,还望三连支持一下!谢谢~

相关文章
|
5天前
|
JavaScript 前端开发 API
Web Components详解-HTML Templates
Web Components详解-HTML Templates
16 6
|
5天前
|
设计模式 JavaScript 前端开发
Web Components详解-组件通信
Web Components详解-组件通信
11 6
|
5天前
|
JavaScript API 开发者
Web Components详解-Shadow DOM插槽
Web Components详解-Shadow DOM插槽
|
5天前
|
JavaScript 前端开发 开发者
Web Components详解-Shadow DOM基础
Web Components详解-Shadow DOM基础
|
前端开发
使用SAP UI5 Web Components开发React应用
使用SAP UI5 Web Components开发React应用
109 0
使用SAP UI5 Web Components开发React应用
|
7天前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
25 0
|
2天前
|
设计模式 Rust 安全
深入理解PHP 7的新特性及其对现代Web开发的影响
本文通过数据驱动的分析,探讨了PHP 7的发布如何革新了Web开发的面貌。文章首先概述了PHP 7带来的性能提升与新特性,然后通过实际案例和性能测试数据,详细讨论了这些新特性对提高代码效率、增强安全性和支持现代编程范式的具体影响。最后,文章将评估PHP 7在当前Web开发环境中的地位,并对其未来的发展做出展望。
|
8天前
|
安全 编译器 API
探索PHP 8的新特性及其对现代Web开发的影响
随着PHP 8的正式发布,这一版本带来了多项重大改进和新特性,旨在提升性能、增加语言的灵活性并简化开发流程。本文将详细探讨PHP 8中的关键更新,包括JIT编译器、联合类型、命名参数、匹配表达式等,并分析这些新特性如何影响现代Web开发的实践。通过引用最新的性能数据和开发者反馈,我们将深入理解PHP 8带来的变革,以及它对现有项目和未来趋势的潜在影响。
|
8天前
|
安全 大数据 PHP
深入理解PHP 7中的新特性及其对现代Web开发的影响
【6月更文挑战第28天】本文将深入探讨PHP 7带来的革新,从性能提升到语法改进,揭示这些变化如何重塑Web开发领域。我们将一窥未来PHP的发展趋势,并分析开发者如何利用这些新特性来构建更快、更安全、更易于维护的应用程序。
14 1
|
10天前
|
程序员 PHP 数据库
深入理解PHP 7的新特性及其对现代Web开发的影响
【6月更文挑战第26天】随着互联网技术的飞速发展,PHP作为服务端脚本语言的佼佼者,其最新版本PHP 7带来了性能和功能上的显著提升。本文将深度剖析PHP 7中的新特性,并探讨这些变化如何优化现代Web开发实践,提升应用性能及开发效率。我们将从语言本身的变化到实际应用案例,全面解读PHP 7给开发者带来的福音。
10 1