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;

And a jsfiddle:


@Michael_B 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)

        <span><!-- using a div also works but is not valid HTML -->

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:

@Toni Leigh 2017-07-24 09:03:16

Apple knows best!

@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_B 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 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_B 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

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

Here is my simplest hack.

button::after {
    content: '';
    flex: 1 0 auto;

Related Questions

Sponsored Content

5 Answered Questions

39 Answered Questions

[SOLVED] Better way to set distance between flexbox items

  • 2013-12-17 05:35:30
  • Sasha Koss
  • 767148 View
  • 648 Score
  • 39 Answer
  • Tags:   css css3 flexbox

12 Answered Questions

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

14 Answered Questions

[SOLVED] How to move an element into another element?

  • 2009-08-14 20:14:45
  • Mark Richman
  • 1049501 View
  • 1609 Score
  • 14 Answer
  • Tags:   javascript jquery html

10 Answered Questions

[SOLVED] Flexbox: center horizontally and vertically

18 Answered Questions

[SOLVED] How do CSS triangles work?

16 Answered Questions

16 Answered Questions

[SOLVED] Click through div to underlying elements

  • 2010-09-09 20:42:54
  • Ryan
  • 625840 View
  • 1496 Score
  • 16 Answer
  • Tags:   css

34 Answered Questions

14 Answered Questions

[SOLVED] <button> vs. <input type="button" />. Which to use?

Sponsored Content