【问题标题】:Prevent CSS `column-span: all` shunting to bottom of page防止 CSS `column-span: all` 分流到页面底部
【发布时间】:2020-10-31 23:50:19
【问题描述】:

我有一个由用户在文本编辑器中提供的 markdown 实时生成的多列 div(2-4 列,具体取决于我的应用程序中的设置)。在某些情况下,他们希望手动插入分栏符。为了实现这一点,我提供了一个 Markdown sn-p,它生成一个带有 CSS 属性 break-after: column 的 div 来手动触发分栏符。如果设置为display: block,它工作正常。但是,如果用户随后插入一个跨越两列的 div(使用 CSS column-span: all),则该跨列元素将被分流到其包含元素的 下方,并且任何进一步的文本都会完全消失,如下所示(特别是在最新版本的 Chrome 中):

.container {
  column-count: 2;
  height: 60mm;
  border: solid black 1px;
}

.container .colbreak {
 color: red;
 break-after: column;
}

.container .wide {
  color: blue;
  column-span: all;
}
<div class="container">

  <p>left left left</p>
  <p>left left left</p>
   
  <div class="colbreak">Column Break</div>
  
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>
  <p>right right right</p>

  <div class="wide">
    span all span all span all
    span all span all span all
    span all span
  </div>
  
  <p>more columns after</p>
  <p>more columns after</p>
  <p>more columns after</p>
  <p>more columns after</p>

</div>

这就是它的样子(注意缺少“后面的更多列”段落):

colbreak 更改为display: inline-block 或其他方式似乎完全忽略了break-after: column(也许这是真正的 问题:为什么break-after 被我忽略了inline-block 元素?

如下所示,我完全不包含 colbreak div 会得到相同的行为:

谁能解释如何实现所需的行为?由于这是在用户输入时实时呈现的,因此我希望通过不需要为每列单独的 div 来保持列的自动平衡。计算文本长度和高度并在键入时在列之间动态移动它们似乎比它的价值更麻烦。如果用户更改为设置,这也会停止工作

【问题讨论】:

    标签: html css css-multicolumn-layout


    【解决方案1】:

    如何达到接近预期的效果:

    如果您想了解更多关于多列 css 支持的信息,我认为css-multicol 会很好读。

    您当前 css 的主要问题是 height in container。要解决这个问题,您可以将容器放在另一个 div 中并使用您想要的样式设置它,这将尽可能地接近您想要的结果。

    .main-container {
      height: minmax(min-content, 100mm);
      overflow: auto;
      border: solid black 1px;
    }
    
    .container {
      column-count: 2;
    }
    
    .container .colbreak {
      color: red;
      break-after: column;
    }
    
    .container .wide {
      color: blue;
      column-span: all;
    }
    <div class="main-container">
      <div class="container">
        <p>left left left</p>
        <p>left left left</p>
    
        <div class="colbreak">Column Break</div>
    
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
    
        <div class="wide">
          span all span all span all span all span all span all span all span
        </div>
    
        <p>more columns after</p>
        <p>more columns after</p>
        <p>more columns after</p>
        <p>more columns after</p>
      </div>
    </div>

    为什么容器上的高度没有按预期工作?

    我相信这是设计使然,至少从我阅读规范的理解来看,它说:

    跨越多于一列的元素称为跨越 元素和它创建的框称为扳手。

    一个跨越元素被从流中取出,留下一个强制中断。这个 不影响跨越元素的绘制顺序[CSS21]。

    更新:

    为什么我的 inline-block 元素忽略了 break-after?:

    这是因为break-word 应该只适用于block-level elements,根据W3C guidelines

    原答案: 您需要将列内容包装到单独的 div 中并将 column-count 样式应用于该 div 并且它将起作用。

    .container {
      height: 100mm;
      border: solid black 1px;
    }
    
    .col2 {
      column-count: 2;
    }
    
    .container .colbreak {
      break-after: column;
    }
    
    .container .wide {
      color: blue;
      column-span: all;
    }
    <div class="container">
      <div class="col2">
        <p>left left left</p>
        <p>left left left</p>
        <p>left left left</p>
    
        <div class="colbreak">Column Break</div>
    
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
      </div>
      <div class="wide">
        span all span all span all span all span all span all span all span all span all span all span all span all span all span all span all
      </div>
    
    </div>

    或者您可以使用 CSS 网格:

    .container {
      height: 100mm;
      border: solid black 1px;
      display: grid;
      grid-template-columns: 50% 50%;
    }
    
    .container .wide {
      color: blue;
      grid-column-start: 1;
      grid-column-end: -1;
    }
    <div class="container">
      <div>
        <p>left left left</p>
        <p>left left left</p>
        <p>left left left</p>
      </div>
      <div>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
      </div>
      <div class="wide">
        span all span all span all span all span all span all span all span all span all span all span all span all span all span all span all
      </div>
    </div>

    【讨论】:

    • 这是我们早期尝试过的,但如您所见,分栏不再出现在所需的位置(一些“右右”段落位于左侧)。当我们更改 colbreak div 的显示类型时,似乎“break-after: column”被简单地忽略了。
    • @TrevorBuckner 我有点误解了,让我更新一下答案。
    • 将列内容包装在单独的 div 中将为您提供所需的行为。
    • 这是一个有趣的选项。本质上,我们只是从 2 列块中删除 wide div。不过,如果可能的话,我希望在恢复 2 列行为的 wide 块之后允许附加文本。这个 HTML 是由用户在文本框中提供的 markdown 实时生成的,因此如果可能的话,减少多个 div 的复杂性将是理想的(每次我们在 2 列之间交换一个新的 div)。我认为解决这个问题的关键实际上可能是:“当我的元素使用display: inline-block 时,为什么会忽略break-after?”请参阅我更新的问题。 (这很好,给了我一些想法)
    • @TrevorBuckner 检查我更新的答案,break-after 应该只适用于 block-level 元素而不是内联。
    【解决方案2】:

    您可以尝试将列分成 2 个 div。它将分隔它们,允许将它们设置为单独的列,而不必插入中断。

    .column {
      float: left;
      width: 50%;
    }
    <div class="container">
      <div class="column">
        <p>left left left</p>
        <p>left left left</p>
        <p>left left left</p>
      </div>
    
      <div class="column">
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
        <p>right right right</p>
      </div>
    
      <div class="wide">
        span all span all span all span all span all span all span all span all span all span all span all span all span all span all span all
      </div>
    </div>

    【讨论】:

    • 嗯...如果可能的话,我想避免为每一列单独的divs,因为一旦文本到达容器底部,它就会消除自然的分列行为。但到目前为止,这看起来像是最好地捕获了所需的行为,并且可能是可行的......
    • 老实说,您也可以制作一个有 2 列的表格,并且底行 colspan = 2
    【解决方案3】:

    建议您重构 HTML 代码并使用 flexbox。它可以让您更好地控制 div 的位置以及您想要使用它的内容的方式。此外,使用 flexbox 进行响应非常容易。

    .container{
      width: 50%;
      border: 1px solid black;
    }
    
    .container .flex {
      display:flex;
      flex-direction: row;
      justify-content: space-around;
    }
    
    .container .wide {
      color: blue;
      column-span: all;
    }
    <div class="container">
      <div class="flex">
        <div>
      <p>left left left</p>
      <p>left left left</p>
      <p>left left left</p>
       <p>left left left</p>
     
       <p>left left left</p>
      <p>left left left</p>
      <p>left left left</p>
       <p>left left left</p>
      <p>left left left</p>
      <p>left left left</p>
       
      <div class="colbreak">Column Break</div>
      </div>
      <div class="flex-2">
      <p>right right right</p>
      <p>right right right</p>
      <p>right right right</p>
      <p>right right right</p>
      <p>right right right</p>
      <p>right right right</p>
      <p>right right right</p>
      </div>
    </div>
    
    <div class="wide">
      
      span all span all span all
      span all span all span all
      span all span all span all
      span all span all span all
      span all span all span all
    </div>
    </div>

    【讨论】:

    • 感谢您的回答。如果可能的话,我想避免为每列使用单独的 div,因为一旦文本到达容器底部,它就会消除自然的分列行为。
    • 您能否详细解释一下分列行为,因为 flexbox 是灵活的,并且无论内容如何,​​都将处于相同的布局中。
    • 当然。通常在 2 列 div 中,您可以键入和键入,您的文本将自动分成两列。由于此 HTML 是从文本框中的用户提供的 markdown 实时生成的,因此文本在列之间自动重排是理想的,而不是试图在运行中将文本排序和平衡到两个 flexbox 中。这说明清楚了吗? (查看更新的问题)
    猜你喜欢
    • 2013-03-18
    • 2011-01-09
    • 2017-09-22
    • 2013-01-04
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多