如何阻止<div>标签干扰计数器?

Alb*_*lby 11 html css css-counter

在下面的代码中,我需要使用divHTML顶部的标记进行样式设置.如果没有div标签,hx标签的轮廓编号正确,但是div一切都完全错误.我需要这个来工作,像这样,但随着div在地点标签还在,我需要它为不同ID的div的工作.有任何想法吗?

body {counter-reset: h1}
h1 {counter-reset: h2}
h2 {counter-reset: h3}

h1:before {counter-increment: h1; content: counter(h1) ". "}
h2:before {counter-increment: h2; content: counter(h1) "." counter(h2) ". "}
h3:before {counter-increment: h3; content: counter(h1) "." counter(h2) "." counter(h3) ". "}
Run Code Online (Sandbox Code Playgroud)
<div class="varies">
    <h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
</div>
<p>Morbi efficitur nibh metus, a vehicula mauris tristique ac. Duis ornare metus eget iaculis hendrerit.</p>
  <h2>Morbi nisi lacus, ultricies sit amet turpis a, aliquet congue nulla.</h2>
        <p>Duis eget facilisis nisl.</p>
    <h3>Donec tincidunt purus quam, ut accumsan lorem hendrerit a.</h3>
      <p>Aenean in mattis quam.</p>
    <h3>Maecenas a nulla sit amet ligula facilisis tincidunt lacinia non enim.</h3>
      <p>Aliquam dignissim turpis placerat, facilisis magna et, venenatis purus.</p>
  <h2>Suspendisse tempus eu elit nec malesuada.</h2>
        <p>In ut sollicitudin nisi. Praesent non porttitor ante, molestie scelerisque mauris.</p>
  <h2>Vivamus eu turpis efficitur, ornare risus in, consectetur tellus.</h2>
        <p>Cras pellentesque orci eu placerat mollis.</p>      
<h1>Duis eu nulla et tellus porttitor auctor.</h1>
Run Code Online (Sandbox Code Playgroud)

Har*_*rry 10

可以通过查看W3C规范关于计数器的创建,范围和继承的说明来详细解释行为的原因.

计数器重置:计数器重置属性在元素上创建新计数器.

计数器的范围:计数器的范围从文档中具有该计数器的"计数器重置"的第一个元素开始.

计数器继承:计数器及其值可以单独继承,可能来自不同的元素.如果元素具有前一个兄弟,则它必须继承所有兄弟的计数器.否则,如果元素具有父元素,则它必须继承所有父元素的计数器.否则,元素必须具有一组空的计数器.然后,该元素以文档顺序从前一个元素继承计数器值.


为什么没有div的片段工作?

在工作片段(没有的片段div)中,会发生以下情况:

  • counter.h1(添加了一个区分元素的前缀)创建(或重置)at body,其初始值设置为0.
  • 所有元素继承其父母的柜台等每一个元素中body获取counter.h1.h1遇到第一个时,值counter.h1增加到1. h1遇到下一个时,它从前一个元素继承计数器值,然后递增到2.
  • counter.h2counter在h1元素处创建,值设置为0.此值对于兄弟姐妹是可见的,h1并且它们都可以继承它.
  • 在这个片段中,所有h2元素实际上都是元素的兄弟h1元素,因此每个h2元素都继承counter.h2了已经创建的元素,h1并且只增加了它的值.因此,h2遇到第一个时counter.h2会变为1,依此类推.
  • h2元素类似,元素也是h3元素h1h2元素的兄弟元素,因此它们也继承counter.h1counter.h2.这就是此样本中编号保持正确的原因.

body {counter-reset: h1}
h1 {counter-reset: h2}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1)". "}
h2:before {counter-increment: h2; content: counter(h1)"." counter(h2)". "}
h3:before {counter-increment: h3; content: counter(h1)"." counter(h2)"." counter(h3)". "}
Run Code Online (Sandbox Code Playgroud)
<!-- body creates counter.h1 and set to 0 -->
<h1>Heading 1 <!-- Inherits counter.h1 from parent, creates counter.h2 and set to 0 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h1 to 1 and displays value -->
</h1>
<p>Paragraph</p>
<h2>Heading 2 <!-- Inherits counter.h1, counter.h2 from sibling, creates counter.h3 and set to 0 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h2 to 1 and displays value -->
</h2>
<p>Paragraph</p>
<h3>Heading 3 <!-- Inherits counter.h1, counter.h2, counter.h3 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h3 to 1 and displays value -->
</h3>
<p>Paragraph</p>
<h3>2nd Heading 3 <!-- Inherits counter.h1, counter.h2, counter.h3 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h3 to 2 and displays value -->  
</h3>
<p>Paragraph</p>
<h2>2nd Heading 2 <!-- Inherits counter.h1, counter.h2, counter.h3, resets counter.h3 to 0 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h2 to 2 and displays value -->
</h2>
<p>Paragraph</p>
<h2>3rd Heading 2 <!-- Inherits counter.h1, counter.h2, counter.h3, resets counter.h3 to 0 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h2 to 3 and displays value -->
</h2>
<p>Paragraph</p>
<h1>2nd Heading 1 <!-- Inherits counter.h1, counter.h2, counter.h3, resets counter.h2 to 0 -->
  <!-- ::before being a child inherits all counters from parent, increments counter.h1 to 2 and displays value -->
</h1>
Run Code Online (Sandbox Code Playgroud)


为什么带div的片段不起作用?

现在让我们来看看不起作用的片段(h1a中存在的片段div).

  • 在这里,h1创建,counter.h2但这只能由h1(其中没有)的兄弟姐妹继承.
  • Whenever a h2 element is encountered, UA tries to increment value of counter.h2 within the :before selector. But here the h2 parent does not inherit counter.h2 and hence h2:before doesn't either. Because of this h2:before will create its own counter.h2 and increment to 1.
  • Subsequent h2 elements also cannot inherit counter.h2 because the counter is created by h2:before (which is a child of h2). Because of this, each time a h2 is encountered a new counter is created within its :before and incremented. This is why all h2 show up as 1.1.
  • Similarly, none of the h3 elements know about counter.h2 and they don't increment it either and this is why they show up as 1.0.x.
  • However, they all can inherit counter.h3 because it was created by h2 element which is a sibling of all h3 elements. This is why counter.h3 gets incremented properly.

body {counter-reset: h1}
h1 {counter-reset: h2}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1)". "}
h2:before {counter-increment: h2; content: counter(h1)"." counter(h2)". "}
h3:before {counter-increment: h3; content: counter(h1)"." counter(h2)"." counter(h3)". "}
Run Code Online (Sandbox Code Playgroud)
<!-- body creates counter.h1, sets it to 0 -->
<div class="test"> <!-- Inherits counter.h1 from parent -->
  <h1>Heading 1 <!-- Again inherits counter.h1 from parent, creates counter.h2 -->
    <!-- ::before increments counter.h1 to 1 and display value-->
  </h1>
</div>
<p>Paragraph</p>
<h2>Heading 2 <!-- Inherits counter.h1 as it is from parent but not counter.h2, creates counter.h3 -->
  <!-- ::before has no counter.h2, so creates a counter.h2 and increments to 1 -->
</h2>
<p>Paragraph</p>
<h3>Heading 3 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2 -->
  <!-- ::before inherits counter.h3 from parent and increments to 1, has no counter.h2 so creates a new counter.h2 and sets to 0 -->
</h3>
<p>Paragraph</p>
<h3>2nd Heading 3 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2 -->
  <!-- ::before inherits counter.h3 from parent and increments to 2, has no counter.h2 so creates a new counter.h2 and sets to 0 -->
</h3>
<p>Paragraph</p>
<h2>2nd Heading 2 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2, resets counter.h3 to 0 -->
  <!-- ::before has no counter.h2, so creates a counter.h2 and increments to 1 -->
</h2>
<p>Paragraph</p>
<h2>3rd Heading 2 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2, resets counter.h3 to 0 -->
  <!-- ::before has no counter.h2, so creates a counter.h2 and increments to 1 -->
</h2>
<p>Paragraph</p>
<h1>2nd Heading 1 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2, resets counter.h2 to 0 -->
  <!-- ::before inherits counter.h1 from parent and increments to 2 -->
</h1>
Run Code Online (Sandbox Code Playgroud)


What is the solution?

Ideal solution to this problem would be to reset all 3 counters first at body itself so that all elements are aware of the existence of a counter and can inherit or use its value.

body {counter-reset: h1 h2 h3}
h1 {counter-reset: h2 h3}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1)". "}
h2:before {counter-increment: h2; content: counter(h1)"." counter(h2)". "}
h3:before {counter-increment: h3; content: counter(h1)"." counter(h2)"." counter(h3)". "}
Run Code Online (Sandbox Code Playgroud)
<!-- body creates counter.h1, counter.h2, counter.h3 sets all 0 -->
<div class="test"> <!-- Inherits all 3 counters -->
  <h1>Heading 1 <!-- Inherits all 3 counters, resets counter.h2 and counter.h3 to 0 -->
    <!-- ::before also inherits all 3 counters, increments counter.h1 to 1 and displays value -->
  </h1>
</div>
<p>Paragraph</p>
<h2>Heading 2 <!-- Inherits all 3 counters, resets counter.h3 to 0 -->
  <!-- ::before also inherits all 3 counters, increments counter.h2 to 1 and displays value -->
</h2>
<p>Paragraph</p>
<h3>Heading 3 <!-- Inherits all 3 counters -->
  <!-- ::before also inherits all 3 counters, increments counter.h3 to 1 and displays value -->
</h3>
<p>Paragraph</p>
<h3>2nd Heading 3 <!-- Inherits all 3 counters -->
  <!-- ::before also inherits all 3 counters, increments counter.h3 to 2 and displays value -->
</h3>
<p>Paragraph</p>
<h2>2nd Heading 2 <!-- Inherits all 3 counters, resets counter.h3 to 0 -->
  <!-- ::before also inherits all 3 counters, increments counter.h2 to 2, resets counter.h3 to 0 and displays value -->
</h2>
<p>Paragraph</p>
<h2>3rd Heading 2 <!-- Inherits all 3 counters, resets counter.h3 to 0 -->
  <!-- ::before also inherits all 3 counters, increments counter.h2 to 3, resets counter.h3 to 0 and displays value -->
</h2>
<p>Paragraph</p>
<h1>2nd Heading 1 <!-- Inherits all 3 counters, resets counter.h2 and counter.h3 to 0 -->
  <!-- ::before also inherits all 3 counters, increments counter.h1 to 2, resets counter.h2, counter.h3 to 0 and displays value -->
</h1>
Run Code Online (Sandbox Code Playgroud)


And*_*dry 5

考虑一下(非常类似于你的结构,只是更简单):

body {
  counter-reset: h1;
}

h1:before { 
  content: counter(h1) ". ";
  counter-increment: h1;
}
h1 {
  counter-reset: h2;
}

h2:before {
  content: counter(h1) "." counter(h2) ". ";
  counter-increment: h2;
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <h1>Heading first level 1</h1>
</div>
  <h2>Heading second level 1</h2>
  <h2>Heading second level 2</h2>
  <h2>Heading second level 3</h2>
  <h2>Heading second level 4</h2>
  <h2>Heading second level 5</h2>    
<h1>Heading first level 2</h1>
  <h2>Test</h2>
  <h2>Test</h2>
  <h2>Test</h2>
<h1>Heading first level 3</h1>
<h1>Heading first level 4</h1>
Run Code Online (Sandbox Code Playgroud)

为什么你的布局不起作用

通过推荐:

计数器是"自嵌套"的,因为重置后代元素或伪元素中的计数器会自动创建计数器的新实例.这对于像HTML中的列表这样的情况很重要,其中元素可以嵌套在任意深度内.

布局中的问题是第一个<h1>内部<div>初始化一个单独的h1计数器实例.这是因为计数器对嵌套元素很敏感.每次重置一个不同级别的计数器时,这不会影响另一个级别的同一个计数器实例!

怎么了

以下是发生的事情:

01. <body>                             | h1 = *
02. <div>                              |
03.   <h1>Heading first level 1</h1>   | h1 = 1 |  div-h2 = *
04. </div>                             |
05.   <h2>Heading second level 1</h2>  |        | h2 = 1
06.   <h2>Heading second level 2</h2>  |        | h2 = 1
07.   <h2>Heading second level 3</h2>  |        | h2 = 1
08.   <h2>Heading second level 4</h2>  |        | h2 = 1
09.   <h2>Heading second level 5</h2>  |        | h2 = 1
10. <h1>Heading first level 2</h1>     | h1 = 2 | h2 = *
11.   <h2>Test</h2>                    |        | h2 = 1
12.   <h2>Test</h2>                    |        | h2 = 2
13.   <h2>Test</h2>                    |        | h2 = 3
14. <h1>Heading first level 3</h1>     | h1 = 3
15. <h1>Heading first level 4</h1>     | h1 = 4
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,在01.我们重置计数器h1工作正常.但是在h1元素中我们重置计数器h2.

发生问题03.,我们计数器复位h2嵌套层次div,澄清这一点,我把这个计数器:div-h2.事实上,未来h2从元素05.09.正在使用的不同的计数器没有被重置!这是反制h2(没有嵌套),即使他们试图增加它,也没有什么可以增加,因为重置是强制性的!

10.我们没有div嵌套,从而计数器h2是正确复位,从而增加为好.

该怎么办

在您的情况下,您必须避免生成页面中不同类的嵌套结构.这是一个建议有一个干净的HTML,在你的情况下,如果你真的需要保持该div,只需添加一个div选择器重置计数器h2:

div {
  counter-reset: h2;
}
Run Code Online (Sandbox Code Playgroud)

所以这是最后的工作片段:

body {
  counter-reset: h1;
}

h1:before { 
  content: counter(h1) ". ";
  counter-increment: h1;
}
h1 {
  counter-reset: h2;
}

div {
  counter-reset: h2;
}

h2:before {
  content: counter(h1) "." counter(h2) ". ";
  counter-increment: h2;
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <h1>Heading first level 1</h1>
</div>
  <h2>Heading second level 1</h2>
  <h2>Heading second level 2</h2>
  <h2>Heading second level 3</h2>
  <h2>Heading second level 4</h2>
  <h2>Heading second level 5</h2>    
<h1>Heading first level 2</h1>
  <h2>Test</h2>
  <h2>Test</h2>
  <h2>Test</h2>
<div>
  <h1>Heading first level 1</h1>
</div>
  <h2>Test</h2>
  <h2>Test</h2>
  <h2>Test</h2>
<h1>Heading first level 3</h1>
<h1>Heading first level 4</h1>
Run Code Online (Sandbox Code Playgroud)

上面的解决方案是有效的,如果你只有那些div嵌套h1,如果你希望有其他标题元素包装成divs,你需要重置h3计数器!但我不推荐这个,因为它是一个非常混乱的CSS安排:难以维护,不易遵循.

记住在CSS中总有一种方法可以实现,你说你需要它div,但我认为你没有尝试所有可能性来摆脱它.