Matthew James Taylor Matthew James Taylor

Web design ›

Style Blocker: How To Prevent CSS Cascade With Shadow DOM

23 Feb 2022

Superman blocking styles

Table of contents

I was recently working on my responsive columns layout system when I encountered a problem.

I wanted to include a demo layout within an article, but I didn't want any of my normal website styles to affect the layout.

Essentially, I wanted to isolate my layout so it was completely unaware of the surrounding page CSS. This meant everything... font family, link colors, heading sizes, EVERYTHING!

How was I going to do that?

My first thought was to use an iframe, but that seemed too messy.

An iframe requires a separate page for the layout which is not good for SEO:

I wanted to avoid both of these issues.

An iframe was not the answer.

So I did a bit of research and that lead me to the dark side... the shadow DOM.

I've looked at the shadow DOM before for other things and it always felt a bit too complicated for my needs, but for blocking styles... it seemed PERFECT!

After a bit of experimentation, I came up with the following solution.

Style-Blocker: A Custom Element To Isolate CSS

The first thing I did was to create a custom HTML element <style-blocker> that I could use as an isolation barrier to block CSS.

I then placed my layout inside the <style-blocker> element like this.

<style-blocker>
    <!-- layout html here -->
</style-blocker>

At this point, nothing has changed. The surrounding page styles still leak into my layout. This is because even though my layout is inside the <style-blocker> element, it's not inside its shadow DOM.

To fix this, we need to complete the following steps with javascript:

  1. Register the <style-blocker> custom element.
  2. Create a shadow root on <style-blocker>.
  3. Move all descendent elements of <style-blocker> into its shadow root.

I included a script element on the page below my layout, and wrote the following javascript to complete the above steps:

<script>
class StyleBlocker extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
    }
    connectedCallback() {
        while (this.childNodes.length > 0) {
            this.shadowRoot.appendChild(this.childNodes[0]);
        }
    }
}
window.customElements.define('style-blocker', StyleBlocker);
</script>

Note: If you include whitespace between the opening <style-blocker> element and the first element inside, or likewise, between the last element inside and the closing </style-blocker> then the script will copy this whitespace across into the shadow DOM too. To prevent this, just remove leading and trailing whitespace.

Success!

My layout is now completely isolated from the surrounding page styles! =)

The best thing about this approach is it's SEO-friendly.

Google will index the complete page including the layout because everything is included in the original HTML source of the page.

Even if Google decides to execute javascript on the page, it will still know about the layout inside the shadow DOM and so it should still be indexed.

I was very happy with this solution.

However.

I had another issue.

My layout requires some styles for it to work, so how do I pass the specific styles I need into the shadow DOM?

How To Pass Styles Into A Shadow DOM

To add styles to a shadow DOM, insert a link element that points to an external stylesheet file, here are the steps:

  1. Create a <link> element.
  2. Set the href attribute to the CSS filename.
  3. Set the rel attribute to 'stylesheet' so the browser knows it's for CSS rules.
  4. Append the <link> element to the shadow DOM.

Rather than hardcode the stylesheet filename in my javascript, I decided to add a css-files attribute to my <style-blocker> element so I can easily pass in optional CSS files.

To make things super-flexible I allow for a comma-separated list of files just in case I need to pass in more than one.

Here's the HTML showing the extra attribute on style-blocker:

<style-blocker css-files="/css/layout.css">
    <!-- layout html here -->
</style-blocker>

Here's the completed javascript including CSS injection:

<script>
class StyleBlocker extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
    }
    connectedCallback() {
        while (this.childNodes.length > 0) {
            this.shadowRoot.appendChild(this.childNodes[0]);
        }

        const cssFiles = this.getAttribute('css-files');
        if (cssFiles) {
            const arrCssFiles = cssFiles.split(',');
            for(let i = 0; i < arrCssFiles.length; i++){
                let link = document.createElement('link');
                link.setAttribute('rel', 'stylesheet');
                link.setAttribute('href', arrCssFiles[i]);
                this.shadowRoot.appendChild(link);
            }
        }
    }
}
window.customElements.define('style-blocker', StyleBlocker);
</script>

Now I can easily isolate parts of my page from the surrounding page styles and inject alternate stylesheets.

A perfect solution that's easy to do!

Shadow DOM vs Iframe

There are some important differences between shadow DOMs and iframes that I want to point out.

Iframes:

Shadow DOM:

Summary

The shadow DOM makes it easy to block surrounding page styles from cascading into specific elements. Injecting styles into a shadow DOM is easy too. The methods I've described above are also SEO friendly so there is no danger of Google not indexing important parts of your page.

Want a live demo of style-blocker? Check out my article: Holy grail 3-column responsive layout, the demo layout near the top of the page is in a shadow DOM.

Overall, I'm impressed with what the shadow DOM can do so I will be experimenting with it further.

Matthew James Taylor

“I've been developing websites professionally for over two decades and running this site since 1997! During this time I've found many amazing tools and services that I cannot live without.”
— Matthew James Taylor

I highly Recommend:

Ezoic

Ezoic — Best ad network for publishers

Earn more than double the revenue of Google Adsense. It's easy to set up and there's no minimum traffic requirements.

Learn more

SiteGround

SiteGround — Best Website Hosting

Professional Wordpress hosting with 24/7 customer support that is the best in the industry, hands down!

Learn more

Surfer SEO

Surfer SEO — Best Content Optimization Tool

Use the power of AI to optimise your website content and increase article rankings on Google.

Learn more

Canva

Canva — Best Graphic Design Software

Create professional graphics and social media imagery with an intuitive online interface.

Learn more

See more of my recommended dev tools.

Responsive Columns Layout System

Responsive Columns: Build Amazing Layouts With Custom HTML Tags

How responsive attributes work

Responsive Attributes: Generate CSS Grid Layouts With Simple HTML

Responsive text size

Responsive Font Size (Optimal Text at Every Breakpoint)

A web developer in the engine room

Best Web Development Tools (Free & Paid)

Columns all the same height

Equal-Height Columns (CSS Grid, Flexbox, Floated Containers, & Table Methods)

Boggle dice shaker

Boggle Dice Shaker (Built With Javascript)

Padding bewteen desktop, tablet, and mobile

Responsive Padding, Margin & Gutters With CSS Calc

Holy grail 3 column layout responsive diagram

Holy Grail 3-Column Responsive Layout (CSS Grid & Flexbox Versions)

Footer at the bottom of the page diagram

Bottom Footer (CSS Grid, Flexbox, & Absolute Position Methods)

3 column product comparison layout

3 Column Layouts (Responsive, Flexbox & CSS Grid)

Open book two column layout

2 Column Layouts (Responsive, Flexbox & CSS Grid)

Is CSS margin top or bottom better?

CSS: Margin Top vs Bottom (A Trick You Should Know)

How to add CSS to HTML

How to add CSS to HTML (With Link, Embed, Import, and Inline styles)

Custom elements plus CSS with no javascript

Custom Element Examples (Without Javascript)

A delicious soup made from custom elements

Replace Divs With Custom Elements For Superior Markup

Racing car made from custom tags

Custom HTML Tags (18 Things To Know Before Using Them)

ID vs Class CSS selectors

ID vs Class: Which CSS Selector Should You Use? (6 Examples)

Looking into an empty div

Empty HTML Tags (21 Weird Things You Need To Know!)

Beautiful centered menus with CSS

CSS: Horizontally Centred Menus (With Optional Dropdowns)

Ads that can change size to fit any screen size

Responsive Banner Ads with HTML5 and CSS3

Responsive house plan

Responsive House Plan (Web Design Meets Architecture!)

Web design Web design Architecture Architecture Life drawing Life drawing Art gallery Art gallery Synesthesia Synesthesia Comics Comics

About Contact Privacy

© 1994 — 2024 Matthew James Taylor