skip to Main Content

I have some sitewide styles and some custom styles, and I want the site wide styles to not apply to the div with id custom-styles or any of its containing elements. How can this be achieved without having to change the CSS in the site wide styles?

I’ve tried adding style="all: unset;" to the div (i.e. #custom-styles, #custom-styles * {all: unset}), but to no avail. Ideally I’d like any styles inside the custom styles div to not inherit any styles from anywhere in case they mess anything up.

To give some context, users need to be able to add their own CSS, and it along with some custom HTML will be inserted on their websites, hence I don’t want any of their website styles to affect the styles of the custom HTML. I can to some extent control the custom HTML, e.g. by wrapping their custom HTML inside my own div with an id or class that I can add my own styles to.

<style>
/* sitewide styles */
*,
::before,
::after {
    margin: 0.5em;
    padding: 0.5em;
    border: none;
    box-sizing: inherit;
    font-family: 'Arial';
}
p {color: red !important}
</style>
<p>
This should be red with all the default styles
</p>
<div id='custom-styles' style="all: unset;">
<style>
/* custom styles for this div only */
p {color: green;}
</style>
<p>
I want this (and any other element within this div) to not be red and not have any default styles - it should only have the styles inside the second style tag (and, for example, be green)
</p>
</div>

2

Answers


  1. I recommend avoiding inlining styles in this manner.

    The all: unset rule does not affect inherited properties unless they are explicitly reset.

    I would also use a class for this, not an ID. This way it’s more portable.

    /* Global styles */
    *, *::before, *::after {
      margin: 0.5em;
      padding: 0.5em;
      border: none;
      box-sizing: inherit;
      font-family: 'sans-serif';
      background: #222;
    }
    
    p {
      color: red !important;
    }
    
    /* Reset and customize styles within #custom-styles */
    .custom-styles, .custom-styles * {
      all: unset;
      color: green !important;   /* Override global red (important)  */
      background: initial;       /* Reset background to default      */
      font-family: initial;      /* Revert to browser's default font */
    }
    <p>
      This should be red with all the default styles
    </p>
    <div class="custom-styles">
      <p>
        I want this (and any other element within this div) to not be red and not have any default styles - it should only have the styles inside the second style tag (and, for example, be green)
      </p>
    </div>

    If you want to be less destructive, I recommend only using important when you can’t control the specificity like in the case where the global <p> color is forced to be red.

    .custom-styles {
      color: green;             /* Itself and any of its children */
    }
    
    .custom-styles p {
      color: green !important;  /* Force only for <p> elements
    }
    
    Login or Signup to reply.
  2. If you want a particular element and it’s content to ignore all CSS declared on the page, try using the shadow DOM. All elements within the shadow DOM are only affected by CSS declared within the shadow DOM. There is an exception concerning inherited styles from CSS declared within the regular DOM, (see comments in the HTML marked with a ❉ for the solution).

    The example below uses a <template> to populate the shadow DOM and declare CSS within the shadow DOM. Details are commented in the example.

    /** ✢
     * Reference the host element (aka section.shadow-host).
     * A host element is any element that is part of the regular DOM.
     * The shadow DOM will be attached to it.
     */
    const shadowHost = document.querySelector(".shadow-host");
    
    /**
     * Attach the shadow DOM to the shadow Host (aka section.shadow-host).
     * Assign "open" to it's [mode] property so that the shadow DOM
     * is accessible by JavaScript.
     */
    const shadowDOM = shadowHost.attachShadow({
      mode: "open"
    });
    
    /** ✻
     * Reference the <template> (aka template.shadow-HTML).
     * A <template> isn't rendered but it's content can be cloned and 
     * rendered in regular and/or shadow DOM by way of JavaScript 
     * (see next line).
     */
    const shadowHTML = document.querySelector(".shadow-HTML");
    
    /**
     * Clone the content of template.shadow-HTML and attach it to the
     * shadow DOM.
     * Now the shadow DOM has a shadow tree consisting of the 
     * <style> and <p> that was in template.shadowHTML.
     */
    shadowDOM.appendChild(shadowHTML.content);
    /**
     * These styles affect all elements within the regular DOM.
     */
    :root {
      font: 2.5ch/1.5 "Segoe UI";
    }
    
    p {
      color: red;
    }
    <p>font-size: 2.5ch; line-height: 3.75ch; font-family: "Segoe UI"; color: red;</p>
    
    <!-- 
      See comments marked with a ✢ in the JavaScript for details 
      concerning the <section> element.
    -->
    <section class="shadow-host"></section>
    
    <p>font-size: 2.5ch; line-height: 3.75ch; font-family: "Segoe UI"; color: red;</p>
    
    <!-- 
      See comments marked with a ✻ in the JavaScript for details
      concerning the <template> element.
    -->
    <template class="shadow-HTML">
    
      <style>
        /** ❉
         * Shadow DOM ignores regular DOM styles with one exception:
         * Elements within the shadow DOM still inherit styles
         * from the regular DOM.
         * The following style ruleset will prevent that from
         * happening.
         * Meaning:
         *   Anything NOT a <style> reset all properties back to 
         *   their original browser defaults.
         */
        *:not(style) { all: initial }
        p { color: green; }
      </style>
      
      <p>font-size: 16px; font-family: "Times New Roman"; line-height: normal; color: green;</p>
      
    </template>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search