Correct way to apply global styles into Shadow DOM

我是研究僧i 提交于 2019-12-18 03:41:37

问题


This questions is similar to some other on StackOverflow, but I couldn't find any answer describing applicable to my situation and non-deprecated method (and I'm starting thinking that maybe there is no any good solution for that situation).

Let's say we have some main.css file which includes common styles for buttons, lists, links and so on. So it's just some standard .css file which contains common styles that we want to reuse across the application. And we want to apply the same styles to Web Components with Shadow DOM.

There are a few ways, that I know about, to accomplish that:

  1. Using one of deprecated approaches: ::shadow, >>>, /deep/ selectors. But those selectors are deprecated by now, so I guess it's not good approach to move forward with.
  2. Using css variables. This approach is good for customization purposes, if we need to set a few properties. But it's too complex if we want to migrate 10-20 common styles from main.css file.
  3. Using @import statement or "link" tags inside of Shadow DOM. It will work, but it will duplicate all styles for every component. If we have 10 web components we will end up with 10 duplicates of exactly the same styles. It doesn't sound like good enough solution too. Especially if we have a lot of common styles, sounds like it can be bad solution from performance point of view.
  4. Don't use Shadow DOM at all and use global styles :) But it's not solution for current problem.

I also checked how the same problem resolved in Angular Framework (I checked version 5 of Angular). When I set encapsulation behavior to Native, it's just actually duplicating styles (like in #3 described above), what I think isn't the best way (but maybe the best currently existing way).

So, does anyone know if there is any other way to solve this problem without described above drawbacks? It just sounds like current drawbacks of Shadow DOM bring even more problems than it tries to solve.


回答1:


There's no real drawback with solution 3:

  1. Whether you apply a CSS style to n elements in a main document, or to 1 element in n Shadow DOM, the style will be duplicated to the whole n elements anyways.

  2. If you import a document n times in n Shadow DOM, il will be actually be loaded only one time and reused through the browser cache.

After that, il will rely on the browser implementation of Shadow DOM and CSS styles, and you should see a performance degradation only the thousands of Shadow DOM.


2019 update for Chrome 73+ and Opera 60+

Now you can directly instanciate a CSSStyleSheet object and assign it to different Shadow DOMs.

This way the HTML won't be duplicated.

var css = new CSSStyleSheet()
css.replaceSync( "@import url( main.css )" )
host.shadowRoot.adoptedStyleSheets = [css] 
host2.shadowRoot.adoptedStyleSheets = [css] 

You can also apply it to the global document:

document.adpotedStyleSheets = [css]

The other advantage is that an update on the stylesheet will be applied to all Shadow DOMs (and document) that adopted it.

 css.replaceSync( '.color { color: red }' )



回答2:


I managed to do it using javascript modules but I doubt it's the cleanest solution. You can create a GlobalStyles.js file that will contain the css styling that is common throughout various components. Changing the language mode on your editor to 'html' will provide syntax highlighting for the 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;

Afterwards, you can import it into another js file that contains the code to the shadow dom of your custom element.

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));
    }
}

The drawback with this approach is it only works if you are working purely with js files.



来源:https://stackoverflow.com/questions/53244494/correct-way-to-apply-global-styles-into-shadow-dom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!