Макети Flex / Grid не працюють на елементах кнопок або полів


91

Я намагаюся відцентрувати внутрішні елементи <button>-tag за допомогою flexbox justify-content: center. Але Safari їх не центрує. Я можу застосувати той самий стиль до будь-яких інших тегів, і він працює за призначенням (див. <p>-Tag). Тільки кнопка вирівняна за лівим краєм.

Спробуйте 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/


Відповіді:


132

Проблема

У деяких браузерах <button>елемент не приймає змін у своєму displayзначенні, окрім перемикання між blockта inline-block. Це означає, що <button>елементом не може бути гнучкий контейнер або контейнер сітки, а також a <table>.

На додаток до <button>елементів, ви можете виявити, що це обмеження стосується <fieldset>і <legend>елементів.

Докладніше див. У звітах про помилки нижче.

Примітка: Хоча вони не можуть бути гнучкими контейнерами, <button>елементи можуть бути гнучкими предметами.


Рішення

Існує простий і легкий спосіб вирішення цієї проблеми у різних браузерах:

Оберніть вміст buttonв spanта зробіть spanгнучкий контейнер.

Відрегульований HTML (загорнутий buttonвміст у 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>

Налагоджений CSS (цільовий span)

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

Переглянуте демо


Посилання / Звіти про помилки

Flexbox на <button>блоці зміщує вміст, але не встановлює контексту гнучкого форматування

Користувач (Оріоль Бруфау): Діти <button>блокуються, як диктує специфікація flexbox. Однак, <button>схоже, встановлює контекст форматування блоків замість гнучкого.

Користувач (Даніель Холберт): Це саме те, що вимагає специфікація HTML. Кілька елементів-контейнерів HTML є "спеціальними" і фактично ігнорують їх displayзначення CSS у Gecko [окрім того, чи є це вбудований рівень проти рівня блоку]. <button>є одним із таких. <fieldset>& <legend>є також.

Додайте підтримку для відображення: макет flex / grid та набір стовпців всередині <button>елементів

Користувач (Даніель Холберт):

<button>неможливо реалізувати (браузерами) у чистому CSS, тому вони є трохи чорною скринькою, з точки зору CSS. Це означає, що вони не обов'язково реагують так само, як, наприклад, а <div> .

Це не характерно для flexbox - наприклад, ми не відображаємо смуги прокрутки, якщо ви overflow:scrollнатискаєте кнопку, і не відображаємо її як таблицю, якщо ви display:tableна неї кладете .

Відступаючи ще далі, це не характерно для <button>. Розглянемо <fieldset>і <table>які також мають особливу поведінку при отриманні.

І старі Тимей HTML елементи , як <button>і <table>і <fieldset>просто не підтримує призначені для користувача displayзначення, крім як для цілей відповіді на питання дуже високого рівня «цей елемент рівня блоку або інлайн-рівня», для протікає іншого контенту навколо елемента .

Також див.


3
Я розумію, чому це може не працювати для <button>s, але чому, по суті, це не працює <fieldset>ні для того, ні для іншого? Чи не слід вважати цей елемент звичайним елементом рівня блоку, який діє для гнучкого контейнера?
fritzmg

3
@fritzmg. Домовились. Правило, ймовірно, вже існує технологій CSS3, таких як Flex та Grid, і їх слід переглянути.
Майкл Бенджамін

Отже, ми хотіли б запобігти неправильному використанню кнопки ... але все одно могли б використати щось інше і розмістити її всередині кнопки. Звучить приблизно так само логічно, як і решта Інтернету ...
Ромен Вінсент

1
@Michael_B Розгляньте можливість додати посилання на фактичний текст, де ви робите твердження. Не потрібно відповідати на мій коментар - якщо ви додасте його до тексту, де ви зробите твердження, я дам вам голос за.
mikemaccana

2
Не divможе бути buttonнащадком, тому що, якщо ви думаєте про це в HTML-коді старої школи, елемент рівня блоку не може бути нащадком елемента вбудованого рівня. Але сьогодні, з HTML5, технічно правильну відповідь , що елемент може приймати тільки формулюючи зміст . A представляє вміст фрази , але ні - ні. A являє собою вміст потоку . Детальнішеbuttonspandivdiv
Майкл Бенджамін


1

Запускаючи 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">

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.