Flex / Grid layouts not working on button or fieldset elements
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 putdisplay: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 customdisplay
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:
- Flexbug #9: Some HTML elements can't be flex containers
- 10. Some HTML elements can't be grid containers
Fieldset cannot apply flex direction
Fieldset, legends and some other elements can not use flexbox
properly. Its a bug.
A possible Solution can be using <div role="group">
in HTML, and add CSS div[role='group']
as selector.
span { background: lightgreen;}span:nth-of-type(odd) { background: pink;}
div, div[role='group']{ display: flex; flex-flow: row wrap;}
<div role="group"> <span>text 1</span> <span>text 2</span> <span>text 3</span></div>
<div> <span>text 1</span> <span>text 2</span> <span>text 3</span></div>
Why can't fieldset be flex containers?
According to Bug 984869 - display: flex
doesn't work for button elements,
<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 putoverflow:scroll
on a button, and we don't render it as a
table if you putdisplay:table
on it.Stepping back even further, this isn't specific to
<button>
. Consider
<fieldset>
andwhich also have special rendering behavior:<table>
data:text/html,<fieldset style="display:flex"><div>abc</div><div>def</div>
In these cases, Chrome agrees with us and disregards the
flex
display mode. (as revealed by the fact that "abc" and "def" end up
being stacked vertically). The fact that they happen to do what you're
expecting on<button style="display:flex">
is likely just due to an
implementation detail.In Gecko's button implementation, we hardcode
<button>
(and
<fieldset>
,and) as having a specific frame class (and hence,<table>
a specific way of laying out the child elements), regardless of the
display
property.If you want to reliably have the children reliably arranged in a
particular layout mode in a cross-browser fashion, your best bet is to
use a wrapper-div inside the button, just as you would need to inside
ofaa<table>
or<fieldset>
.
Therefore, that bug was marked as "resolved invalid".
There is also Bug 1047590 - display: flex;
doesn't work in <fieldset>
, currently "unconfirmed".
Good news: Firefox 46+ implements Flexbox for <fieldset>
. See bug 1230207.
Chrome issues with CSS Grid styled buttons
How about this?
<button>
<div className="container">
<div className="header"></div>
<div className="child"></div>
<div className="child"></div>
<div className="child"></div>
<div className="child"></div>
</div>
</button>
Related Topics
Print Header/Footer on All Pages (Print Mode)
How to Disable Hover Effect for Active Link
On Hover of Child, Change Background Color of Parent Container (Css Only)
How to Type Text With Hat "^" in HTML
Css - How to Make the Checkbox and Label in One Line
How to Remove Outline in Bootstrap 4
How to Style Selected Option Color Separately from Disabled Option
How to Remove Free Spaces Between Divs
Placing Two Divs on Top of Each Other Without Using Position:Absolute
Using Mailto to Send Email With an Attachment
Force Element to Display Outside of Overflow:Hidden
How to Place Div in Top Right Hand Corner of Page
How to Prevent Newline At the End of HTML Input Field
How to Prevent Flex-Items from Overflowing Flex Parent With No Wrap
How to Remove All Script Tags from HTML File
Setting Attribute Disabled on a Span Element Does Not Prevent Click Events
How to Run a HTML File from Terminal
How to Set the Height of an Outer Div to Always Be Equal to a Particular Inner Div