【问题标题】:How To Isolate a div from public CSS styles?如何从公共 CSS 样式中隔离 div?
【发布时间】:2012-04-08 15:58:36
【问题描述】:

我有一些代码,例如在 html 中

<html>
 <body>
  <img src='an image source'/>
  <h1>Hi it's test</h1>
  <div id='mydiv'>
    <img src='an image source'/>
    <h1>Hi it's test</h1>
  </div>
 </body>
</html>

如果我使用以下 CSS 代码对其进行样式设置:

img{
   width:100px;
   height:100px;
}
h1{
   font-size:26px;
   color:red;
}

问题是:如何防止和隔离 mydiv div 标签内的标签与公共标签样式的样式?

【问题讨论】:

    标签: html css


    【解决方案1】:

    CSS Cascading and Inheritance Level 3 引入了the all shorthand propertythe unset keyword,它们一起可以让您方便地实现这一目标。

    例如,如果作者在元素上指定all: initial,它将 阻止所有继承并重置所有属性,就像没有规则一样 出现在级联的作者、用户或用户代理级别。

    这对于包含在 页面,它不希望继承外部页面的样式。 但是请注意,应用于该元素的任何“默认”样式(例如 例如,例如display: block 来自块元素的 UA 样式表,例如 因为&lt;div&gt;) 也会被吹走。

    您需要将 all: initial 应用于您的 div 并将 all: unset 应用于其后代:

    #mydiv {
      all: initial; /* blocking inheritance for all properties */
    }
    #mydiv * {
      all: unset; /* allowing inheritance within #mydiv */
    }
    

    您可能希望在您的 div 上使用一个类而不是一个 id,这样您编写的任何为其后代设置样式的规则都不必匹配或超过此规则中使用的高特异性。

    为了安全起见,您可能还想阻止潜在伪元素后代的样式:

    #mydiv::before,
    #mydiv::after,
    #mydiv *::before,
    #mydiv *::after {
      all: unset;
    }
    

    或者,为了更广泛的浏览器支持,您可以手动尝试通过设置所有已知的 CSS 属性来执行 all 所做的事情(不要忘记前缀版本):

    #mydiv {
      /*
       * using initial for all properties
       * to totally block inheritance
       */
      align-content: initial;
      align-items: initial;
      align-self: initial;
      alignment-baseline: initial;
      animation: initial;
      backface-visibility: initial;
      background: initial;
      ...
    }
    
    #mydiv::before,
    #mydiv::after,
    #mydiv *,
    #mydiv *::before,
    #mydiv *::after {
      /*
       * using inherit for normally heritable properties,
       * and initial for the others, as unset does
       */
      align-content: initial;
      align-items: initial;
      align-self: initial;
      ...
      color: inherit;
      ...
    }
    

    您可以鼓励浏览器支持all 速记属性,并通过以下问题链接跟踪其采用情况:

    all 速记属性的最新浏览器支持信息可在here 获得。

    【讨论】:

    • 请注意,使用这种技术,:hover 之类的伪类似乎并未取消设置。你不能阻止这样的事情影响你的组件:button:hover { background-color: gray; }
    • @ThomasL'huillier 那是不正确的:选择器#mydiv * 的规则比button:hover 规则击败(具有更高的特异性)。如果您没有看到这一点,那么您的阻塞规则可能使用了比上面推荐的更低特异性的选择器(可能是.mydiv * 而不是#mydiv *?)。如果使用 ID 选择器对您来说不是一个可行的选择,您可以根据需要多次重复您的类选择器,以确保您的页面具有一定的优势:.mydiv.mydiv.mydiv.mydiv *。希望这会有所帮助。
    • @Zardo,请参阅以“或者,为了更广泛的浏览器支持...”开头的段落。该技术适用于 IE/Edge。
    • 另外需要注意的是,如果在父层次结构中的任何位置都存在!important,那么all 属性将无济于事。
    • 我尝试使用all: initial,但它有一些奇怪的副作用。 #mydiv 中的所有 div 将具有 displayinline(而不是人们可能期望的 block),除非它被显式覆盖。这似乎是expected behavior
    【解决方案2】:

    老问题,但自从接受答案以来,情况发生了一些变化。现在有一个名为 revert 的 CSSWG 推荐关键字,它比 initialunset 更适合解决这个问题,因为它将属性重置为它们在 user agent stylesheet 中定义的内容,而不是他们的initial 值(不考虑它们使用的元素)。例如,对于revert#mydiv 内部的div 将按照我们的预期将其显示设置为block,而不是inlinedisplay 的初始值)。

    你必须这样做:

    #mydiv,
    #mydiv::before,
    #mydiv::after,
    #mydiv *
    #mydiv *::before,
    #mydiv *::after {
      all: revert;
    }
    

    在撰写本文时,revert is supported in Edge, Firefox, Chrome, and Safari,但不是 IE 或 Opera。

    对于已接受的答案,还有其他需要考虑的因素。如果您想在#mydiv 中设置任何样式,则需要使用至少与您用来取消设置或还原所有内容的选择器一样具体的选择器,否则它将被该规则覆盖,即使它出现在之后它在 CSS 中。

    所以你需要做这样的事情(注意#mydiv,它提升了规则的specificity):

    #mydiv p {
      margin-top: 20px;
    }
    
    #mydiv .bg-black {
      background-color: black;
    }
    
    // etc.
    

    【讨论】:

    • 这将是最好的解决方案,一旦可用。 Firefox 现在正在考虑草稿补丁。您可以对该功能进行投票。
    • 答案写得非常好。
    【解决方案3】:

    从技术上讲,你不能,这就是 CSS 的工作方式。如果定义了任何样式 样式表中的 div 标记,它将应用于所有 div 元素。

    您可以尝试的几件事是不要使用标记名称设置样式 而是提供类名称并为类提供样式声明。这样您就可以确定所有样式的去向。

    或。如果您希望某些特定的 Div 标签没有样式而其他 Div 有。你可以随时重置它,给它一些不同的类名或 id 并重置样式声明

    【讨论】:

      【解决方案4】:

      如果不使其他业务逻辑复杂化,iframe 也是一种不错的样式隔离解决方案。此外,这可以在纯 JavaScript 中完成,也可以在旧版浏览器中使用。

      const HTMLToIsolate = `...` // get your div tag as HTML string
      const parentContainerRef = document.body; // or something else
      const newIframe = document.createElement('iframe');
      // set height & width to 100% and remove borders for newIframe
      
      parentContainerRef.appendChild(newIframe)
      newIframe.contentWindow.document.open('text/html', 'replace');
      newIframe.contentWindow.document.write(HTMLToIsolate);
      newIframe.contentWindow.document.close();
      
      // bonus to remove scroll bars by setting proper iframe's height
      newIframe.addEventListener('load', function onIFrameLoad(e) {
          const iframeBody = this.contentDocument.querySelector("body");
          this.style.height = `${iframeBody.scrollHeight}px`;
      });
      

      当我必须将一个复杂的 HTML 文件嵌入到我的网页中时,这对我来说非常有效,该文件是在没有MixedContent 警告且没有覆盖嵌入 HTML 的父 HTML 样式的情况下远程获取的。感谢https://benfrain.com/sandbox-local-htmlcss-code-snippets-inside-iframe-style-guidespattern-libraries/ 提出这个绝妙的主意!

      尽管#mydiv * { all: unset } CSS 技巧,正如公认的解决方案here 中所建议的那样有效,但它最终成为一个复杂的浏览器操作,因为我的页面上有许多 DOM 节点。

      【讨论】:

        【解决方案5】:

        CSS 直接子选择器 可能会有所帮助,它在包括 IE7+ 在内的所有浏览器中都可用。这使您可以应用不会级联到子级的样式。例如,在您的代码中,您可以使用以下 CSS:

        body > img {
          width:100px;
          height:100px;
        }
        body > h1 {
          font-size:26px;
          color:red;
        }
        

        而且该 CSS 仅适用于直接在 BODY 元素上的元素。

        【讨论】:

        • 很好,如果在示例中使用 OP 的
          标签而不是 ,答案可能会有所改善。例如。 #mydiv > img { ...} #mydiv > h1 {...}
        猜你喜欢
        • 2012-07-13
        • 2019-04-09
        • 2021-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-09
        • 1970-01-01
        相关资源
        最近更新 更多