Chrome / Safari nie wypełnia 100% wysokości flex rodzica

235

Chcę mieć menu pionowe o określonej wysokości.

Każde dziecko musi wypełnić wysokość rodzica i mieć wyśrodkowany tekst.

Liczba dzieci jest losowa, więc muszę pracować z wartościami dynamicznymi.

Div .containerzawiera losową liczbę dzieci ( .item), które zawsze muszą wypełnić wysokość rodzica. Aby to osiągnąć, użyłem Flexboksa.

Do tworzenia linków z tekstem wyrównanym do środka używam display: table-celltechniki. Ale korzystanie z wyświetlaczy tabel wymaga użycia wysokości 100%.

Mój problem polega na tym, że .item-inner { height: 100% }nie działa w pakiecie internetowym (Chrome).

  1. Czy istnieje rozwiązanie tego problemu?
  2. Czy może istnieje inna technika .itempolegająca na tym, aby wszystkie wypełniały wysokość elementu nadrzędnego tekstem wyrównanym pionowo do środka?

Przykład tutaj jsFiddle, powinien być oglądany w Firefox i 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>

Ricardo Castañeda
źródło
1
zostało to naprawione - bugs.chromium.org/p/chromium/issues/detail?id=426898
vsync
3
Nie jest to szczególnie istotne dla OP, ale może być istotne dla pracowników Google, którzy wylądowali tutaj w celu „wyświetlania wysokości bezwzględnej safari 100% nie działa” lub czegoś podobnego. Mam element takiego elastycznego pojemnika wewnątrz i musiał określić top:0i left:0mieć wydaje się zgodnie z oczekiwaniami.
AlexMA
1
@vsync nie został jeszcze naprawiony: stackoverflow.com/questions/46226298/…
TylerH

Odpowiedzi:

408

Rozwiązanie

Użyj zagnieżdżonych kontenerów elastycznych.

Pozbądź się wysokości procentowych. Pozbądź się właściwości tabeli. Pozbyć się vertical-align. Unikaj absolutnego pozycjonowania. Po prostu trzymaj się Flexboksa do końca.

Zastosuj display: flexdo elementu flex ( .item), dzięki czemu będzie to elastyczny pojemnik. To automatycznie ustawia align-items: stretch, co każe child ( .item-inner) rozwinąć pełną wysokość rodzica.

Ważne: Usuń określone wysokości z elementów elastycznych, aby ta metoda działała. Jeśli dziecko ma określoną wysokość (np. height: 100%), Wówczas zignoruje align-items: stretchpochodzenie od rodzica. Aby stretchdomyślny działał, wzrost dziecka musi być obliczony na auto (pełne wyjaśnienie ).

Spróbuj tego (bez zmian w HTML):

Demo jsFiddle


Wyjaśnienie

Mój problem polega na tym, że .item-inner { height: 100% }nie działa w pakiecie internetowym (Chrome).

To nie działa, ponieważ używasz wysokości procentowej w sposób niezgodny z tradycyjną implementacją specyfikacji.

10.5 Wysokość treści: heightwłaściwość

procent
Określa procentową wysokość. Procent jest obliczany w odniesieniu do wysokości wygenerowanego bloku zawierającego blok. Jeśli wysokość zawierającego blok nie jest wyraźnie określona, ​​a ten element nie jest pozycjonowany bezwzględnie, wartość zostanie obliczona na auto.

auto
Wysokość zależy od wartości innych właściwości.

Innymi słowy, aby procentowa wysokość działała na potomku w przepływie, rodzic musi mieć ustawioną wysokość.

W kodzie kontener najwyższego poziomu ma zdefiniowaną wysokość: .container { height: 20em; }

Kontener trzeciego poziomu ma określoną wysokość: .item-inner { height: 100%; }

Ale między nimi kontener drugiego poziomu - .item- nie ma określonej wysokości. Webkit uważa to za brakujący link.

.item-innermówi Chrome: daj miheight: 100% . Chrome szuka informacji o obiekcie nadrzędnym ( .item) i odpowiada: 100% czego? Nic nie widzę (ignorując istniejącą flex: 1regułę). W rezultacie ma zastosowanie height: auto(wysokość zawartości), zgodnie ze specyfikacją.

Z drugiej strony Firefox akceptuje teraz wysokość flex rodzica jako odniesienie do procentowej wysokości dziecka. IE11 i Edge również akceptują wysokości elastyczności.

Ponadto Chrome zaakceptuje flex-growjako odpowiednie odniesienie nadrzędne, jeśli zostanie użyte w połączeniu zflex-basis (każda wartość liczbowa działa ( autonie będzie), w tym flex-basis: 0). Jednak w chwili pisania tego tekstu to rozwiązanie nie działa w przeglądarce Safari.


Cztery rozwiązania

1. Określ wysokość wszystkich elementów nadrzędnych

Niezawodnym rozwiązaniem dla wielu przeglądarek jest określenie wysokości wszystkich elementów nadrzędnych. Zapobiega to brakującym linkom, które przeglądarki oparte na Webkit uznają za naruszenie specyfikacji.

Pamiętaj, że min-heighti max-heightnie są akceptowane. To musi być heightwłasność.

Więcej informacji tutaj: Praca z heightwłaściwością CSS i wartościami procentowymi

2. Pozycjonowanie względne i absolutne CSS

Zastosuj position: relativedo rodzica i position: absolutedziecka.

Rozmiar dziecko z height: 100%i width: 100%lub użyj offsetowych właściwości: top: 0, right: 0, bottom: 0,left: 0 .

W przypadku pozycjonowania bezwzględnego wysokość procentowa działa bez określonej wysokości nadrzędnej.

3. Usuń niepotrzebne pojemniki HTML (zalecane)

Czy w pobliżu są potrzebne dwa pojemniki button? Dlaczego nie usunąć .itemlub .item-inner, albo jedno i drugie? Chociaż buttonelementy czasami zawodzą jako elastyczne kontenery , mogą być elastycznymi przedmiotami. Rozważyć buttondzieckiem .containeralbo .itemi usuwanie nieodpłatne Mark-up.

Oto przykład:

4. Zagnieżdżone pojemniki Flex (zalecane)

Pozbądź się wysokości procentowych. Pozbądź się właściwości tabeli. Pozbyć się vertical-align. Unikaj absolutnego pozycjonowania. Po prostu trzymaj się Flexboksa do końca.

Zastosuj display: flexdo elementu flex ( .item), dzięki czemu będzie to elastyczny pojemnik. To automatycznie ustawia align-items: stretch, co każe child ( .item-inner) rozwinąć pełną wysokość rodzica.

Ważne: Usuń określone wysokości z elementów elastycznych, aby ta metoda działała. Jeśli dziecko ma określoną wysokość (np. height: 100%), Wówczas zignoruje align-items: stretchpochodzenie od rodzica. Aby stretchdomyślny działał, wzrost dziecka musi być obliczony na auto (pełne wyjaśnienie ).

Spróbuj tego (bez zmian w HTML):

jsFiddle

Michael Benjamin
źródło
3
Rozwiązałem
tylko kilka uwag zaczerpniętych z linku wyjaśniającego tego wspaniałego postu - „wyrównaj-elementy: rozciągnij” powoduje, że dzieci elastyczne rozciągają się w poprzek osi poprzecznej pojemnika - to znaczy rozciągają dzieci na wysokość, elastyczny pojemnik powinien mieć kierunek elastyczny jako rząd.
mało co
3
Mogę potwierdzić, że użycie zagnieżdżonych kontenerów elastycznych działa najlepiej. W naszym menu niekonsekwentnie korzystaliśmy z Flexboksa. Zamiast używać flex: 1 i display: flex na pojemnikach nadrzędnych, w niektórych miejscach zastosowaliśmy wysokość: 100%. Wszystko działało zgodnie z oczekiwaniami po zastąpieniu odpowiednich definicji. Dzięki @Michael_B za podpowiedź! :)
flocbit
1
@JamesHarrington, CSS rozwijał się z czasem i jest złożony ;-)
DerMike
Każde rozwiązanie powinno być inną odpowiedzią. Jak mogę w ten sposób głosować na konkretne rozwiązanie?
Jp_
14

Rozwiązanie: Wyjmij height: 100%w .Item-wewnętrzna i dodać display: flexw .Item

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

nghiepit
źródło
Dzięki, pomogło mi to. Czy dzieci Flex są automatycznie rozciągane na wysokość pojemnika? Czy to dlatego działa?
Reece Kenney
@ReeceKenney, tak, na twoje pytania. Wyjaśnia to moja odpowiedź. Zobacz rozwiązanie nr 4.
Michael Benjamin
10

Określenie atrybutu flex dla kontenera zadziałało dla mnie:

.container {
    flex: 0 0 auto;
}

Dzięki temu wysokość jest ustawiona i nie rośnie.

huseyin39
źródło
6

Mobile Safari Jest poprawka do przeglądarki. musisz dodać -webkit-box dla urządzeń iOS.

Dawny.

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

jeśli używasz align-items: stretch;właściwości elementu nadrzędnego, usuń height : 100%element podrzędny.

Narasinghe
źródło
2

Miałem podobny problem w iOS 8, 9 i 10 i powyższe informacje nie mogły go naprawić, jednak znalazłem rozwiązanie po całym dniu pracy nad tym. To prawda, że ​​nie będzie działać dla wszystkich, ale w moim przypadku moje przedmioty były ułożone w kolumnie i miały 0 wysokości, kiedy powinna była wysokość. Przełączenie css na wiersz i zawijanie rozwiązało problem. Działa to tylko wtedy, gdy masz jeden przedmiot i są one ułożone w stos, ale ponieważ zajęło mi to dzień, aby się o tym przekonać, pomyślałem, że powinienem podzielić się swoją poprawką!

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

.item {
    width: 100%;
}
Designer023
źródło
0

Miałem podobny błąd, ale podczas używania stałej liczby na wysokość, a nie procent. Był to również elastyczny pojemnik w ciele (który nie ma określonej wysokości). Okazało się, że w Safari mój elastyczny pojemnik z jakiegoś powodu miał wysokość 9 pikseli, ale we wszystkich innych przeglądarkach wyświetlał prawidłową wysokość 100 pikseli określoną w arkuszu stylów.

Udało mi się go uruchomić, dodając zarówno właściwości heighti min-heightdo klasy CSS.

Dla mnie zarówno Safari 13.0.4, jak i Chrome 79.0.3945.130:

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

Mam nadzieję że to pomoże!

Carlton Lindsay
źródło