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变量。

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

相关文章
|
1月前
|
编解码 前端开发 JavaScript
使用 CSS 打印样式为 Web 页面设置专业的打印机效果
使用 CSS 打印样式为 Web 页面设置专业的打印机效果
52 2
|
2月前
|
XML 缓存 JavaScript
提升对前端的认知,不得不了解Web API的DOM和BOM
该文章强调了在前端开发中理解和掌握DOM(文档对象模型)和BOM(浏览器对象模型)的重要性,并介绍了它们的相关操作和应用。
提升对前端的认知,不得不了解Web API的DOM和BOM
|
2月前
|
前端开发
【前端web入门第五天】03 清除默认样式与外边距问题【附综合案例产品卡片与新闻列表】
本文档详细介绍了CSS中清除默认样式的方法,包括清除内外边距、列表项目符号等;探讨了外边距的合并与塌陷问题及其解决策略;讲解了行内元素垂直边距的处理技巧;并介绍了圆角与盒子阴影效果的实现方法。最后通过产品卡片和新闻列表两个综合案例,展示了所学知识的实际应用。
59 11
|
3月前
|
XML JavaScript 前端开发
哇塞!Web 前端惊现 DOM 元素神操作,一场惊心动魄的网页变革,你准备好了吗?
【8月更文挑战第23天】在Web前端开发中,熟练操作DOM元素至关重要。DOM作为一种编程接口,将HTML/XML文档表示为节点树,便于使用JavaScript访问及修改文档内容与结构。
58 0
|
3月前
|
XML JavaScript 测试技术
Web自动化测试框架(基础篇)--HTML页面元素和DOM对象
本文为Web自动化测试入门指南,介绍了HTML页面元素和DOM对象的基础知识,以及如何使用Python中的Selenium WebDriver进行元素定位、操作和等待机制,旨在帮助初学者理解Web自动化测试中的关键概念和操作技巧。
53 1
|
3月前
|
开发者 前端开发 UED
打造企业专属形象:Vaadin主题与样式定制,让你的Web应用脱颖而出!
【8月更文挑战第31天】在Web应用开发中,界面设计至关重要。Vaadin框架提供强大的主题和样式定制功能,助力开发者打造符合品牌形象的独特外观。本文详细介绍了Vaadin主题的概念及创建流程,并演示了如何通过CSS和SCSS定制组件样式,使用主题继承扩展现有主题,以及为特定组件设置专属样式。遵循这些最佳实践,不仅能提升用户体验,还能增强品牌的识别度,让你的应用更加出众。
37 0
|
4月前
|
JavaScript 前端开发 API
Web Components详解-HTML Templates
Web Components详解-HTML Templates
78 6
|
4月前
|
设计模式 JavaScript 前端开发
Web Components详解-组件通信
Web Components详解-组件通信
81 6
|
1月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
101 3
|
17天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
105 45