Flexbox не работает с кнопками или элементами fieldset

Я пытаюсь центрировать внутренние элементы <button> тег с флексбоксом justify-content: center, Но Safari не центрирует их. Я могу применить тот же стиль к любым другим тегам, и он работает как задумано (см. <p> -тег). Только кнопка выровнена по левому краю.

Попробуйте Firefox или Chrome, и вы увидите разницу.

Есть ли какой-нибудь стиль пользовательского агента, который мне нужно переписать? Или любое другое решение этой проблемы?

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>

И jsfiddle: http://jsfiddle.net/z3sfwtn2/2/

2 ответа

Решение

Проблема в том, что <button> Элемент не предназначен, чтобы быть гибким (или сеточным) контейнером.

На момент написания этой статьи браузеры на основе Webkit (Chrome и Safari) придерживались этого принципа разработки. Firefox и Edge нет. Я не тестировал другие браузеры.

Поэтому у вас не должно возникнуть проблем с <button> элемент гибкий (или сетка) контейнер в Firefox и Edge. Но не ожидайте, что он будет работать в Chrome или Safari.

Это поведение в настоящее время относится как минимум к трем элементам:

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

Я теоретизирую, но я считаю, что идея состоит в том, чтобы поддерживать уровень здравого смысла при оформлении элементов HTML. Например, боги HTML хотели, чтобы авторы не превратили кнопку в таблицу.

Тем не менее, по крайней мере, в этом случае есть простой и легкий обходной путь:

Оберните содержимое button в span и сделать span гибкий контейнер.

Скорректированный HTML (завернутый button содержание в 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>

Скорректированный CSS (таргетинг span)

button > span, p {
    display: flex;
    flex-direction: row;
    justify-content: center;
}

Пересмотренный Демо

ПРИМЕЧАНИЕ: хотя они не могут быть гибкими контейнерами, button элементы могут быть гибкими.

Рекомендации:

Вот мой самый простой взлом.

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

Начиная с Chrome 83, button теперь работает как inline-grid/grid/inline-flex/flex, вы можете узнать больше об этой новой функции здесь

Вот фрагмент (для тех, кто использует Chrome 83 и выше)

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

Другие вопросы по тегам