I layout Flex / Grid non funzionano su elementi pulsante o fieldset


91

Sto cercando di centrare gli elementi interni di un <button>tag con flexbox justify-content: center. Ma Safari non li centra. Posso applicare lo stesso stile a qualsiasi altro tag e funziona come previsto (vedi il <p>tag). Solo il pulsante è allineato a sinistra.

Prova Firefox o Chrome e puoi vedere la differenza.

C'è uno stile di user agent che devo sovrascrivere? O qualsiasi altra soluzione a questo problema?

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>

E un jsfiddle: http://jsfiddle.net/z3sfwtn2/2/


Risposte:


132

Il problema

In alcuni browser l' <button>elemento non accetta modifiche al suo displayvalore, oltre al passaggio da blocke inline-block. Ciò significa che un <button>elemento non può essere un contenitore flessibile, una griglia o <table>uno.

Oltre a <button>elementi, si può trovare questo vincolo applicando <fieldset>e <legend>gli elementi, pure.

Vedere le segnalazioni di bug di seguito per maggiori dettagli.

Nota: sebbene non possano essere contenitori flessibili, gli <button>elementi possono essere elementi flessibili.


La soluzione

Esiste una soluzione alternativa semplice e facile per tutti i browser a questo problema:

Avvolgi il contenuto di buttonin a spane crea il spancontenitore flessibile.

HTML modificato ( buttoncontenuto a capo in 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 modificato (mirato span)

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

Demo rivista


Riferimenti / Segnalazioni di bug

Flexbox su un <button>blocca i contenuti ma non stabilisce un contesto di formattazione flessibile

Utente (Oriol Brufau): I figli del <button>sono bloccati, come impone la specifica flexbox. Tuttavia, <button>sembra stabilire un contesto di formattazione del blocco invece di uno flessibile.

Utente (Daniel Holbert): Questo è effettivamente ciò che richiede la specifica HTML. Diversi elementi contenitore HTML sono "speciali" ed effettivamente ignorano il loro displayvalore CSS in Gecko [a parte se è a livello di riga o a livello di blocco]. <button>è uno di questi. <fieldset>e lo <legend>sono anche.

Aggiunta del supporto per la visualizzazione: layout flessibile / griglia e colonne all'interno degli <button>elementi

Utente (Daniel Holbert):

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

Questo non è specifico per flexbox - es. Non rendiamo le barre di scorrimento se metti overflow:scrollun pulsante, e non la rendiamo come una tabella se ci metti display:tablesopra.

Facendo ancora un passo indietro, questo non è specifico per <button>. Considera <fieldset>e <table>che hanno anche un comportamento di rendering speciale.

E i vecchi elementi HTML come <button>e <table>e <fieldset>semplicemente non supportano i displayvalori personalizzati , se non per rispondere alla domanda di alto livello "questo elemento è a livello di blocco o inline", per far scorrere altri contenuti attorno all'elemento .

Vedi anche:


3
Capisco perché potrebbe non funzionare per <button>s, ma perché diavolo non funziona per <fieldset>nessuno dei due? Quell'elemento non dovrebbe essere considerato un normale elemento a livello di blocco valido per un contenitore flessibile?
fritzmg

3
@fritzmg. Concordato. La regola probabilmente preesiste alle tecnologie CSS3, come Flex e Grid, e dovrebbe essere rivalutata.
Michael Benjamin

Quindi vorremmo evitare che un pulsante venga utilizzato in modo improprio ... ma potremmo comunque utilizzare in modo improprio qualcos'altro e posizionarlo all'interno del pulsante. Sembra logico come il resto del web ...
Romain Vincent

1
@Michael_B Considerare l'aggiunta di un riferimento al testo effettivo in cui si effettua l'asserzione. Non c'è bisogno di rispondere al mio commento - se lo aggiungi al testo in cui fai l'affermazione ti darò un voto positivo.
mikemaccana

2
A divnon può essere figlio di a buttonperché, se ci pensi in HTML vecchia scuola, un elemento a livello di blocco non può essere figlio di un elemento a livello inline. Ma oggi, con HTML5, la risposta tecnicamente corretta è che un buttonelemento può accettare solo Phrasing Content . A spanrappresenta il contenuto della frase , ma a divno. A divrappresenta il contenuto del flusso . Maggiori dettagli
Michael Benjamin


1

A partire da Chrome 83, buttonora funziona come inline-grid/grid/inline-flex/flex, puoi vedere di più su questa nuova funzionalità qui

Ecco uno snippet (per coloro che utilizzano Chrome 83 e versioni successive)

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

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.