文本节点后第一个块的边距(垂直空间)?

时间:2017-07-26 21:33:15

标签: html css

第一个问题:

<dd><td><li>之类的区域内,我是否正确地说下列其中一项或两项都是正常且正确的?

<td>
  An introductory sentence as a text node.
  <p>A further sentence as a paragraph.</p>
</td>

和/或:

<td>
  <p>An introductory sentence as a paragraph.</p>
  <p>A further sentence as a paragraph.</p>
</td>

第二个问题:

假设是这样的话,我可以使用什么CSS来确保在两种情况下两个句子之间有差距,而不是在第一句话之前?

我的问题是,如果我做某事......

td > p { margin-top: 1em; }

...当第一个句子是文本节点时,这可以正常工作,但当第一个句子在段落中时,它会在第一个句子和包含<td>之间留下不需要的边距。

我希望解决方案即使在第一个句子包含内联元素时也能正常工作,例如<strong><a href="...">

总之,CSS应该为两个HTML示例的两个生成相同的布局,如下所示:

-- top of <td> here
-- no margin here
-- first sentence here (whether it's a text node and/or inside a <p>)
-- margin here, between the two sentences
-- second sentence here inside a <p>

第三个问题:

如果确实无法定义为两种HTML创建相同格式的CSS规则,那么我想网站作者必须小心,始终只使用一个HTML标记?

如果是这样,你认为这是正常的吗?

  • 永远不要使用其他块启动块,始终使用文本节点启动(然后您可以使用CSS规则,即第一个块应该有margin-top );例如,执行此操作:

    <td>
      An introductory sentence as a text node.
      <p>A further sentence as a paragraph.</p>
    </td>
    

    这不起作用,例如,如果块中的第一件事是列表 - 列表会有不需要的margin-top

    <td>
      <ul>
        <li>List item</li>
        <li>List item</li>
      </ul>
    </td>
    
  • 永远不要使用文本节点启动块,始终使用块启动它(然后您可以使用CSS规则,该规则指出第一个块不应具有{{1 }});例如,执行此操作:

    margin-top

    这比我预期的标记更多。我想我习惯看到<td> <p>An introductory sentence as a paragraph.</p> <p>A further sentence as a paragraph.</p> </td> 而不是<li>List item</li>

  • 这样的标记
  • 请勿标准化,使用其中之一,但必要时会向块添加额外的<li><p>List item</p></li>class=属性,以便根据具体情况添加或删除上边距。

7 个答案:

答案 0 :(得分:12)

我不确定您是否会认为这是对您的问题的完整答案,因为我知道您在示例中使用的是<td>,而<td>之间的区别是{{} 1}}和<dd><li>元素是<td>元素在不破坏其<table>特定行为的情况下可以抵消其周围元素的事实。但至少我可以回答你的第三个问题的一部分:

  

如果确实无法定义为两种HTML创建相同格式的CSS规则......

这不是真的,您始终可以使用:before width集来呈现浮动的100%;伪元素,并设置margin的{​​{1}}的一半兄弟姐妹<p>元素。

&#13;
&#13;
dd {
  border: 1px dashed lightblue; /* this line is for demonstration purposes only */
}

dd:before {
  float: left;
  content: "";
  width: 100%;
  margin: 0.5em;
}
&#13;
<dd>
  An introductory sentence as a text node.
  <p>A further sentence as a paragraph.</p>
</dd>
<dd>
  <p>An introductory sentence as a paragraph.</p>
  <p>A further sentence as a paragraph.</p>
</dd>
&#13;
&#13;
&#13;

这引入了一个空的&#34;虚拟&#34;段落,仅影响<dd>的直接文本节点,因为<p>元素只会执行their automatic margin collapsing magic而不是向下移动。我认为这证明至少可以定义一个CSS规则,为两种HTML创建相同的格式。

这里是如何运作的,或者至少我是如何理解这一点的。 W3C在CSS规范中有一个示例,它向我们显示问题中的文本节点必须是anonymous block box,因为它是在display: block;集合的框内呈现的文本节点,{{1它有一个<dd>集的兄弟,display: block;

通过添加伪元素 - 在此匿名块框内呈现(必须是,因为否则它将永远不能像内联元素一样,或者它可能呈现为两个anonymous inline boxes,没有包含块框) - 但无论如何,我们最终得到两个匿名内联框(伪元素和文本节点)。

下一步是获取这些匿名内联框中的第一个,即伪元素,并通过向左浮动将其从正常流中取出,然后将其<p>设置为width,并且使它占据一个与兄弟100%边缘高度匹配的高度(我通过设置<p>边距的一半来完成,但你可以通过设置与<p>的边距匹配的高度或底部边距来做同样的事情。

现在前面的文本节点有一个人为的上边距。问题仍然存在,如果没有前面的文本节点,为什么这不会影响<p>元素?我认为这是因为 - 因为没有前面的文本节点 - 伪元素本身被渲染为应用它的元素内的空匿名块框(作为伪元素,内容总是在元素内部呈现)应用它们,这与在<p>之前呈现空<span>元素基本相同。

这是一个概念证明:

&#13;
&#13;
<p>
&#13;
dd {
  border: 1px dashed lightblue;
}

span {
  float: left;
  height: 1em;
  width: 100%;
  background-color: lightgray;
}

dd:not(:first-child)::before {
  content: "";
  float: left;
  height: 1em;
  width: 100%;
  background-color: lightgray;
}
&#13;
&#13;
&#13;

这个&#34;人为边缘&#34;是一个左浮动的块框(在伪元素的情况下是匿名块框)在其包含的元素内。如果他们需要,所有其他块框将向下移动(因为它们是根据W3C floating spec假设浮动框不为它们留下任何空间),这只会在浮动框开始长大时发生它隐藏的边距,并且在解决这个特定问题时没有发生,因为我已经专门设置了人工边际与<dd> <span></span> <p> The dashed light blue line marks the paragraphs margin box, the light grey box is the span. </p> </dd> <dd> <p> The dashed light blue line marks the paragraphs margin box, the light grey box is the pseudo element. </p> </dd>的实际边距一样高&# 39; S

我认为秘密在于W3C浮动规范的这一部分,这有点难以理解:

  

由于浮动不在流中,因此创建了未定位的块框   在浮动箱垂直流动之前和之后,好像浮子没有   存在。但是,旁边创建的当前和后续行框   必要时缩短浮子以为边缘盒腾出空间   浮动。

     

当存在垂直位置时,线框旁边是浮点数   满足所有这四个条件:(a)在顶部或低于顶部   线盒的,(b)在线盒底部或上方,(c)在下面   浮子的上边缘,(d)下边缘上方   浮动。

     

注意:这意味着浮动外部高度为零或外部为负   高度不会缩短线框。

     

如果缩短的行框太小而无法包含任何内容,那么   线框向下移动(并重新计算其宽度),直到任何一个   一些内容适合或没有更多的浮动存在。任何内容   浮动框之前的当前行在同一行中重排   浮子的另一面。换句话说,如果是内联级别的框   在遇到适合的左浮动之前放置在线上   剩下的行框空间,左边的浮动放在那行上,   与行框顶部对齐,然后是内联级别框   已经在线上相应地移动到浮动的右侧   (右边是左边浮动的另一边),反之亦然   rtl和右浮动。

我理解这意味着&#34;在浮动框垂直流动之前和之后创建的非定位块框,好像浮动不存在&#34;,所以<p> s是非定位块盒不应受浮动盒的影响。

但这并不意味着什么。相反,它指出,当盒子向左浮动时,在浮动盒子的右侧创建一个线框,填充浮动盒子右侧和容纳盒子右侧之间的空间。并且在该行框内部存在块框,该框是后续<p>元素。如果<p>元素可以放在满足上述四个条件的空间中,它将位于行框中的浮点旁边。

由于浮动设置的宽度为<p>,因此100%不适合浮动框旁边,并且它位于其行框内,向下移动到下一个框线,它以某种方式神奇地决定部分地遵守规则的第一部分:&#34;在浮动框垂直流动之前和之后创建的非定位块框,就好像浮动不存在&#34;,这似乎只是对于边距是正确的,因为只要浮动框超出边距,块框就会开始向下移动,也许是因为它也坐在一个线框中。

现在除了<p>标签以外的任何内容,让顶部添加的空间消失是非常简单的,因为可以通过将包含内容的元素与其包含的元素相抵消来轻松完成。

&#13;
&#13;
<td>
&#13;
dd {
  position: absolute;
  margin-top: -1em;      
}

dd:before {
  float: left;
  content: "";
  width: 100%;
  margin: 0.5em;
}

div {
  position: relative;
  /* everything below this line is for demonstration purposes only */
  border-top: 1px dashed lightblue;
  height: 80px;
}
&#13;
&#13;
&#13;

我认为回答第二个问题,至少对于<div> <dd> An introductory sentence as a text node. <p>A further sentence as a paragraph.</p> </dd> </div> <div> <dd> <p>An introductory sentence as a paragraph.</p> <p>A further sentence as a paragraph.</p> </dd> </div><dd>元素,甚至允许在前面的文本节点中使用内联元素。

如果您想在<li>内执行此操作,则必须以其他方式开始管理<td><td>身高,因为您必须在<table>内使用绝对定位,并通过将表格单元格设置为<td>(或通过在{{1}内渲染额外的display: block;来打破表格增长及其内容的默认表格行为并使用它作为块级元素,但这也会破坏默认的单元格增长行为。)

&#13;
&#13;
<div>
&#13;
<td>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

第一回答:

根据当前的HTML规范(HTML5)允许。但是,上一代HTML(HTML4 / XHTML1)的严格版本要求某些元素(例如bodyform)仅包含块,而不包含裸文本或文本级元素(现在统称为& #34;措词内容&#34;)。较新的规范必须放宽这个限制才能与现实相匹配,但我相信它有一个理由,主要是因为下一点......

第二回答:

正如Mathijs Flietstra在他的回答中所说,任何与没有任何display:block包装器的块级元素放在同一容器中的文本运行最终都是匿名块框(因为CSS块可以包含内联框或阻止盒子,但不是两种类型)。这些匿名框的行为与通常的块框一样(想想div元素),但是您不能直接设置它们任何CSS属性,它们只从容器中获取可继承的属性。所以没有办法既不设置填充也不设置边距,也不设置边框和背景。所有现有的CSS选择器都没有考虑到它们(:empty伪类除外),但在这种情况下它并不是非常有用。)

是的,有时您可以找到解决此限制的黑客行为。此外,像网格布局这样的现代CSS机制提供了一些方法,例如,无论类型如何,容器之间都有均匀的间距:

&#13;
&#13;
div > * {
  margin:0;
}
div{
  display:grid;
  grid-columns: 1fr;
  grid-row-gap: 1em;
  border:1px solid black;
}
&#13;
<div>
  <p>An introductory sentence as a paragraph.</p>
  <p>A further sentence as a paragraph.</p>
  <p>Another further sentence as a paragraph.</p>
</div>

<div>
  An introductory sentence as a text node.
  <p> A further sentence as a paragraph.</p>
  <address>Another further sentence as an <code>address</code> element.</address>
</div>
&#13;
&#13;
&#13;

但是,这些工作方法都不是银弹。例如,您无法在不破坏表格结构的情况下将display:grid应用于表格单元格。

第三个答案:

鉴于CSS块只能包含一种类型的盒子以及使用匿名盒子有多大的问题,我可以说好的经验法则如下:

  

永远不要在没有包装器的情况下将文本节点放在应该出现其他块的块中。

只需<li>Text</li>即可。但是如果嵌套列表应该在将来某个时候添加到此<li>,恕我直言,最好将文本包装在任何元素中 - 至少只是<span>(那么你会能够设置它display:block和任何块属性,如果这种需要突然发生的话。)

答案 2 :(得分:0)

第一个回答:

即可。 <dd> <dt> 元素都接受 flow content 。这意味着段落标记或原始文本是完全可以接受的。段落本身并没有打破流量,所以你可以拥有你想要的尽可能多的。

第二个答案:

您可以使用 :first-of-type 伪选择器:

&#13;
&#13;
dd {
  border: 1px solid black;
  padding: 5px;
}

dd > p:first-of-type {
  margin-top: 5em;
}
&#13;
<dd>
  <p>Sample text</p>
  <p>Sample text</p>
</dd>
&#13;
&#13;
&#13;

这允许您定位任何指定选择器的第一个匹配项(在这种情况下,该标记是<p>标记的直接子项的任何<dd>标记。 / p>

因为伪选择器是相对于<p>标记的,所以当第一个元素一个<p>标记时,这也有效:

&#13;
&#13;
dd {
  border: 1px solid black;
  padding: 5px;
}

dd > p:first-of-type {
  margin-top: 5em;
}
&#13;
<dd>
  <strong>Bold text</strong>
  <p>Sample text</p>
  <p>Sample text</p>
</dd>
&#13;
&#13;
&#13;

另请注意,<p>代码本身具有预定义的margin: 1em 0规则,如果您希望<p>代码更贴近彼此,则可以覆盖该规则

评论答案:

请注意,p:first-of-type定位的是第一个 <p> 标记。未指定标记的文本正在考虑成为直接父级的一部分(在本例中为<dd>,默认情况下为<body>)。因为您只定位第一个<p>代码,如果您希望两者之间的自由文本和第二段中包含的文字之间的边距,您需要在两者的顶部和底部应用边距:

&#13;
&#13;
dd {
  border: 1px solid black;
  padding: 5px;
}

dd > p:first-of-type {
  margin: 5em 0;
}
&#13;
<dd>
  Free text
  <p>TARGETED text</p>
  <p>Paragraph text</p>
</dd>
&#13;
&#13;
&#13;

希望这有帮助! :)

答案 3 :(得分:0)

<强>改性

1)是的

2)no,除非你通过保持第一行简短来阻止文本节点溢出单行的宽度。甚至不能使用<br>

添加

'Free'浮动(未标记)文本似乎没有任何CSS选择器可用,这使得无法使用Javascript进行选择。我记得有过这样的需要。称之为W3C遗漏?

唯一的可能性似乎是:empty选择器,但是因此我无法创建一些CSS逻辑来抓住在标记元素之前延迟的文本节点。所以这种使用看起来最黯淡(假设我知道我的逻辑......)

结束添加

在其他情况下,您可以删除几个元素上免费提供的HTML默认top-margin(请参阅CSS代码的第一行),并添加td>:not(:first-child) { margin-top: 1rem }以使第二行显示上边距。

p,.or-any-element-with-HTML-default-margins {
    margin-top: 0;
}
td>:not(:first-child) {
    margin-top: 1rem;
}
 
   /* demo, ignore */
   table,tr,td {
    border: 1px dotted silver;
    border-collapse: collapse;
}
.wrapper {
    max-width: 20rem;
    margin: 0 auto;
}
h2 {
    text-align: center;
}
<div class="wrapper">
    <h2>some table</h2>
    <table>
        <tr>
            <td>text node
                <p><strong>paragraph</strong> paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph </p>
            </td>
        </tr>
          <tr>
            <td>
                <p><strong>1st</strong> paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph </p>
                <p><strong>2nd</strong> paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph </p>
            </td>
        </tr>
        <tr>
            <td>
                <p><strong>paragraph</strong> paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph </p>
                Ordered List (<strong>text node</strong>)
                <ol>
                    <li>List item 1</li>
                    <li>List item 2</li>
                </ol>
            </td>
        </tr>
        <tr>
            <td>
                <p><strong>paragraph</strong> paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph paragraph </p>
                Unordered List (<strong>text node</strong>)
                <ul>
                    <li>List item 1</li>
                    <li>List item 2</li>
                </ul>
            </td>
        </tr>
    </table>
</div>

3)不适合SO。因此,我的2美分留在我的口袋里......

答案 4 :(得分:0)

  1. 是的,这是可以接受的。您可以使用W3C的标记验证服务(https://validator.w3.org/)来检查您的HTML是否有效。
  2. 我能够使用Button完成此任务。请参阅下面的演示。你甚至可以给TextView一个窄的宽度来换行,看看它是否仍然有用。
  3. :last-child
    <td>

答案 5 :(得分:0)

为应该有边距的元素添加一个类:

  • 指定上边距
  • 指定行高

或者使用它是特定的,就像第二个子元素一样:

td:nth-child(2) {
   top-margin: 2px;
}

答案 6 :(得分:-1)

第一个答案:有效

第二回答

无法区分这两个<p>元素与父(<div>

的关系

案例1:WithText

<div>
  Hello
  <p> hi</p>
</div>

情况2:WithoutText

<div>
  <p>hi</p>
</div>

<p>是第一个孩子,最后一个孩子等的情况下。将应用于WithText的<p>的每个选择器也将应用于WithoutText的<p>

但我还是试过......

何时:订单无关(逆序)且容器大小已修复

div p{
  margin:0 0 20px 0;
}
div{
  height:150px;
  display:flex;
  justify-content: end;
  flex-direction: column-reverse;
  border:1px solid black;
}
<div>
  <p>An introductory sentence as a paragraph.</p>
  <p>A further sentence as a paragraph.</p>
  <p> An another further sentence as a paragraph.</p>
</div>

<div>
  An introductory sentence as a text node.
      <p> A further sentence as a paragraph.</p>
      <p> An another further sentence as a paragraph.</p>
</div>

第三回答:

  

这不可能吗?

我不知道..

  

然后我想网站作者必须小心谨慎,始终只使用   一个HTML标记?

一致性很好。但是这里没有强制它的规则。

  

如果是这样,你认为这是正常的吗?

这取决于......