24

Shadow dom encapsulate css styles, selectors don't cross the shadow boundary.

Question: How to use global common css styles in shadow dom?
(suppose there are some common css styles which will be used across all pages (e.g.: font-family, h1, h2, clear, reset ...), how to make it works in shadow dom?)

Rao
  • 20,781
  • 11
  • 57
  • 77
Jiubao
  • 241
  • 1
  • 2
  • 3

6 Answers6

8

I've just struggled with the same problem as an original issue, namely: defining once some global rule for, say, <h3> element and benefit from that within any/many ShadowDOMs.

No, css-variables are not suited well for this thing, since even if I've defined once, say, font and color variables for <h3>, I'll still need to go over each and every shadowed stylesheet and add a CSS rule consuming them.

At the point of writing this (yes, we are 2019 now) the shortest standardized solution is indeed importing some global common CSS. Works perfectly in Chrome, Firefox and Anaheim (Edge on Chromium).

It still requires to add an @import rule in each and every component, so still costy (from coding/maintenance POV, the stylesheet fetched only once), but that's the lowest price we can pay now.

GullerYA
  • 1,320
  • 14
  • 27
4

Some solutions:

Please note, one of the articles listed above was also pointed out by Amid. By the time that article was written, Chrome had no CSS variables. But now it already works natively with the recently launched Google Chrome 49.

Community
  • 1
  • 1
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
  • 3
    Thanks! So CSS variable, :host-context, ::shadow(deprecated) are the answers for this question. While, the context for this question is: when I'm trying angular2, it introduces shadow DOM for components. My concern is, if we encapsulate the whole page into one nested shadow DOM tree, above things may not be a solution for css sharing, imagine we involve in bootstrap, how do we use it in shadow DOM? – Jiubao Mar 07 '16 at 06:35
  • 1
    I see how to use CSS variables, but it feels awkward not to be able to override browser built-in styles globally. The docs and specs seem to change again and again. There's changin @apply syntax, deprecated ::shadow, experimental ::theme and so on. Anybody with a sustainable solution? – Markus Apr 25 '18 at 08:26
4

It is 2022

ShadowDOM is styled by:

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
3

Non of the provided links work for me in Chrome 66 (as of 2018) so I ended up with this to customize custom element from outside:

<custom-element tabindex=10>
  <style>
    :host div {
      --color: red;
    }
  </style>
</custom-element>

class Element extends HTMLElement {
    constructor() {
        super();
        var shadow = this.attachShadow({mode: 'open'});

        var user_style = shadow.host.innerHTML.match(/<style>([\s\S]*?)<\/style>/);
        var style = document.createElement('style');
        style.innerHTML = `
            :host div {
                color: var(--color, #aaa);
             }
        ` + user_style ? user_style[1] : '';    

        shadow.appendChild(style);
        shadow.host.querySelector('style').remove();
    }
}

customElements.define(
  "custom-element",
  Element
) 
jcubic
  • 61,973
  • 54
  • 229
  • 402
2

Define styles in a base element and have all elements that need the style inherit from that base element.

With lit, something like this

export class AppComponentBase extends LitElement {
  static styles = css`
:host {
  font-family: sans-serif;
  font-size: 21px;
}
`;
}

And then in stead of inheriting from LitElement, make all components in your application inherit from AppComponentBase like this:


export class HomeRouteComponent extends AppComponentBase {

    render() {
        return html`
<h1>Home</h1>
<p>
    Welcome to my website
</p>
`;
    }
}

You can also add or some styles

export class HomeRouteComponent extends AppComponentBase {
    static styles = [super.styles, css`
h1 {
    color: red;
}
`]
    render() {
        return html`
<h1>Home</h1>
<p>
    Welcome to my website
</p>
`;
    }
}

Having a common component to inherit from may have other advantages. For instance to share some logic, although this might better be achieved via controllers.

This is all lit, but the same concept could be implemented with "bare" customElmements with relative ease.

Elmer
  • 9,147
  • 2
  • 48
  • 38
-3

You do it via ::shadow pseudo-element. Like this:

::shadow .redColor
{
    background-color: red;    
}

That will apply styling to all elements inside shadow trees with .redColor class.

More info + other styling possibilities in this great article: Shadow DOM 201

Amid
  • 21,508
  • 5
  • 57
  • 54
  • 4
    ::shadow was deprecated, Amid. – Marcelo Glasberg Mar 06 '16 at 23:15
  • I know. But for now it works and is a viable solution among others mentioned in the article i referenced. – Amid Mar 06 '16 at 23:28
  • It will be completely removed, so I guess no one should be using it. The article is ok, of course. – Marcelo Glasberg Mar 06 '16 at 23:31
  • 1
    Deprecation means time to get rid of it from projects. Browser vendors didn't do it to give you more time to be happy with old specs, but to give you time to drop it. Using deprecated specs in new projects is more than an anti pattern, if somebody did it in my team knowing it's deprecated, I would fire them the moment I notice that. – Dracco Dec 03 '18 at 20:16
  • **::shadow is deprecated:** https://developers.google.com/web/updates/2017/10/remove-shadow-piercing – Danny '365CSI' Engelman Jan 13 '19 at 09:53