Почему <fieldset> не может быть гибким контейнером?

Я пытался стилизовать fieldset элемент с display: flex а также display: inline-flex,

Однако это не сработало: flex вел себя как block, а также inline-flex вел себя как inline-block,

Это происходит как в Firefox, так и в Chrome, но странным образом это работает в IE.

Это ошибка? Я не мог найти это fieldset должно иметь какое-либо специальное поведение, ни в HTML5, ни в спецификациях CSS Flexible Box Layout.

fieldset, div {
    display: flex;
    border: 1px solid;
}
<fieldset>
    <p>foo</p>
    <p>bar</p>
</fieldset>
<div>
    <p>foo</p>
    <p>bar</p>
</div>

5 ответов

Решение

В соответствии с ошибкой 984869 - display: flex не работает для элементов кнопки,

<button> не может быть реализовано (браузерами) в чистом CSS, поэтому с точки зрения CSS они представляют собой нечто вроде черного ящика. Это означает, что они не обязательно реагируют так же, как, например, <div> было бы.

Это не относится к flexbox - например, мы не отображаем полосы прокрутки, если вы положили overflow:scroll на кнопку, и мы не будем отображать его в виде таблицы, если вы положите display:table в теме.

Отступив еще дальше, это не относится к <button>, Рассматривать <fieldset> а также <table> которые также имеют особое поведение рендеринга:

data:text/html,<fieldset style="display:flex"><div>abc</div><div>def</div>

В этих случаях Chrome соглашается с нами и игнорирует flex режим отображения. (как показывает тот факт, что "abc" и "def" оказываются сложенными вертикально). Тот факт, что они делают то, что вы ожидаете от <button style="display:flex"> скорее всего только из-за деталей реализации.

В реализации кнопки Gecko, мы жестко закодировали <button> (а также <fieldset>, а также <table>) с определенным классом фреймов (и, следовательно, с определенным способом размещения дочерних элементов), независимо от display имущество.

Если вы хотите надежно расположить дочерние элементы в определенном режиме макета кросс-браузерным способом, лучше всего использовать оболочку-div внутри кнопки, точно так же, как вам нужно внутри <table> или же <fieldset>,

Следовательно, эта ошибка была помечена как "исправлена ​​как недействительная".

Есть также ошибка 1047590 - display: flex; не работает в <fieldset>, в настоящее время "неподтвержденный".


Хорошие новости: Firefox 46+ реализует Flexbox для <fieldset>, Смотрите ошибку 1230207.

Я обнаружил, что это может быть ошибка в Chrome и Firefox, где legend а также fieldset заменены элементы.

Сообщения об ошибках:

Bug Chrome
Ошибка Firefox

Возможный обходной путь:

Возможный обходной путь будет использовать <div role="group"> в HTML и применение в CSS div[role='group'] как селектор.

Пожалуйста, пометьте ошибку Chrome, чтобы повысить ее приоритет

Это ошибка в Chrome. Добавьте звездочку к этой проблеме, чтобы повысить приоритет ее исправления:https://bugs.chromium.org/p/chromium/issues/detail?id=375693

Тем временем я создал эти три примера Code Pen, чтобы показать, как можно обойти проблему. Они построены с использованием CSS Grid для примеров, но те же методы можно использовать для flexbox.

Использование aria-labelledby вместо легенды

Это более правильный способ справиться с проблемой. Обратной стороной является то, что вам приходится иметь дело с созданием уникальных идентификаторов, применяемых к каждому фальшивому элементу легенды.

https://codepen.io/daniel-tonon/pen/vaaGzZ

<style>
.flex-container {
    display: flex;
}
</style>

<fieldset aria-labelledby="fake-legend">
    <div class="flex-container">
        <div class="flex-child" id="fake-legend">
            I am as good accessibilty wise as a real legend
        </div>

        ...

    </div>
</fieldset>

Использование role="group" и aria-labelledby вместо fieldset и legend

Если вам нужно, чтобы гибкий контейнер мог растягиваться до высоты родственного элемента, а затем также передавать это растяжение его дочерним элементам, вам нужно будет использовать role="group" вместо того <fieldset>

https://codepen.io/daniel-tonon/pen/BayRjGz

<style>
.flex-container {
    display: flex;
}
</style>

<div role="group" class="flex-container" aria-labelledby="fake-legend">
    <div class="flex-child" id="fake-legend">
        I am as good accessibilty wise as a real legend
    </div>

    ...

</div>

Создание поддельной копии легенды для стилизации

Это гораздо более хитрый способ сделать это. Он по-прежнему доступен, но при этом вам не нужно иметь дело с идентификаторами. Основной недостаток заключается в том, что между реальным элементом легенды и фальшивым элементом легенды будет дублированный контент.

https://codepen.io/daniel-tonon/pen/zLLqjY

<style>
.screen-reader-only {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.flex-container {
    display: flex;
}
</style>

<fieldset>
    <legend class="screen-reader-only">
        I am a real screen-reader accessible legend element
    </legend>

    <div class="flex-container">
        <div class="flex-child" aria-hidden="true">
            I am a fake legend purely for styling purposes
        </div>

        ...

    </div>
</fieldset>

Легенда ДОЛЖНА быть прямым потомком

Когда вы впервые попытаетесь исправить это самостоятельно, вы, вероятно, попытаетесь сделать это:

<!-- DO NOT DO THIS! -->
<fieldset>
    <div class="flex-container">
        <legend class="flex-child">
            Broken semantics legend text
        </legend>

        ...

    </div>
</fieldset>

Вы обнаружите, что это работает, и затем, вероятно, двинетесь дальше, даже не задумываясь.

Проблема в том, что размещение оболочки div между набором полей и легендой нарушает отношения между двумя элементами. Это нарушает семантику набора полей / легенды.

Таким образом, вы, в первую очередь, победили всю цель использования fieldset / legend.

Кроме того, нет особого смысла в использовании набора полей, если вы не дадите этому набору полей легенду.

По своему опыту я обнаружил, что ни <fieldset>ни <button>ни <textarea> может правильно использовать display:flex или унаследованные свойства.

Как уже упоминали другие, сообщалось об ошибках. Если вы хотите использовать flexbox для управления заказами (например, order:2), тогда вам нужно будет обернуть элемент в div. Если вы хотите, чтобы flexbox управлял фактической компоновкой и размерами, то вы можете рассмотреть возможность использования div вместо элемента управления вводом (который, я знаю, воняет).

Чтобы ответить на исходный вопрос: да, это ошибка, но она не была четко определена в то время, когда был задан вопрос.

Теперь рендеринг для набора полей лучше определен: https://html.spec.whatwg.org/multipage/rendering.html

В Firefox и Safari, flexbox на fieldsetв настоящее время работает. Его еще нет в Chromium. (См. https://bugs.chromium.org/p/chromium/issues/detail?id=375693)

Также см. https://blog.whatwg.org/the-state-of-fieldset-interoperability, чтобы узнать об улучшениях, внесенных в спецификацию в 2018 году.

<div role="group">
    <p>foo</p>
    <p>bar</p>
</div>
<div>
    <p>foo</p>
    <p>bar</p>
</div>

Возможно, нужно использовать группу ролей, потому что Firefox, Chrome и я думаю, что Safari, по-видимому, имеет ошибку с fieldsets. Тогда селектор в CSS будет просто

div[role='group'], div {
    display: flex;
    border: 1px solid;
}

Изменить: Вот некоторые проблемы, с которыми сталкиваются и другие люди.

Выпуск 375693

Выпуск 262679

Вы можете добавить дополнительный div в <fieldset> со следующими реквизитами:

flex-inner-wrapper {
  display: inherit;
  flex-flow: inherit;
  justify-content: inherit;
  align-items: inherit;
}
Другие вопросы по тегам