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

时间:2015-07-27 16:11:42

标签: html css css-counter

在下面的代码中,我需要使用HTML顶部的div标记进行样式设置。如果没有div标记,则hx标记的大纲编号正确,但如果div到位,则一切都完全错误。我需要thisthis一样工作,但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) ". "}
<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>

2 个答案:

答案 0 :(得分:9)

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

  

计数器重置: counter-reset属性在元素上创建新计数器。

     

计数器的范围:计数器的范围从文档中对该计数器进行“计数器重置”的第一个元素开始。

     

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

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

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

  • counter.h1(添加了一个区别于元素的前缀)在body创建(或重置),其初始值设置为0.
  • 所有元素都会继承其父级的计数器,因此body中的每个元素都会获得counter.h1。遇到第一个h1时,counter.h1的值会增加到1.当遇到下一个h1时,它会从前一个元素继承计数器值,然后递增到2. / LI>
  • counter.h2计数器在h1元素处创建,值设置为0.此值对h1的兄弟可见,并且它们都可以继承它。
  • 在此代码段中,所有h2元素实际上都是h1元素的兄弟元素,因此每个h2元素都会继承已在{{1}创建的counter.h2元素并且只增加其值。因此,当遇到第一个h1时,h2变为1,依此类推。
  • counter.h2元素类似,h2元素也是h3h1元素的兄弟元素,因此它们也继承h2和{{ 1}}。这就是此样本中编号保持正确的原因。

counter.h1
counter.h2

为什么带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)". "}中存在<!-- 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>的片段。)

  • 此处h1创建div,但这只能由h1的兄弟姐妹(其中没有)继承。
  • 每当遇到counter.h2元素时,UA会尝试在h1选择器中增加h2的值。但是counter.h2父级不会继承:before,因此h2也不会。因此counter.h2将创建自己的h2:before并增加到1.
  • 后续的h2:before元素也无法继承counter.h2,因为计数器是由h2counter.h2的子项)创建的。因此,每次遇到h2:before时,都会在其h2内创建一个新计数器并递增。这就是为什么所有h2都显示为 1.1 的原因。
  • 同样,:before个元素都不知道h2,也不会增加它们,这就是为什么它们显示为 1.0.x 的原因。
  • 但是,它们都可以继承h3,因为它是counter.h2元素创建的,它是所有counter.h3元素的兄弟。这就是h2正确递增的原因。

h3
counter.h3

解决方案是什么?

这个问题的理想解决方案是首先在主体本身重置所有3个计数器,以便所有元素都知道计数器的存在并且可以继承或使用它的值。

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)". "}
<!-- 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>

答案 1 :(得分:5)

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

&#13;
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13;

为什么你的布局不起作用

通过推荐:

  

计数器是&#34;自我嵌套&#34;,在重置计数器的意义上   后代元素或伪元素自动创建一个新元素   柜台的实例。这对于列表等情况很重要   在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

正如您所见,在01.我们重置了正常工作的h1计数器。但是,在h1元素中,我们会重置计数器h2

03.问题出现在我们重置嵌套级别h2中的计数器div的情况下,为了澄清这一点,我称之为计数器:div-h2。事实上,h205.的下一个09.元素正在使用另一个尚未重置的计数器!这是计数器h2(没有嵌套),即使他们试图递增它,也没有什么可以增加,因为重置是强制性的!

10.中,我们没有div嵌套,因此计数器h2被正确重置,因此也会增加。

怎么做

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

div {
  counter-reset: h2;
}

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

&#13;
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13;

如果您只为div设置了h1嵌套,以防您希望将其他标题元素包含在div中,那么上面的解决方案就有效了,而不是需要重置h3 1}}也在那里反击!但我不推荐这个,因为它是一个非常混乱的CSS安排:难以维护,不易遵循。

请记住,在CSS中始终有一种实现目标的方法,你说你需要div,但我认为你并没有尝试所有可能来摆脱它。