Perché <fieldset> non può essere un contenitore flessibile?


201

Ho provato a modellare un fieldsetelemento con display: flexe display: inline-flex.

Tuttavia, non ha funzionato: si è flexcomportato come blocke si è inline-flexcomportato come inline-block.

Questo succede sia su Firefox che su Chrome, ma stranamente funziona su IE.

E 'un errore? Non riuscivo a trovare che fieldsetdovesse avere un comportamento speciale, né in HTML5 né nelle specifiche CSS Layout flessibile scatola .

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


2
Sì, è un bug. Correzione semplice: utilizzare un altro elemento. code.google.com/p/chromium/issues/detail?id=262679
Adam

Risposte:


145

Secondo il bug 984869 - display: flexnon funziona per gli elementi dei pulsanti ,

<button>non è implementabile (dai browser) nei CSS puri, quindi sono un po 'una scatola nera, dal punto di vista dei CSS. Ciò significa che non necessariamente reagiscono nello stesso modo in cui, ad esempio, un <div>.

Questo non è specifico per la flexbox - ad esempio non eseguiamo il rendering delle barre di scorrimento se si inserisce overflow:scrollun pulsante e non lo eseguiamo come tabella se lo si inserisce display:table.

Facendo un passo indietro, questo non è specifico <button>. Tener conto di <fieldset> e <table> che hanno anche un comportamento di rendering speciale:

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

In questi casi, Chrome è d'accordo con noi e ignora la flex modalità di visualizzazione. (come rivelato dal fatto che "abc" e "def" finiscono per essere impilati verticalmente). Il fatto che capiti di fare ciò che ti aspetti <button style="display:flex">è probabilmente dovuto solo ai dettagli di implementazione.

Nell'implementazione dei pulsanti di Gecko, abbiamo hardcode <button>(e <fieldset>,e <table>) come avente una specifica classe di frame (e quindi un modo specifico di strutturare gli elementi figlio), indipendentemente dalla displayproprietà.

Se vuoi avere i bambini in modo affidabile disposti in modo affidabile in una particolare modalità di layout in modo cross-browser, la soluzione migliore è utilizzare un wrapper-div all'interno del pulsante, proprio come avresti bisogno all'interno un <table>oa <fieldset>.

Pertanto, quel bug è stato contrassegnato come "risolto non valido".

C'è anche un bug 1047590 - display: flex;non funziona<fieldset> , attualmente "non confermato".


Buone notizie : Firefox 46+ implementa Flexbox per <fieldset>. Vedi bug 1230207 .


Considerando che Flexbox è in un limbo da 8 anni ormai, trovo "notevolmente" un po 'un'esagerazione. Semmai, sono sorpreso che abbiano funzionato in Firefox così rapidamente. Forse ti piacerebbe aiutare a dare una marcia in più a Google (eh, capito ?).
BoltClock

3
<button> is not implementable (by browsers) in pure CSS- è solo sbagliato. Un browser è libero di implementare ciò <button>che desidera, non è "obbligato per contratto" a renderlo utilizzando librerie di widget di sistema o altro, che compromettono la capacità di modellarli con CSS o altri comportamenti personalizzati. Lo stesso vale per qualsiasi altro elemento, davvero.
AMN

4
@BoltClock Non sei sicuro di cosa intendi per limbo. Tutti i principali browser supportano la terza e ultima revisione della sintassi dal 2015; l'interoperabilità è piuttosto buona, credo. Ora abbiamo anche ottenuto un ampio supporto per Grid! 🎉
Šime Vidas,

@ Šime Vidas: vedo, sembra che sia CR da un anno ormai. Giusto. Ho pensato che non ce l'avrebbe mai fatta.
BoltClock

9
2017 davvero. Dove indico la mia rabbia? Anni di attesa per implementare in sicurezza flexbox, innumerevoli articoli, tute, prove / errori, ottengo lì il 98% e ... set di campi. È come convincere un elettricista a cablare la mia casa, solo per scoprire che un jack di alimentazione non è collegato a terra. "Non esagerare" Sento la gente pensare, esagerare non lo so. Devo letteralmente rispondere per questo domani. Flex è stata la risposta a diversi bug di tabella legacy che dovevo risolvere. Flex è ora la causa di una manciata più piccola di bug non legacy. Dove indico la mia rabbia?
danjah

20

Ho scoperto che questo potrebbe essere un bug su Chrome e Firefox in cui legende fieldsetsono sostituiti elementi .

Bug segnalati:

Bug Chrome (ancora aperto)
Bug Firefox (risolto dalla v46)

Una possibile soluzione alternativa:

Una possibile soluzione potrebbe essere l'utilizzo <div role="group">in HTML e l'applicazione in CSS div[role='group']come selettore.


AGGIORNARE

In Chrome la versione 83 button può funzionare con il display: inline-grid/grid/inline-flex/flex, puoi vedere la demo qui sotto:

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


11

Aggiungi il bug di Chrome per aumentare la priorità dei bug

Questo è un bug in Chrome. Aggiungi una stella a questo problema per aumentare la priorità da correggere: https://bugs.chromium.org/p/chromium/issues/detail?id=375693

Nel frattempo, ho creato questi tre esempi di Code Pen per mostrare come aggirare il problema. Sono costruiti utilizzando la griglia CSS per gli esempi, ma le stesse tecniche possono essere utilizzate per la flexbox.

Usando aria-labelledby anziché legenda

Questo è il modo più propizio per affrontare il problema. Il rovescio della medaglia è che devi occuparti della generazione di ID univoci applicati a ogni elemento legenda falso.

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>

Utilizzo di role = "group" e aria-labelledby invece di fieldset e legenda

Se hai bisogno del contenitore flessibile per essere in grado di allungare fino all'altezza di un elemento fratello e quindi passare anche questo tratto ai suoi figli, dovrai usare role="group"invece di<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>

Creazione di una falsa legenda duplicata a scopi di styling

Questo è un modo molto più confuso per farlo. È comunque altrettanto accessibile ma non è necessario gestire gli ID quando lo si fa in questo modo. Il lato negativo principale è che ci sarà un contenuto duplicato tra l'elemento legenda reale e l'elemento legenda falso.

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>

La leggenda DEVE essere un diretto discendente

Quando provi per la prima volta a risolvere il problema da solo, probabilmente proverai a farlo:

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

        ...

    </div>
</fieldset>

Scoprirai che funziona, e poi probabilmente passerai senza pensarci due volte.

Il problema è che mettere un wrapper div tra il fieldset e la legenda interrompe la relazione tra i due elementi. Questo rompe la semantica di fieldset / legenda.

Così facendo, hai sconfitto in primo luogo l'intero scopo di usare fieldset / legenda.

Inoltre, non ha molto senso usare un fieldset se non si dà a quel set di campi una legenda.


9

Nella mia esperienza, ho scoperto che né <fieldset>, né <button>, né è <textarea>possibile utilizzare display:flexo ereditare correttamente le proprietà.

Come altri hanno già detto, sono stati segnalati bug. Se desideri utilizzare la flexbox per controllare l'ordinamento (ad es. order:2), Dovrai avvolgere l'elemento in un div. Se vuoi che flexbox controlli il layout e le dimensioni effettivi, potresti prendere in considerazione l'uso di un div, invece del controllo di input (che puzza, lo so).


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

Potrebbe essere necessario utilizzare il gruppo di ruoli perché Firefox, Chrome e penso che Safari abbiano apparentemente un bug con i set di campi. Quindi il selettore nel CSS sarebbe semplicemente

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

Modifica: ecco alcuni problemi che stanno vivendo anche altre persone.

Numero 375693

Numero 262679


Questo è ancora un problema in Chrome 60.
evolutionxbox

Ancora qui in Chrome 66.
Brad,

Chrome 72 effettua il check-in.
danemacmillan,

Chrome 73 effettua il check-in
Michael Draper,

Chrome 75 effettua il check-in
xaddict

3

puoi aggiungere div aggiuntivi <fieldset>con i seguenti oggetti di scena:

flex-inner-wrapper {
  display: inherit;
  flex-flow: inherit;
  justify-content: inherit;
  align-items: inherit;
}

1
Non capisco i voti negativi. Questo è effettivamente corretto. Ma ricorda di mantenere l' <legend>elemento (se usato) al livello più alto <fieldset>dell'elemento per mantenerne l'uso come previsto ( Permitted content: An optional <legend> element, followed by flow content.- vedi developer.mozilla.org/en-US/docs/Web/HTML/Element/… )
Froxx

2
Non sono stato io, ma dovrei immaginare che il downvote abbia qualcosa a che fare con il non rispondere alla domanda. Non si trattava di trovare una soluzione alternativa, ma il comportamento di fieldsetse stesso.
Manngo,

Sì, potrebbe non rispondere direttamente alla domanda (che era un po 'filosofica), ma questa è una possibile soluzione per questo ridicolo bug.
Eric S. Bullington,

Down ha votato perché incoraggia a spezzare la semantica <legend>dell'elemento. Questo in primo luogo sconfigge lo scopo di utilizzare fieldset / legenda. Vedi la mia risposta qui: stackoverflow.com/a/59425373/1611058
Daniel Tonon

3

Per rispondere alla domanda originale: sì, è un bug, ma non era ben definito al momento della domanda.

Ora il rendering per fieldset è meglio definito: https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements

In Firefox e Safari, flexboxsu fieldsetora funziona. Non è ancora in Chromium. (Vedi https://bugs.chromium.org/p/chromium/issues/detail?id=375693 )

Vedi anche https://blog.whatwg.org/the-state-of-fieldset-interoperability per i miglioramenti apportati alle specifiche nel 2018.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.