Chrome / Safari füllt nicht 100% der Höhe des Flex-Elternteils

235

Ich möchte ein vertikales Menü mit einer bestimmten Höhe haben.

Jedes Kind muss die Höhe des Elternteils ausfüllen und mittig ausgerichteten Text haben.

Die Anzahl der Kinder ist zufällig, daher muss ich mit dynamischen Werten arbeiten.

Div .containerenthält eine zufällige Anzahl von Kindern ( .item), die immer die Größe des Elternteils ausfüllen müssen. Um das zu erreichen, habe ich Flexbox verwendet.

Um Links mit Text zu erstellen, der auf die Mitte ausgerichtet ist, verwende ich display: table-cellTechnik. Für die Verwendung von Tabellenanzeigen muss jedoch eine Höhe von 100% verwendet werden.

Mein Problem ist, dass .item-inner { height: 100% }es im Webkit (Chrome) nicht funktioniert.

  1. Gibt es eine Lösung für dieses Problem?
  2. Oder gibt es eine andere Technik, mit der alle .itemdie Höhe des übergeordneten Elements mit vertikal zur Mitte ausgerichtetem Text füllen?

Beispiel hier jsFiddle, sollte in Firefox und Chrome angezeigt werden

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

Ricardo Castañeda
quelle
1
es wurde jetzt behoben - bugs.chromium.org/p/chromium/issues/detail?id=426898
vsync
3
Dies ist nicht speziell für OP relevant, könnte aber für Googler relevant sein, die hier landen, um "Safari-Anzeige absolute Höhe 100% funktioniert nicht" oder ähnliches. Ich habe ein solches Element in einem Flex-Container und musste angeben top:0und left:0es wie erwartet anzeigen lassen.
AlexMA
1
@vsync wurde noch nicht behoben: stackoverflow.com/questions/46226298/…
TylerH

Antworten:

408

Lösung

Verwenden Sie verschachtelte Flex-Container.

Prozentuale Höhen loswerden. Tabelleneigenschaften entfernen. Werde los vertical-align. Vermeiden Sie eine absolute Positionierung. Bleib einfach bis zum Ende bei der Flexbox.

Auf display: flexdas Flex-Element ( .item) auftragen und es zu einem Flex-Behälter machen. Dies wird automatisch festgelegt align-items: stretch, wodurch das Kind ( .item-inner) angewiesen wird, die volle Größe des Elternteils zu erweitern.

Wichtig: Entfernen Sie die angegebenen Höhen von den Flex-Elementen, damit diese Methode funktioniert. Wenn für ein Kind eine bestimmte Größe angegeben ist (z. B. height: 100%), wird das align-items: stretchKommen des Elternteils ignoriert . Damit die stretchStandardeinstellung funktioniert, muss die Größe des Kindes berechnet werden auto (vollständige Erklärung ).

Versuchen Sie dies (keine Änderungen an HTML):

jsFiddle-Demo


Erläuterung

Mein Problem ist, dass .item-inner { height: 100% }es im Webkit (Chrome) nicht funktioniert.

Es funktioniert nicht, weil Sie die prozentuale Höhe auf eine Weise verwenden, die nicht der herkömmlichen Implementierung der Spezifikation entspricht.

10.5 Inhaltshöhe: die heightEigenschaft

Prozent
Gibt eine prozentuale Höhe an. Der Prozentsatz wird in Bezug auf die Höhe des Blocks der generierten Box berechnet. Wenn die Höhe des enthaltenden Blocks nicht explizit angegeben wird und dieses Element nicht absolut positioniert ist, berechnet der Wert zu auto.

auto
Die Höhe hängt von den Werten anderer Eigenschaften ab.

Mit anderen Worten, damit die prozentuale Höhe für ein untergeordnetes Element funktioniert, muss das übergeordnete Element eine festgelegte Höhe haben.

In Ihrem Code hat der Container der obersten Ebene eine definierte Höhe: .container { height: 20em; }

Der Container der dritten Ebene hat eine definierte Höhe: .item-inner { height: 100%; }

Der Container der zweiten Ebene - .item- hat jedoch keine definierte Höhe. Webkit sieht dies als fehlendes Glied.

.item-innersagt Chrome: gib mirheight: 100% . Chrome sucht als .itemReferenz beim übergeordneten Element ( ) und antwortet: 100% von was? Ich sehe nichts (ignoriere die flex: 1Regel, die es gibt). Infolgedessen gilt es height: auto(Inhaltshöhe) gemäß Spezifikation.

Firefox hingegen akzeptiert jetzt die Flexhöhe eines Elternteils als Referenz für die prozentuale Größe des Kindes. IE11 und Edge akzeptieren ebenfalls Flexhöhen.

Außerdem akzeptiert Chrome flex-growals angemessene übergeordnete Referenz, wenn es in Verbindung mit verwendet wirdflex-basis (jeder numerische Wert funktioniert ( autowird nicht funktionieren ), einschließlich flex-basis: 0). Zum jetzigen Zeitpunkt schlägt diese Lösung in Safari jedoch fehl.


Vier Lösungen

1. Geben Sie für alle übergeordneten Elemente eine Höhe an

Eine zuverlässige browserübergreifende Lösung besteht darin, für alle übergeordneten Elemente eine Höhe anzugeben. Dies verhindert fehlende Links, die von Webkit-basierten Browsern als Verstoß gegen die Spezifikation angesehen werden.

Beachten Sie, dass min-heightund max-heightnicht akzeptabel sind. Es muss das heightEigentum sein.

Weitere Details hier: Arbeiten mit der CSS- heightEigenschaft und Prozentwerten

2. Relative und absolute CSS-Positionierung

Bewerben Sie position: relativesich beim Elternteil und position: absolutebeim Kind.

Größe des Kind mit height: 100%und width: 100%oder verwenden Sie die Offset - Eigenschaften: top: 0, right: 0, bottom: 0, left: 0.

Bei der absoluten Positionierung funktioniert die prozentuale Höhe ohne eine bestimmte Höhe auf dem übergeordneten Element.

3. Entfernen Sie unnötige HTML-Container (empfohlen)

Benötigen zwei Container button? Warum nicht entfernen .itemoder .item-inneroder beides? Obwohl buttonElemente manchmal als Flex-Container versagen , können sie Flex-Elemente sein. Erwägen Sie, buttonaus .containeroder ein Kind zu machen .itemund unbegründete Markierungen zu entfernen.

Hier ist ein Beispiel:

4. Verschachtelte Flex-Container (empfohlen)

Prozentuale Höhen loswerden. Tabelleneigenschaften entfernen. Werde los vertical-align. Vermeiden Sie eine absolute Positionierung. Bleib einfach bis zum Ende bei der Flexbox.

Auf display: flexdas Flex-Element ( .item) auftragen und es zu einem Flex-Behälter machen. Dies wird automatisch festgelegt align-items: stretch, wodurch das Kind ( .item-inner) angewiesen wird, die volle Größe des Elternteils zu erweitern.

Wichtig: Entfernen Sie die angegebenen Höhen von den Flex-Elementen, damit diese Methode funktioniert. Wenn für ein Kind eine bestimmte Größe angegeben ist (z. B. height: 100%), wird das align-items: stretchKommen des Elternteils ignoriert . Damit die stretchStandardeinstellung funktioniert, muss die Größe des Kindes berechnet werden auto (vollständige Erklärung ).

Versuchen Sie dies (keine Änderungen an HTML):

jsFiddle

Michael Benjamin
quelle
3
Ich habe mein Problem mit height
behoben
Nur eine Bemerkung aus dem Erklärungslink dieses großartigen Beitrags - "Align-Items: Stretch" - bewirkt, dass sich Flex-Kinder über die Querachse des Containers ausdehnen. Das heißt, Kinder werden auf die Höhe gedehnt. Der Flex-Container sollte eine Flex-Richtung haben als Reihe.
Littlewhywhat
3
Ich kann bestätigen, dass die Verwendung verschachtelter Flex-Container am besten funktioniert. Wir haben die Flexbox in unserem Menü uneinheitlich verwendet. Anstatt flex: 1 und display: flex für übergeordnete Container zu verwenden, haben wir an einigen Stellen height: 100% verwendet. Alles hat wie erwartet funktioniert, nachdem wir die entsprechenden Definitionen ersetzt haben. Danke @Michael_B für den Hinweis! :)
Flocbit
1
@ JamesHarrington, CSS ist im Laufe der Zeit gewachsen und komplex ;-)
DerMike
Jede Lösung sollte eine andere Antwort sein. Wie kann ich auf diese Weise in einer bestimmten Lösung abstimmen?
Jp_
14

Lösung: Entfernen Sie height: 100%in .item-Innen und fügen Sie display: flexin .item

Demo: https://codepen.io/tronghiep92/pen/NvzVoo

nghiepit
quelle
Danke, das hat mir geholfen. Dehnen sich flexible Kinder automatisch auf die Höhe ihres Containers? Funktioniert das deshalb?
Reece Kenney
@ReeceKenney, ja, zu deinen Fragen. Dies wird in meiner Antwort erklärt. Siehe Lösung 4.
Michael Benjamin
10

Das Angeben eines Flex-Attributs für den Container hat bei mir funktioniert:

.container {
    flex: 0 0 auto;
}

Dies stellt sicher, dass die Höhe eingestellt ist und auch nicht wächst.

huseyin39
quelle
6

Für Mobile Safari gibt es einen Browser-Fix. Sie müssen -webkit-box hinzufügen für iOS-Geräte .

Ex.

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

Wenn Sie die align-items: stretch;Eigenschaft für das übergeordnete Element verwenden, entfernen Sie das height : 100%aus dem untergeordneten Element.

Narasinghe
quelle
2

Ich hatte ein ähnliches Problem in iOS 8, 9 und 10 und die obigen Informationen konnten es nicht beheben, aber ich habe nach einem Tag Arbeit daran eine Lösung gefunden. Zugegeben, es wird nicht für alle funktionieren, aber in meinem Fall wurden meine Elemente in einer Spalte gestapelt und hatten eine Höhe von 0, wenn es sich um eine Inhaltshöhe handeln sollte. Das Problem wurde behoben, indem das CSS auf Zeile und Zeilenumbruch umgestellt wurde. Dies funktioniert nur, wenn Sie einen einzelnen Artikel haben und dieser gestapelt ist. Da ich jedoch einen Tag gebraucht habe, um dies herauszufinden, dachte ich, ich sollte meinen Fix teilen!

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

.item {
    width: 100%;
}
Designer023
quelle
0

Ich hatte einen ähnlichen Fehler, aber während ich eine feste Zahl für die Höhe und keinen Prozentsatz verwendete. Es war auch ein flexibler Behälter innerhalb des Körpers (der keine spezifizierte Höhe hat). Auf Safari schien mein Flex-Container aus irgendeinem Grund eine Höhe von 9 Pixel zu haben, aber in allen anderen Browsern wurde die im Stylesheet angegebene korrekte Höhe von 100 Pixel angezeigt.

Ich habe es geschafft, es zum Laufen zu bringen, indem ich der CSS-Klasse sowohl die heightals auch die min-heightEigenschaften hinzugefügt habe .

Folgendes hat für mich sowohl in Safari 13.0.4 als auch in Chrome 79.0.3945.130 funktioniert:

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

Hoffe das hilft!

Carlton Lindsay
quelle