Flexbox not working on button or fieldset elements in Chrome / Safari

I’m trying to center inner elements of a <button>-tag with flexbox’s justify-content: center. But Safari does not center them. I can apply the same style to any other tags and it works as intended (see the <p>-tag). Only the button is left-aligned.

Try Firefox or Chrome and you can see the difference.

Is there any user agent style I have to overwrite? Or any other solution to this problem?

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>

And a jsfiddle:
http://jsfiddle.net/z3sfwtn2/2/

The problem is that the <button> element cannot be a flex container in some browsers.

Depending on the browser, certain HTML elements will not accept display changes. Three of these elements are:

  • <button>
  • <fieldset>
  • <legend>

The idea is to maintain a level of common sense when styling HTML elements. For instance, the rule prevents authors from turning a fieldset into a table.

However, there is an easy workaround in this case:

Solution: 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

NOTE: Although they cannot be flex containers, button elements can be flex items.

References:

  • Bug 984869 – display: flex doesn’t work for button elements
  • Bug 1176786 – Flexbox on a blockifies the contents but doesn’t establish a flex formatting context

Here is my simplest hack.

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