Como centralizar verticalmente o conteúdo com altura variável dentro de uma div?

158

Qual é a melhor maneira de centralizar verticalmente o conteúdo de uma div quando a altura do conteúdo é variável. No meu caso particular, a altura da div do contêiner é fixa, mas seria ótimo se houvesse uma solução que funcionasse nos casos em que o contêiner também tivesse uma altura variável. Além disso, eu adoraria uma solução sem, ou com muito pouco uso de hacks CSS e / ou marcação não semântica.

texto alternativo

jessegavin
fonte
o método nesse artigo desmorona no Safari (4.0.5): S
7
@ ripper234 Não exatamente, pois esta pergunta é sobre variável div altura
Rauli Rajande
9
Além disso, essa pergunta foi feita primeiro.
Gui Imamura

Respostas:

147

Basta adicionar

position: relative;
top: 50%;
transform: translateY(-50%);

para a div interna.

O que ele faz é mover a borda superior da div interna para a meia altura da div externa ( top: 50%;) e depois a div interna para a metade da altura ( transform: translateY(-50%)). Isso funcionará com position: absoluteou relative.

Lembre-se disso transforme translatetenha prefixos de fornecedores que não estejam incluídos por simplicidade.

Codepen: http://codepen.io/anon/pen/ZYprdb

BlackCetha
fonte
6
Apenas me perguntei por que isso funciona no Chrome e Firefox, mas não no Safari. Então notei que a maioria transformdas coisas relacionadas é -webkit-prefixada e agora funciona. Como lembrete: não se esqueça de adicionar o -webkit-prefixo também.
22615 miho
5
Use uma ferramenta como github.com/postcss/autoprefixer para manipular os prefixos para você.
Jamie Chong
6
Esta resposta deve estar no topo.
Jose Faeti
3
Isso deve ter muito mais votos positivos! A propósito, ele também funciona position: absolute, não é?
caw
4
Esse método tem um efeito colateral lamentável no Chrome - se o seu invólucro tiver um número ímpar de pixels, translateele renderizará tudo embaçado ao tentar manipular .5px de altura em tudo.
Keith
157

Esta parece ser a melhor solução que encontrei para esse problema, desde que o navegador suporte o ::beforepseudo elemento: CSS-Tricks: Centering in the Unknown .

Não requer nenhuma marcação extra e parece funcionar extremamente bem. Não pude usar o display: tablemétodo porque os tableelementos não obedecem à max-heightpropriedade.

.block {
  height: 300px;
  text-align: center;
  background: #c0c0c0;
  border: #a0a0a0 solid 1px;
  margin: 20px;
}

.block::before {
  content: '';
  display: inline-block;
  height: 100%; 
  vertical-align: middle;
  margin-right: -0.25em; /* Adjusts for spacing */

  /* For visualization 
  background: #808080; width: 5px;
  */
}

.centered {
  display: inline-block;
  vertical-align: middle;
  width: 300px;
  padding: 10px 15px;
  border: #a0a0a0 solid 1px;
  background: #f5f5f5;
}
<div class="block">
    <div class="centered">
        <h1>Some text</h1>
        <p>But he stole up to us again, and suddenly clapping his hand on my
           shoulder, said&mdash;"Did ye see anything looking like men going
           towards that ship a while ago?"</p>
    </div>
</div>

Fadi
fonte
3
Agora, isso é uma solução brilhante. Muito obrigado por postar isto!
Troy Alford
Como na outra resposta, essa seria muito melhor se descrevesse a abordagem e incluísse o código no link.
KatieK
3
+1, esta solução é realmente bastante engenhosa! Btw, você pode adicionar .block { white-space: nowrap; font-size: 0; line-height: 0; }e deixar a margem direita negativa no pseudo elemento, basta redefinir fs e lh em .centered ... assim você garante que o elemento seja posicionado corretamente mesmo que seja mais largo do que a viewport (e não tem que usar a margem negativa um pouco confusa).
Simon
@jessegavin - na sua opinião ... como se compara com a abordagem que você descreveu: stackoverflow.com/questions/396145/…
pulkitsinghal
1
Além disso, isso é interrompido quando o bloco externo do contêiner possui altura mínima em vez de altura.
Lincoln B
16

Isso é algo que eu precisei fazer várias vezes e uma solução consistente ainda exige que você adicione um pouco de marcação não semântica e alguns hacks específicos do navegador. Quando obtivermos suporte do navegador para o css 3, você terá sua centralização vertical sem pecar.

Para uma melhor explicação da técnica, você pode consultar o artigo do qual a adaptei , mas basicamente envolve adicionar um elemento extra e aplicar estilos diferentes no IE e navegadores compatíveis position:table\table-cellcom elementos que não são de tabela.

<div class="valign-outer">
    <div class="valign-middle">
        <div class="valign-inner">
            Excuse me. What did you sleep in your clothes again last night. Really. You're gonna be in the car with her. Hey, not too early I sleep in on Saturday. Oh, McFly, your shoe's untied. Don't be so gullible, McFly. You got the place fixed up nice, McFly. I have you're car towed all the way to your house and all you've got for me is light beer. What are you looking at, butthead. Say hi to your mom for me.
        </div>
    </div>
</div>

<style>
    /* Non-structural styling */
    .valign-outer { height: 400px; border: 1px solid red; }
    .valign-inner { border: 1px solid blue; }
</style>

<!--[if lte IE 7]>
<style>
    /* For IE7 and earlier */
    .valign-outer { position: relative; overflow: hidden; }
    .valign-middle { position: absolute; top: 50%; }
    .valign-inner { position: relative; top: -50% }
</style>
<![endif]-->
<!--[if gt IE 7]> -->
<style>
    /* For other browsers */
    .valign-outer { position: static; display: table; overflow: hidden; }
    .valign-middle { position: static; display: table-cell; vertical-align: middle; width: 100%; }
</style>

Existem várias maneiras (hacks) de aplicar estilos em conjuntos específicos de navegadores. Usei comentários condicionais, mas veja o artigo acima para ver duas outras técnicas.

Nota: Existem maneiras simples de obter a centralização vertical se você souber algumas alturas com antecedência, se estiver tentando centralizar uma única linha de texto ou em vários outros casos. Se você tiver mais detalhes, envolva-os, pois pode haver um método que não requer hacks no navegador ou marcação não semântica.

Atualização: Estamos começando a obter um melhor suporte do CSS3 ao navegador, trazendo tanto a caixa flexível quanto as transformações como métodos alternativos para obter a centralização vertical (entre outros efeitos). Consulte esta outra pergunta para obter mais informações sobre métodos modernos, mas lembre-se de que o suporte ao navegador ainda é superficial para CSS3.

Prestaul
fonte
Sim, encontrei esse artigo hoje e não consegui fazê-lo funcionar para minha situação específica. Talvez eu precise analisar isso mais a fundo.
jessegavin 12/09/08
Talvez você possa postar o código que está usando que não funciona?
Chris Marasti-Georg
Essa ainda é a melhor solução para esse problema?
precisa saber é o seguinte
Esse artigo parece não funcionar no Chrome 23, Firefox 16 e IE 9. Essa resposta parece ser uma solução melhor.
Fernando Correia
Não, esse artigo ainda funciona no Chrome e Firefox mais recentes a partir de 24 de fevereiro de 2013
OMA
9

Usando o seletor filho, peguei a resposta incrível de Fadi acima e reduzi-a a apenas uma regra de CSS que posso aplicar. Agora tudo o que preciso fazer é adicionar o contentCenterednome da classe aos elementos que quero centralizar:

.contentCentered {
  text-align: center;
}

.contentCentered::before {
  content: '';
  display: inline-block;
  height: 100%; 
  vertical-align: middle;
  margin-right: -.25em; /* Adjusts for spacing */
}

.contentCentered > * {
  display: inline-block;
  vertical-align: middle;
}
<div class="contentCentered">
  <div>
    <h1>Some text</h1>
    <p>But he stole up to us again, and suddenly clapping his hand on my
      shoulder, said&mdash;"Did ye see anything looking like men going
      towards that ship a while ago?"</p>
  </div>
</div>

Código bifurcado: http://codepen.io/dougli/pen/Eeysg

dougli
fonte
Legal. Obrigado por compartilhar. Uma nota de cautela é que o *seletor terá desempenho pior do que a resposta aceita. Pode não ser um problema, mas vale a pena notar. stevesouders.com/blog/2009/06/18/simplifying-css-selectors
jessegavin
Obrigado. Sim, provavelmente terá um desempenho pior, mas hoje em dia as regras CSS provavelmente não afetam muito as coisas. Provavelmente, podemos melhorar isso selecionando em > divvez disso. calendar.perfplanet.com/2011/…
dougli
Simples e ótimo. Funciona perfeitamente para mim.
Lovro
4

Melhor resultado para mim até agora:

div a ser centrado:

position: absolute;
top: 50%;
transform: translateY(-50%);
margin: 0 auto;
right: 0;
left: 0;
Leo Dimuccio
fonte
Funcionou como um encanto
m4heshd
3

Você pode usar a margem automática. Com o flex, o div também parece estar centralizado verticalmente.

body,
html {
  height: 100%;
  margin: 0;
}
.site {
  height: 100%;
  display: flex;
}
.site .box {
  background: #0ff;
  max-width: 20vw;
  margin: auto;
}
<div class="site">
  <div class="box">
    <h1>blabla</h1>
    <p>blabla</p>
    <p>blablabla</p>
    <p>lbibdfvkdlvfdks</p>
  </div>
</div>
Loïc G.
fonte
display: flex ainda é praticamente um recurso experimental; nenhum navegador suporta corretamente ainda
andreszs 06/10
1

Para mim, a melhor maneira de fazer isso é:

.container{
  position: relative;
}

.element{
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

A vantagem é não precisar explicitar a altura

Leandro Castro
fonte
0

Esta é a minha solução incrível para uma divaltura dinâmica (percentual).

CSS

.vertical_placer{
  background:red;
  position:absolute; 
  height:43%; 
  width:100%;
  display: table;
}

.inner_placer{  
  display: table-cell;
  vertical-align: middle;
  text-align:center;
}

.inner_placer svg{
  position:relative;
  color:#fff;
  background:blue;
  width:30%;
  min-height:20px;
  max-height:60px;
  height:20%;
}

HTML

<div class="footer">
    <div class="vertical_placer">
        <div class="inner_placer">
            <svg> some Text here</svg>
        </div>
    </div>
</div>  

Tente você mesmo.

user3432605
fonte
0

você pode usar a tela flexível, como no código abaixo:

.example{
  background-color:red;
  height:90px;
  width:90px;
  display:flex;
  align-items:center; /*for vertically center*/
  justify-content:center; /*for horizontally center*/
}
<div class="example">
    <h6>Some text</h6>
</div>

hassan yousefi
fonte