Chrome / Safari non riempiono il 100% dell'altezza del genitore flessibile


235

Voglio avere un menu verticale con un'altezza specifica.

Ogni bambino deve riempire l'altezza del genitore e avere un testo allineato al centro.

Il numero di bambini è casuale, quindi devo lavorare con valori dinamici.

Div .containercontiene un numero casuale di figli ( .item) che devono sempre riempire l'altezza del genitore. Per riuscirci ho usato la flexbox.

Per creare collegamenti con testo allineato al centro sto usando la display: table-celltecnica. Ma l'utilizzo di display da tavolo richiede un'altezza del 100%.

Il mio problema è che .item-inner { height: 100% }non funziona in webkit (Chrome).

  1. C'è una soluzione per questo problema?
  2. Oppure esiste una tecnica diversa per .itemriempire tutto l'altezza del genitore con il testo verticale allineato al centro?

Esempio qui jsFiddle, dovrebbe essere visualizzato in Firefox e Chrome

.container {
  height: 20em;
  display: flex;
  flex-direction: column;
  border: 5px solid black
}
.item {
  flex: 1;
  border-bottom: 1px solid white;
}
.item-inner {
  height: 100%;
  width: 100%;
  display: table;
}
a {
  background: orange;
  display: table-cell;
  vertical-align: middle;
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>



3
Questo non è specificamente rilevante per OP, ma potrebbe essere rilevante per i googler che arrivano qui per "l'altezza assoluta di visualizzazione del safari al 100% non funziona" o qualcosa di simile. Ho un elemento come questo all'interno di un contenitore flessibile e ho dovuto specificare top:0e left:0farlo apparire come previsto.
AlexMA,

1
@vsync non è stato ancora fissato: stackoverflow.com/questions/46226298/...
TylerH

Risposte:


408

Soluzione

Utilizzare contenitori flessibili nidificati.

Sbarazzarsi delle altezze percentuali. Sbarazzarsi delle proprietà della tabella. Sbarazzarsi di vertical-align. Evitare il posizionamento assoluto.Attacca con flexbox fino in fondo.

Applicare display: flexsull'elemento flessibile ( .item), rendendolo un contenitore flessibile. Questo imposta automaticamente align-items: stretch, che dice al bambino ( .item-inner) di espandere l'intera altezza del genitore.

Importante: rimuovere le altezze specificate dagli oggetti flessibili per far funzionare questo metodo. Se un bambino ha un'altezza specificata (ad es. height: 100%), Ignorerà la align-items: stretchprovenienza dal genitore. Perché l' stretchimpostazione predefinita funzioni, è necessario calcolare l'altezza del bambino auto (spiegazione completa ).

Prova questo (nessuna modifica a HTML):

jsFiddle demo


Spiegazione

Il mio problema è che .item-inner { height: 100% }non funziona in webkit (Chrome).

Non funziona perché stai utilizzando l'altezza percentuale in un modo non conforme all'implementazione tradizionale delle specifiche.

10.5 Altezza del contenuto: la heightproprietà

percentuale
Specifica un'altezza percentuale. La percentuale viene calcolata rispetto all'altezza del blocco contenitore della casella generata. Se l'altezza del blocco contenitore non è specificata in modo esplicito e questo elemento non è posizionato in modo assoluto, il valore viene calcolato su auto.

auto
L'altezza dipende dai valori di altre proprietà.

In altre parole, affinché l'altezza percentuale funzioni su un figlio in-flow, il genitore deve avere un'altezza impostata.

Nel tuo codice, il contenitore di livello superiore ha un'altezza definita: .container { height: 20em; }

Il contenitore di terzo livello ha un'altezza definita: .item-inner { height: 100%; }

Ma tra loro, il contenitore di secondo livello - .item- no ha un'altezza definita. Webkit lo considera come un collegamento mancante.

.item-innersta dicendo a Chrome: dammiheight: 100% . Chrome guarda al genitore ( .item) come riferimento e risponde: il 100% di cosa? Non vedo nulla (ignorando la flex: 1regola che c'è). Di conseguenza, si applica height: auto(altezza del contenuto), in conformità con le specifiche.

Firefox, d'altra parte, ora accetta l'altezza di flessione di un genitore come riferimento per l'altezza percentuale del bambino. IE11 e Edge accettano anche altezze di flessione.

Inoltre, Chrome accetterà flex-growcome riferimento padre adeguato se utilizzato insieme aflex-basis (qualsiasi valore numerico funziona ( autonon funzionerà), incluso flex-basis: 0). Al momento della stesura di questo documento, tuttavia, questa soluzione non funziona in Safari.


Quattro soluzioni

1. Specificare un'altezza su tutti gli elementi padre

Una soluzione affidabile per più browser consiste nello specificare un'altezza su tutti gli elementi padre. Ciò impedisce collegamenti mancanti, che i browser basati su Webkit considerano una violazione delle specifiche.

Si noti che min-heighte max-heightnon sono accettabili. Deve essere la heightproprietà.

Maggiori dettagli qui: utilizzo della heightproprietà CSS e dei valori percentuali

2. Posizionamento relativo e assoluto CSS

Applicare position: relativeal genitore e position: absoluteal bambino.

Taglia il bambino con height: 100%e width: 100%, o utilizzare le proprietà di offset: top: 0, right: 0, bottom: 0, left: 0.

Con il posizionamento assoluto, l'altezza percentuale funziona senza un'altezza specificata sul genitore.

3. Rimuovere contenitori HTML non necessari (consigliato)

C'è bisogno di due container in giro button? Perché non rimuovere .itemo .item-inner, o entrambi? Sebbene gli buttonelementi a volte falliscano come contenitori flessibili , possono essere oggetti flessibili. Prendi in considerazione l'idea di creare buttonun figlio .containero di .itemrimuovere un markup gratuito.

Ecco un esempio:

4. Contenitori Flex nidificati (consigliato)

Sbarazzarsi delle altezze percentuali. Sbarazzarsi delle proprietà della tabella. Sbarazzarsi di vertical-align. Evitare il posizionamento assoluto. Attacca con flexbox fino in fondo.

Applicare display: flexsull'elemento flessibile ( .item), rendendolo un contenitore flessibile. Questo imposta automaticamente align-items: stretch, che dice al bambino ( .item-inner) di espandere l'intera altezza del genitore.

Importante: rimuovere le altezze specificate dagli oggetti flessibili per far funzionare questo metodo. Se un bambino ha un'altezza specificata (ad es. height: 100%), Ignorerà la align-items: stretchprovenienza dal genitore. Perché l' stretchimpostazione predefinita funzioni, è necessario calcolare l'altezza del bambino auto (spiegazione completa ).

Prova questo (nessuna modifica a HTML):

jsFiddle


3
Ho risolto il mio problema usando l'altezza: auto
Alfrex92 del

solo alcune osservazioni tratte dal link esplicativo di questo grande post - "align-items: stretch" consente ai bambini flessibili di espandersi attraverso l'asse trasversale del contenitore - ovvero di allungare i bambini all'altezza, il contenitore flessibile dovrebbe avere una direzione flessibile come riga.
littlewhywhat

3
Posso confermare che l'utilizzo di contenitori flex nidificati funziona meglio. Abbiamo usato il flexbox in modo incoerente nel nostro menu. Invece di usare flex: 1 e display: flex su container parent abbiamo usato altezza: 100% in alcuni punti. Tutto ha funzionato come previsto dopo aver sostituito le definizioni corrispondenti. Grazie @Michael_B per il suggerimento! :)
flocbit

1
@JamesHarrington, CSS è cresciuto nel tempo ed è complesso ;-)
DerMike

Ogni soluzione dovrebbe essere una risposta diversa. Come posso votare una soluzione specifica in questo modo?
Jp_


10

Specificare un attributo flessibile per il contenitore ha funzionato per me:

.container {
    flex: 0 0 auto;
}

Questo assicura che l'altezza sia impostata e non cresca neanche.


6

Per Mobile Safari Esiste una correzione del browser. devi aggiungere -webkit-box per dispositivi iOS.

Ex.

display: flex;
display: -webkit-box;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
align-items: stretch;

se si utilizza la align-items: stretch;proprietà per l'elemento padre, rimuovere l' height : 100%elemento dall'elemento figlio.


2

Ho avuto un problema simile in iOS 8, 9 e 10 e le informazioni sopra non sono riuscite a risolverlo, tuttavia ho scoperto una soluzione dopo una giornata di lavoro su questo. Concesso che non funzionerà per tutti, ma nel mio caso i miei oggetti erano impilati in una colonna e avevano altezza 0 quando avrebbe dovuto essere l'altezza del contenuto. Il cambio del CSS in riga e a capo ha risolto il problema. Funziona solo se hai un singolo oggetto e sono impilati ma dato che mi ci è voluto un giorno per scoprirlo, ho pensato che avrei dovuto condividere la mia correzione!

.wrapper {
    flex-direction: column; // <-- Remove this line
    flex-direction: row; // <-- replace it with
    flex-wrap: wrap; // <-- Add wrapping
}

.item {
    width: 100%;
}

0

Ho avuto un bug simile, ma durante l'utilizzo di un numero fisso per l'altezza e non una percentuale. Era anche un contenitore flessibile all'interno del corpo (che non ha un'altezza specificata). Sembrava che su Safari, il mio container flessibile avesse un'altezza di 9 px per qualche motivo, ma in tutti gli altri browser mostrava l'altezza corretta di 100 px specificata nel foglio di stile.

Sono riuscito a farlo funzionare con l'aggiunta sia la heighte min-heightle proprietà alla classe CSS.

Quanto segue ha funzionato per me su Safari 13.0.4 e Chrome 79.0.3945.130:

.flex-container {
  display: flex;
  flex-direction: column;
  min-height: 100px;
  height: 100px;
}

Spero che questo ti aiuti!

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.