为什么 overflow:hidden 会破坏 Firefox 中的多列呈现而不是 Chrome?

Why does overflow:hidden break multiple column rendering in Firefox but not in Chrome?

我最近在 columns:2 div 中的 Firefox 中偶然发现了一个奇怪的行为。

如果列表有 overflow:hidden 设置,Firefox 将不再以 2 列呈现。在 Chrome 中呈现,它在 2 列中符合预期(有和没有溢出)。

这是一个最小的例子:

$('button').on('click', (e) => {
  $('ul').toggleClass('overflow')
})
div {
  columns:2;
}

ul.overflow {
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>toggle overflow</button>
<div>
    <ul>
        <li>Lorem ipsum dolor.</li>
        <li>Consequuntur, ab nostrum.</li>
        <li>Quibusdam, iure, fuga.</li>
        <li>Suscipit quisquam, vel.</li>
        <li>Assumenda architecto, adipisci!</li>
        <li>Molestias, nostrum ratione.</li>
        <li>Quaerat, eveniet, in.</li>
        <li>Illum, debitis, dicta.</li>
        <li>Tempore, placeat, ea.</li>
        <li>Amet dignissimos, maiores.</li>
        <li>Odio, eos, ullam.</li>
        <li>Modi libero, quis!</li>
        <li>Aliquid, commodi, voluptates.</li>
        <li>Aperiam, magni, vel.</li>
        <li>Vitae, minima dolorum!</li>
        <li>Quidem, corporis, dolorum.</li>
        <li>Autem, minima, sit.</li>
        <li>Adipisci, odio, numquam.</li>
        <li>At, dicta, hic!</li>
        <li>Odit, blanditiis voluptate.</li>
    </ul>
</div>

在 CodePen 上: https://codepen.io/BugHunter2k/pen/rNaVpGG

什么样的渲染才是对的? 有什么我可以添加的,这样 Firefox 即使使用 overflow:hidden

也能呈现 2 列

这可能是 Firefox 的错误。

但是您可以将 columns: 2; 放在 ul 而不是 div 上。它还将解决第二列与第一列不对齐的(不需要的?)行为。

不要忘记在您的代码中使用浏览器前缀。它总是可以帮助您防止一些错误。

虽然 Thierry 的回答包括解决一个问题的解决方案,但它也解决了您面临的实际问题(我相信是无意中),并且有问题地将责任归咎于错误的浏览器。让我们分解一下:

首先,这实际上在 Firefox 中工作正常,而在 Chrome 中不正确。

您有一个 div 由于 columns: 2 而充当 multi-column container,它是 shorthand 用于:

div {
    column-count: 2;
    column-width: auto;
}

这个多列容器建立了一个新的 block formatting context,因此后代元素的任何属性都将相对于 div 而不是本例中的页面应用。

要记住的一件事是多列布局有点灵活(我也不是指与 flexbox 布局相关的)...它们会尝试遵守您提供的值,但是如果他们可以容纳更少的列,或者如果他们必须占用更多的列来适应您的标记,他们很可能会这样做。您稍后会在我的回答中看到这方面的示例。

在 div 中,您有一个无序列表,通常在垂直列表中显示其子项,但由于之前的 columns: 2,您的 <ul> 会自动拆分以适合尽可能分成两列。因为没有在任何地方声明 heightwidth 属性(通常或作为 column- 属性),它只是将内容拆分为 50-50。您在列表的两半之间看到的错位是因为 <ul> 默认情况下有 margin-top 属性 这将列表项的前半部分向下推 16px(通常是边距的大小<ul>s)。

之所以在 ul {} 中应用 columns: 2 而不是 div {} 解决了您的问题,是因为您现在正在拆分 <ul> 本身 分成两列,而不是试图将普通的 <ul> 挤进多列容器中,但是它可以容纳;浏览器知道以这种方式将相同的格式应用于每一列的开头。

现在,<div> 默认与其容器一样宽(因为它的默认 display:block; 属性)和它的内容一样高。如果要向 <ul> 添加更多项,则两组列表项的高度会增加(如果为 div 设置了背景颜色,则可以更容易地看到) .

回到我提到的灵活性,如果您将 div 的高度限制在 150px,您会看到列数增加并溢出 div 默认:

div {
    columns:2;
    column-rule: thin solid red; /* this value added just to illustrate the split between columns */
    height: 150px;
    background: grey; /* this value added for ease of visual comprehension */
}

ul.overflow {
    overflow: hidden;
}
<div>
    <ul>
        <li>Lorem ipsum dolor.</li>
        <li>Consequuntur, ab nostrum.</li>
        <li>Quibusdam, iure, fuga.</li>
        <li>Suscipit quisquam, vel.</li>
        <li>Assumenda architecto, adipisci!</li>
        <li>Molestias, nostrum ratione.</li>
        <li>Quaerat, eveniet, in.</li>
        <li>Illum, debitis, dicta.</li>
        <li>Tempore, placeat, ea.</li>
        <li>Amet dignissimos, maiores.</li>
        <li>Odio, eos, ullam.</li>
        <li>Modi libero, quis!</li>
        <li>Aliquid, commodi, voluptates.</li>
        <li>Aperiam, magni, vel.</li>
        <li>Vitae, minima dolorum!</li>
        <li>Quidem, corporis, dolorum.</li>
        <li>Autem, minima, sit.</li>
        <li>Adipisci, odio, numquam.</li>
        <li>At, dicta, hic!</li>
        <li>Odit, blanditiis voluptate.</li>
    </ul>
</div>

如您所见,div 与容器一样宽(无论您的容器有多大)并且列分为三列,因为这需要满足列表项的数量你有。它通过 溢出 子元素来做到这一点,以尝试保持列的高度相等。 您在切换按钮时看到的行为的秘密是 overflow: hidden; 所做的。

当您将 overflow: hidden; 应用到一个元素时,它 也会 建立一个新的块格式上下文。创建一个新的块格式化上下文基本上说 "reset my layout computation from scratch here; don't factor in what the containing block was doing"。在您的情况下,它表示 "ignore the CSS column layout in the previous block formatting context and just display like a <ul> normally would"。 Chrome 没有这样做,但它应该这样做。这可能是 wrong/incomplete 实施的情况,也可能是 Chrome 开发人员根据他们认为大多数人想要的内容做出决定的情况。这两种情况在该供应商中都很常见。

其次,Thierry 为修复 <ul> 两部分垂直对齐不均匀的建议是将 column 属性应用于 <ul> 特定的 目标也可以通过将 margin-top property/setting 移除为 0 来实现,但是这种解决该目标的方法还执行以下操作:

  • <ul> 应用适当的多列布局设置(正如我之前提到的,现在浏览器知道在多列布局的上下文中处理列表和列表项,而不仅仅是试图将列表压缩到多列容器中)。
  • <ul> 上设置 columns 属性 本身意味着,当由于 overflow: hidden; 而创建新的块格式化上下文时,关于<ul> 忽略来自父 <div> 的内容及其块格式上下文。换句话说,多列布局应用在由 overflow: hidden;.
  • 创建的 new 块格式化上下文中

如果您只是想将无序列表拆分为多列,那么这种新行为最终就是您想要的。如果您希望为多列布局考虑多种类型的元素(或只是多种元素),则需要将其保留在父级 <div> 上。