O Chrome / Safari não preenche 100% da altura do pai flexível

235

Eu quero ter um menu vertical com uma altura específica.

Cada filho deve preencher a altura dos pais e ter um texto alinhado ao meio.

O número de filhos é aleatório, então eu tenho que trabalhar com valores dinâmicos.

Div .containercontém um número aleatório de filhos ( .item) que sempre precisam preencher a altura do pai. Para conseguir isso, usei o flexbox.

Para criar links com o texto alinhado ao meio, estou usando a display: table-celltécnica. Mas o uso de exibições de tabela exige o uso de uma altura de 100%.

Meu problema é que .item-inner { height: 100% }não está funcionando no webkit (Chrome).

  1. Existe uma correção para esse problema?
  2. Ou existe uma técnica diferente para fazer com que todos .itempreencham a altura dos pais com o texto alinhado na vertical ao meio?

Exemplo aqui jsFiddle, deve ser visualizado no 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>

Ricardo Castañeda
fonte
3
Isso não é especificamente relevante para o OP, mas pode ser relevante para os googlers que chegam aqui para "a altura absoluta do safári mostra que 100% não funciona" ou algo semelhante. Eu tenho um elemento como este dentro de um contêiner flex e tive que especificar top:0e left:0fazê-lo aparecer conforme o esperado.
AlexMA #
1
@vsync ainda não foi corrigido: stackoverflow.com/questions/46226298/…
TylerH

Respostas:

408

Solução

Use contêineres flexíveis aninhados.

Livre-se das alturas percentuais. Livre-se das propriedades da tabela. Livre-se vertical-align. Evite posicionamento absoluto. Basta ficar com o flexbox todo o caminho.

Aplique display: flexao item flex ( .item), tornando-o um contêiner flex. Isso define automaticamente align-items: stretch, o que instrui o filho ( .item-inner) a expandir toda a altura do pai.

Importante: Remova as alturas especificadas dos itens flexíveis para que este método funcione. Se uma criança tiver uma altura especificada (por exemplo height: 100%), ela ignorará a align-items: stretchvinda dos pais. Para que o stretchpadrão funcione, a altura da criança deve ser calculada como auto (explicação completa ).

Tente isso (sem alterações no HTML):

Demonstração do jsFiddle


Explicação

Meu problema é que .item-inner { height: 100% }não está funcionando no webkit (Chrome).

Não está funcionando porque você está usando a porcentagem de altura de uma maneira que não está de acordo com a implementação tradicional da especificação.

10.5 Altura do conteúdo: a heightpropriedade

porcentagem
Especifica uma altura percentual. A porcentagem é calculada em relação à altura do bloco contendo a caixa gerada. Se a altura do bloco que contém não for especificada explicitamente e esse elemento não estiver absolutamente posicionado, o valor será calculado como auto.

auto
A altura depende dos valores de outras propriedades.

Em outras palavras, para que a altura percentual funcione em um filho em fluxo, o pai deve ter uma altura definida.

No seu código, o contêiner de nível superior tem uma altura definida: .container { height: 20em; }

O contêiner de terceiro nível tem uma altura definida: .item-inner { height: 100%; }

Mas entre eles, o contêiner de segundo nível - .item- não tem uma altura definida. Webkit vê isso como um link ausente.

.item-innerestá dizendo ao Chrome: me dêheight: 100% . O Chrome procura referência nos pais ( .item) e responde: 100% do que? Não vejo nada (ignorando a flex: 1regra que existe). Como resultado, aplica-se height: auto(altura do conteúdo), de acordo com as especificações.

O Firefox, por outro lado, agora aceita a altura flexível de um pai como referência para a porcentagem de altura da criança. O IE11 e o Edge também aceitam alturas flexíveis.

Além disso, o Chrome aceitará flex-growcomo uma referência pai adequada se usado em conjunto comflex-basis (qualquer valor numérico funciona ( autonão funcionará), inclusive flex-basis: 0). No momento da redação deste artigo, no entanto, essa solução falha no Safari.


Quatro Soluções

1. Especifique uma altura em todos os elementos pai

Uma solução confiável entre navegadores é especificar uma altura em todos os elementos pai. Isso evita a falta de links, que os navegadores baseados no Webkit consideram uma violação das especificações.

Observe que min-heighte max-heightnão são aceitáveis. Deve ser a heightpropriedade.

Mais detalhes aqui: Trabalhando com a heightpropriedade CSS e os valores percentuais

2. Posicionamento relativo e absoluto do CSS

Aplique position: relativeaos pais e position: absoluteà criança.

Tamanho da criança com height: 100%e width: 100%ou use as propriedades de deslocamento: top: 0, right: 0, bottom: 0, left: 0.

Com o posicionamento absoluto, a altura percentual funciona sem uma altura especificada no pai.

3. Remova os contêineres HTML desnecessários (recomendado)

Há necessidade de dois contêineres por aí button? Por que não remover .itemou .item-inner, ou ambos? Embora os buttonelementos às vezes falhem como contêineres flexíveis , eles podem ser itens flexíveis. Considere criar buttonum filho .containerou .itemremover uma marcação gratuita.

Aqui está um exemplo:

4. Recipientes flexíveis aninhados (recomendado)

Livre-se das alturas percentuais. Livre-se das propriedades da tabela. Livre-se vertical-align. Evite posicionamento absoluto. Basta ficar com o flexbox todo o caminho.

Aplique display: flexao item flex ( .item), tornando-o um contêiner flex. Isso define automaticamente align-items: stretch, o que instrui o filho ( .item-inner) a expandir toda a altura do pai.

Importante: Remova as alturas especificadas dos itens flexíveis para que este método funcione. Se uma criança tiver uma altura especificada (por exemplo height: 100%), ela ignorará a align-items: stretchvinda dos pais. Para que o stretchpadrão funcione, a altura da criança deve ser calculada como auto (explicação completa ).

Tente isso (sem alterações no HTML):

jsFiddle

Michael Benjamin
fonte
3
Corrigi
apenas algumas observações tiradas do link de explicação deste ótimo post - "align-items: stretch" faz com que as crianças flex se expandam através do eixo transversal do contêiner - ou seja, para esticar as crianças até a altura, o contêiner flex deve ter a direção flex como linha.
littlewhywhat
3
Posso confirmar que o uso de contêineres flexíveis aninhados funciona melhor. Usamos o flexbox inconsistentemente em nosso menu. Em vez de usar flex: 1 e display: flex em contêineres pai, usamos height: 100% em alguns lugares. Tudo funcionou como esperado depois que substituímos as definições correspondentes. Obrigado @Michael_B pela dica! :)
flocbit 27/05
1
@JamesHarrington, CSS tem crescido ao longo do tempo e é complexo ;-)
DerMike
Cada solução deve ser uma resposta diferente. Como posso votar em uma solução específica dessa maneira?
Jp_
14

Solução: Remover height: 100%em .item-interior e adicionar display: flexem .item

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

nghiepit
fonte
Obrigado, isso me ajudou. As crianças flex se alongam automaticamente até a altura de seu contêiner? É por isso que isso funciona?
Reece Kenney
@ReeceKenney, sim, às suas perguntas. Isso é explicado na minha resposta. Veja a solução 4.
Michael Benjamin
10

A especificação de um atributo flex para o contêiner funcionou para mim:

.container {
    flex: 0 0 auto;
}

Isso garante que a altura seja definida e também não cresça.

huseyin39
fonte
6

Para o Mobile Safari Há uma correção no navegador. você precisa adicionar -webkit-box para dispositivos 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 você estiver usando a align-items: stretch;propriedade do elemento pai, remova o height : 100%do elemento filho.

Narasinghe
fonte
2

Eu tive um problema semelhante no iOS 8, 9 e 10 e as informações acima não puderam corrigi-lo, no entanto, descobri uma solução depois de um dia trabalhando nisso. Concedido que não funcionará para todos, mas, no meu caso, meus itens foram empilhados em uma coluna e tinham 0 altura quando deveria ter sido a altura do conteúdo. Mudar o css para ser linha e quebra resolveu o problema. Isso só funciona se você tiver um único item e eles estiverem empilhados, mas como levei um dia para descobrir isso, pensei em compartilhar minha correção!

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

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

Eu tive um bug semelhante, mas enquanto usava um número fixo para altura e não uma porcentagem. Era também um contêiner flexível dentro do corpo (que não possui altura especificada). Parecia que, no Safari, meu container flexível tinha uma altura de 9px por algum motivo, mas em todos os outros navegadores, ele exibia a altura correta de 100px especificada na folha de estilo.

Consegui fazê-lo funcionar adicionando as propriedades heighte min-heightà classe CSS.

O seguinte funcionou para mim no Safari 13.0.4 e no Chrome 79.0.3945.130:

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

Espero que isto ajude!

Carlton Lindsay
fonte