altura da linha como uma porcentagem não funciona

87

Estou tendo um problema com a altura da linha que não consigo entender.

O código a seguir centralizará uma imagem em um div:

CSS

.bar {
    height: 800px;
    width: 100%;
    line-height:800px;
    background-color: #000;
    text-align: center; 
}

.bar img {
    vertical-align: middle;   
}

HTML

<div class="bar">
    <img src="http://27.media.tumblr.com/yHWA4oxH870ulxnoH7CkOSDR_500.jpg" alt="Foo Image" />
</div>

No entanto, se eu alterar a altura da linha para 100%, a altura da linha não terá efeito (ou pelo menos não se tornará 100% da div).

Exemplo de jsfiddle

Alguém sabe o que estou fazendo de errado?

Minha cabeça dói
fonte

Respostas:

194

line-height: 100%significa 100% do tamanho da fonte para esse elemento, não 100% de sua altura. Na verdade, a linha de altura é sempre relativa ao tamanho de fonte, não a altura, a menos que o seu valor utiliza uma unidade de comprimento absoluto ( px, pt, etc.).

BoltClock
fonte
3
Ah. São sempre os erros bobos que me pegam. Obrigado! Aceitarei sua resposta quando permitir.
Minha cabeça dói
1
Aparentemente, os autores das especificações pensaram erroneamente que ninguém iria querer definir o tamanho da fonte / altura da linha em relação à altura do elemento ...
Andy
1
@Andy: A boa (?) Notícia é que em breve isso será possível com o uso de variáveis ​​em cascata . Apenas alguns anos de espera ...
BoltClock
@BoltClock ah, legal! Isso vai ser bom. Obrigado por me avisar!
Andy
vh é uma exceção. No CSS3, se você definir como 100vh, ele funcionará como alguns desenvolvedores podem querer. Observe, porém, que ele não funciona em navegadores mais antigos que não suportam CSS3.
Philll_t
97

Sei que essa pergunta é antiga, mas descobri qual é a solução alternativa perfeita para mim.

Eu adiciono este css ao div que desejo centralizar:

div:before {
  content: "";
  display: inline-block;
  height: 100%;
  vertical-align: middle;
}

Isso funciona sempre e é limpo.

Edit: Apenas para fins de conclusão, eu uso scss e tenho um mixin útil que incluo em todos os pais que são filhos diretos que desejo centralizar verticalmente:

@mixin vertical-align($align: middle) {
  &:before {
    content: "";
    display: inline-block;
    height: 100%;
    vertical-align: $align;
    // you can add font-size 0 here and restore in the children to prevent
    // the inline-block white-space to mess the width of your elements
    font-size: 0;
  }
  & > * {
    vertical-align: $align;
    // although you need to know the font-size, because "inherit" is 0
    font-size: 14px;
  }
}

Explicação completa: div:beforeadicionará um elemento dentro do div, mas antes de qualquer um de seus filhos. Ao usar :beforeou :afterdevemos usar uma content:declaração, caso contrário, nada acontecerá, mas para o nosso propósito, o conteúdo pode estar vazio. Em seguida, dizemos ao elemento para ser tão alto quanto seu pai, desde que a altura de seu pai seja definida e este elemento seja pelo menos inline-block. vertical-aligndefine a posição vertical de self em relação aos pais, ao contrário de text-alignque funciona de maneira diferente.

A @mixindeclaração é para usuários sass e seria usada assim:

div {
    @include vertical-align(middle)
}
santiago arizti
fonte
Embora as outras respostas estejam todas corretas, esta é provavelmente a solução mais limpa e elegante para o problema acima.
mstation
Não é a resposta, mas muito útil!
Alex
Você poderia explicar o que está acontecendo lá em detalhes? Não consigo entender
Valdrinium
1
@Valdrinit vou editar a resposta com mais explicações
santiago arizti
36

Quando você usa a porcentagem como a altura da linha, ela não se baseia no contêiner div, mas sim no tamanho da fonte.

Locrizak
fonte
22

line-height: 100% seria uma maneira fácil de centralizar verticalmente os elementos, se fosse calculado em relação ao container, mas seria muito fácil, portanto não funciona.

Em vez disso, é apenas outra maneira de dizer a altura da linha: 1em (certo?)

Outra maneira de centralizar verticalmente um elemento seria:

.container {
     position:relative;
}
.center {
     position:absolute;
     top:0; left:0; bottom:0; right:0;
     margin: auto;
     /* for horiz left-align, try "margin: auto auto auto 0" */
}
Rolf
fonte
1
Isso não funciona para mim ... não tenho certeza se estou faltando alguma coisa.
clifgriffin
1
@clifgriffin, tente definir uma largura e altura fixas tanto no contêiner quanto no filho "central", certificando-se de que o filho seja menor que o contêiner. A criança deve acabar centralizada horizontalmente e verticalmente dentro do recipiente.
Rolf
22
isso seria muito fácil, portanto, não funciona +1 :-)
elipoultorak
@clifgriffin certifique-se de que o contêiner tenha a largura e altura corretas, você pode centralizar tudo em uma div do mesmo tamanho. Este foi o ajuste que tive que fazer.
David Carrigan
@ user3576887 "isso seria muito fácil, portanto, não funciona" é exatamente por que estou rejeitando isso - há uma boa razão para que não funcione da maneira que você gostaria aqui, e isso não deveria ser obscurecido para fins de entretenimento, crítica ou o que quer que seja.
TheThirdMan
11

pode não ser bonito, mas está funcionando e sua semântica;

<div class="bar" style="display: table; text-align: center;">
    <img style="display: table-cell; vertical-align: middle;" src="http://27.media.tumblr.com/yHWA4oxH870ulxnoH7CkOSDR_500.jpg" alt="Foo Image" />
</div>

display: table-cell dá a um elemento a capacidade única de alinhar verticalmente (pelo menos eu acho que é único)

Johan Olsson
fonte
Obrigado pela resposta, tentei seu código, mas não parece funcionar para mim.
Minha cabeça dói
hmm, isso é um pouco estranho; se você puder postar parte do seu código para que eu possa dar uma olhada mais de perto, talvez eu possa ajudar mais
Johan Olsson
Olsson - Acabei de colar seu código em um JSFiddle e não funcionou. Obrigado pela oferta de ajuda - mas posso me safar definindo uma altura de linha absoluta por enquanto. Se isso mudar, analisarei mais detalhadamente sua resposta. Obrigado novamente pela ajuda!
Minha cabeça dói
6

Essa é uma resposta muito tardia, no entanto, em navegadores modernos, supondo que o elemento pai também tenha 100% da altura da tela, você pode usar a vhunidade da janela de visualização. FIDDLE

line-height: 100vh;

Suporte de navegador

FelisPhasma
fonte
Um uso legítimo raro de vh em vez de%.
cytsunny de
1

Esta solução funciona no IE9 e superior. Primeiro, definimos a posição superior da criança em 50% (meio do pai). Então, usando uma translateregra, mude a criança para cima pela metade de sua altura real. O principal benefício é que não precisamos definir a altura da criança, ela é calculada dinamicamente pelo navegador. JSFiddle

.bar {
    height: 500px;
    text-align: center;
    background: green;
}
.bar img {
    position: relative;
    top: 50%;
    transform: translate(0, -50%);
}
Webars
fonte
1

Uma abordagem mais moderna é usar o flexbox para isso, é mais simples e limpo. No entanto, flexbox é um paradigma completamente diferente do que inline-block, floatou positioncostumava ser.

Para alinhar os itens dentro de .parentvocê, faça:

.parent {
  display: flex;
  align-items: center;
}

Isso é tudo. Filhos de flexpais são automaticamente convertidos em itens filhos flexíveis.

Você deve ler mais sobre o flexbox, um bom lugar para começar é esta folha de dicas: https://css-tricks.com/snippets/css/a-guide-to-flexbox/

santiago arizti
fonte
0

Você pode definir a altura da linha com base na altura desse elemento. Se a altura do elemento 200px significa que você precisa definir a altura da linha para 200px para centralizar o texto.

span {
  height: 200px;
  width: 200px; 
  border: 1px solid black;
  line-height: 200px; 
  display: block;
}
<span>Im vertically center</span>

Rajá
fonte