The Problem
In some browsers the <button>
element doesn't accept changes to its display
value, beyond switching between block
and inline-block
. This means that a <button>
element cannot be a flex or grid container, or a <table>
, either.
In addition to <button>
elements, you may find this constraint applying to <fieldset>
and <legend>
elements, as well.
See the bug reports below for more details.
Note: Although they cannot be flex containers, <button>
elements can be flex items.
The Solution
There is a simple and easy cross-browser workaround to this problem:
Wrap the content of the button
in a span
, and make the span
the flex container.
Adjusted HTML (wrapped button
content in a 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>
Adjusted CSS (targeted span
)
button > span, p {
display: flex;
flex-direction: row;
justify-content: center;
}
Revised Demo
References / Bug Reports
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.
Also see: