By Ingemar


2016-02-17 17:49:33 8 Comments

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/

3 comments

@dippas 2020-05-31 05:02:56

Starting Chrome 83, the button now works as inline-grid/grid/inline-flex/flex, you can see more about this new feature here

Here is a snippet(for those using Chrome 83 and up)

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">

@Michael Benjamin 2016-02-17 19:43:51

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:

@fritzmg 2018-12-07 13:32:12

I get why it might not work for <button>s, but why on earth is it not working for <fieldset> either? Shouldn't that element be considered a regular block level element that is valid for a flex container?

@Michael Benjamin 2018-12-07 13:55:49

@fritzmg. Agreed. The rule probably pre-exists CSS3 technologies, such as Flex and Grid, and should be re-evaluated.

@Romain Vincent 2019-06-26 21:56:51

So we would like to prevent a button from being misused... but could still misuse something else and place it inside of the button. Sounds about as logic as the rest of the web...

@Jonathan Schofield 2019-08-10 17:46:59

Finding this thread in 2019 and noting that <button> works well as a flex-container in Chrome 76 and Safari 12.1. But both are buggy when the button is a child of display:grid. See codepen.io/urlyman/pen/rXqmqY. Firefox 68 holds up.

@mikemaccana 2019-08-21 15:06:05

Do you have a citation for <button> not being designed to be a flex (or grid) container? It looks like the browsers regard the inability to set display on these elements as a bug and are actively fixing them.

@mikemaccana 2019-08-21 15:23:45

@Michael_B Consider adding a reference to the actual text where you make the assertion. No need to reply to my comment - if you add it to the text where you make the assertion I'll give you an upvote.

@mikemaccana 2019-08-23 09:36:18

Also why isn't a div inside a button valid HTML?

@Michael Benjamin 2019-08-25 02:28:46

A div can't be a child of a button because, if you think of it in old-school HTML, a block-level element can't be a child of an inline-level element. But today, with HTML5, the technically correct answer is that a button element can only accept Phrasing Content. A span represents Phrasing Content, but a div does not. A div represents Flow Content. More details

@Systems Rebooter 2020-05-19 07:18:31

Unbelievable! :)

@Igari Takeharu 2016-11-08 09:39:22

Here is my simplest hack.

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

@Nuthinking 2020-01-13 17:10:01

Doesn't work for me. How would you fix this: codepen.io/nuthinking/pen/…

Related Questions

Sponsored Content

6 Answered Questions

[SOLVED] In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?

3 Answered Questions

[SOLVED] What are the differences between flex-basis and width?

  • 2015-12-18 09:17:22
  • jpeltoniemi
  • 69689 View
  • 225 Score
  • 3 Answer
  • Tags:   css flexbox width

27 Answered Questions

[SOLVED] Flex-box: Align last row to grid

12 Answered Questions

[SOLVED] Why don't self-closing script elements work?

7 Answered Questions

[SOLVED] Can't scroll to top of flex item that is overflowing container

2 Answered Questions

[SOLVED] align textarea and button in a bootstrap grid

2 Answered Questions

[SOLVED] Overlapping CSS flexbox items in Safari

3 Answered Questions

[SOLVED] Basic Angular material layout / flex example not working

3 Answered Questions

[SOLVED] Set height of CSS flex elements to the same amount?

Sponsored Content