为什么 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>
会自动拆分以适合尽可能分成两列。因为没有在任何地方声明 height
或 width
属性(通常或作为 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>
上。
我最近在 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
这可能是 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>
会自动拆分以适合尽可能分成两列。因为没有在任何地方声明 height
或 width
属性(通常或作为 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>
上。