Flex / Grid 布局不适用于按钮或字段集元素

Flex / Grid layouts not working on button or fieldset elements

我正在尝试将 <button> 标签的内部元素与 flexbox 的 justify-content: center 居中。但 Safari 不会将它们居中。我可以将相同的样式应用于任何其他标签,并且它按预期工作(请参阅 <p>-标签)。只有按钮是左对齐的。

试试 Firefox 或 Chrome,您会发现区别。

有没有我必须覆盖的用户代理样式?或者这个问题的任何其他解决方案?

div {
  display: flex;
  flex-direction: column;
  width: 100%;
}
button, p {
  display: flex;
  flex-direction: row;
  justify-content: center;
}
<div>
  <button>
    <span>Test</span>
    <span>Test</span>
  </button>
  <p>
    <span>Test</span>
    <span>Test</span>
  </p>
</div>

还有一个 jsfiddle: http://jsfiddle.net/z3sfwtn2/2/

问题

在某些浏览器中,<button> 元素不接受对其 display 值的更改,除了在 blockinline-block 之间切换。这意味着 <button> 元素不能是弹性或网格容器,也不能是 <table>

除了 <button> 元素之外,您可能会发现此约束也适用于 <fieldset><legend> 元素。

有关详细信息,请参阅下面的错误报告。

注意:虽然它们不能是弹性容器,但 <button> 个元素可以是弹性项目。


解决方案

这个问题有一个简单易行的跨浏览器解决方法:

button 的内容包装在 span 中,并使 span 成为 flex 容器。

已调整 HTML(将 button 内容包装在 span 中)

<div>
    <button>
        <span><!-- using a div also works but is not valid HTML -->
            <span>Test</span>
            <span>Test</span>
        </span>
    </button>
    <p>
        <span>Test</span>
        <span>Test</span>
    </p>
</div>

调整后CSS(目标span

button > span, p {
    display: flex;
    flex-direction: row;
    justify-content: center;
}

Revised Demo


参考资料/错误报告

Flexbox on a <button> blockifies the contents but doesn't establish a flex formatting context

User (Oriol Brufau): The children of the <button> are blockified, as dictates the flexbox spec. However, the <button> seems to establish a block formatting context instead of a flex one.

User (Daniel Holbert): That is effectively what the HTML spec requires. Several HTML container-elements are "special" and effectively ignore their CSS display value in Gecko [aside from whether it's inline-level vs. block-level]. <button> is one of these. <fieldset> & <legend> are as well.

Add support for display:flex/grid and columnset layout inside <button> elements

User (Daniel Holbert):

<button> is not implementable (by browsers) in pure CSS, so they are a bit of a black box, from the perspective of CSS. This means that they don't necessarily react in the same way that e.g. a <div> would.

This isn't specific to flexbox -- e.g. we don't render scrollbars if you put overflow:scroll on a button, and we don't render it as a table if you put display:table on it.

Stepping back even further, this isn't specific to <button>. Consider <fieldset> and <table> which also have special rendering behavior.

And old-timey HTML elements like <button> and <table> and <fieldset> simply do not support custom display values, other than for the purposes of answering the very high-level question of "is this element block-level or inline-level", for flowing other content around the element.

另见:

这是我最简单的技巧。

button::before,
button::after {
    content: '';
    flex: 1 0 auto;
}

从 Chrome 83 开始,button 现在作为 inline-grid/grid/inline-flex/flex 使用,您可以查看有关此新功能的更多信息 here

这是一个片段(对于使用 Chrome 83 及以上的用户)

button {
  display: inline-flex;
  height: 2rem;
  align-items: flex-end;
  width: 4rem;
  -webkit-appearance: none;
  justify-content: flex-end;
}
<!-- 

The align-items keyword should fail in Chrome 81 or earlier, but work in Chrome 83 or later. To see the error, the button needs styles that make it more of an extrinsic container. In other words, it needs a height or width set. 
 
-->
<button>Hi</button>
<input type="button" value="Hi">