Alinhar verticalmente uma imagem dentro de uma div com altura responsiva

135

Eu tenho o código a seguir que configura um contêiner que tem uma altura que muda com a largura quando o navegador é redimensionado (para manter uma proporção quadrada).

HTML

<div class="responsive-container">
    <div class="dummy"></div>
    <div class="img-container">
        <IMG HERE>
    </div>
</div>

CSS

.responsive-container {
    position: relative;
    width: 100%;
    border: 1px solid black;
}

.dummy {
    padding-top: 100%; /* forces 1:1 aspect ratio */
}

.img-container {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

Como alinhar verticalmente o IMG dentro do contêiner? Todas as minhas imagens têm alturas variáveis ​​e o contêiner não pode ter uma altura fixa / altura da linha porque é responsiva ... Por favor, ajude!

user1794295
fonte
1
Aqui está uma solução flexbox simples: stackoverflow.com/a/31977476/3597276
Michael Benjamin

Respostas:

381

Aqui está uma técnica para alinhar elementos embutidos dentro de um pai , horizontal e verticalmente ao mesmo tempo:

Alinhamento vertical

1) Nesta abordagem, criamos um inline-block(pseudo-) elemento como o primeiro (ou último) filho do pai e definimos sua heightpropriedade 100%para assumir toda a altura do pai .

2) Além disso, a adição vertical-align: middlemantém os elementos embutidos (-bloco) no meio do espaço da linha. Então, adicionamos essa declaração CSS ao primeiro filho e ao nosso elemento (a imagem ).

3) Finalmente, para remover o caractere de espaço em branco entre os elementos embutidos (-bloco) , poderíamos definir o tamanho da fonte do pai como zero por font-size: 0;.

Nota: usei a técnica de substituição de imagem de Nicolas Gallagher a seguir.

Quais são os benefícios?

  • O contêiner ( pai ) pode ter dimensões dinâmicas.
  • Não há necessidade de especificar explicitamente as dimensões do elemento de imagem.

  • Podemos facilmente usar essa abordagem para alinhar um <div>elemento verticalmente também; que pode ter um conteúdo dinâmico (altura e / ou largura). Mas observe que você deve redefinir a font-sizepropriedade do divpara exibir o texto interno. Demo Online .

<div class="container">
    <div id="element"> ... </div>
</div>
.container {
    height: 300px;
    text-align: center;  /* align the inline(-block) elements horizontally */
    font: 0/0 a;         /* remove the gap between inline(-block) elements */
}

.container:before {    /* create a full-height inline block pseudo=element */
    content: ' ';
    display: inline-block;
    vertical-align: middle;  /* vertical alignment of the inline element */
    height: 100%;
}

#element {
    display: inline-block;
    vertical-align: middle;  /* vertical alignment of the inline element */
    font: 16px/1 Arial sans-serif;        /* <-- reset the font property */
}

A saída

Alinhar verticalmente um elemento em seu contêiner

Container Responsivo

Esta seção não responderá à pergunta, pois o OP já sabe como criar um contêiner responsivo. No entanto, vou explicar como isso funciona.

Para fazer a altura de um elemento de contêiner mudar com sua largura (respeitando a proporção), poderíamos usar um valor percentual para a paddingpropriedade superior / inferior .

Um valor percentual no preenchimento / margens superior / inferior é relativo à largura do bloco que o contém.

Por exemplo:

.responsive-container {
  width: 60%;

  padding-top: 60%;    /* 1:1 Height is the same as the width */
  padding-top: 100%;   /* width:height = 60:100 or 3:5        */
  padding-top: 45%;    /* = 60% * 3/4 , width:height =  4:3   */
  padding-top: 33.75%; /* = 60% * 9/16, width:height = 16:9   */
}

Aqui está a demonstração online . Comente as linhas da parte inferior e redimensione o painel para ver o efeito.

Além disso, poderíamos aplicar a paddingpropriedade a um filho fictício ou :before/ :afterpseudoelemento para obter o mesmo resultado. Mas observe que, nesse caso, o valor percentual ativado paddingé relativo à largura do .responsive-containerpróprio.

<div class="responsive-container">
  <div class="dummy"></div>
</div>
.responsive-container { width: 60%; }

.responsive-container .dummy {
  padding-top: 100%;    /*  1:1 square */
  padding-top: 75%;     /*  w:h =  4:3 */
  padding-top: 56.25%;  /*  w:h = 16:9 */
}

Demo # 1 .
Demo # 2 (usando :afterpseudo-elemento)

Adicionando o conteúdo

O uso da padding-toppropriedade causa um enorme espaço na parte superior ou inferior do conteúdo, dentro do contêiner .

Para corrigir isso, temos que envolva o conteúdo por um elemento de invólucro, remover esse elemento de documento fluxo normal usando posicionamento absoluto e, finalmente, expandir o invólucro (bu usando top, right, bottome leftpropriedades) para preencher todo o espaço de seu pai, o recipiente .

Aqui vamos nós:

.responsive-container {
  width: 60%;
  position: relative;
}

.responsive-container .wrapper {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}

Aqui está a demonstração online .


Reunindo todos

<div class="responsive-container">
  <div class="dummy"></div>

  <div class="img-container">
    <img src="http://placehold.it/150x150" alt="">
  </div>
</div>
.img-container {
  text-align:center; /* Align center inline elements */
  font: 0/0 a;       /* Hide the characters like spaces */
}

.img-container:before {
  content: ' ';
  display: inline-block;
  vertical-align: middle;
  height: 100%;
}

.img-container img {
  vertical-align: middle;
  display: inline-block;
}

Aqui está a demonstração de trabalho .

Obviamente, você pode evitar o uso de ::beforepseudoelemento para compatibilidade do navegador e criar um elemento como o primeiro filho do .img-container:

<div class="img-container">
    <div class="centerer"></div>
    <img src="http://placehold.it/150x150" alt="">
</div>
.img-container .centerer {
  display: inline-block;
  vertical-align: middle;
  height: 100%;
}

DEMO ATUALIZADO .

Usando max-*propriedades

Para manter a imagem dentro da caixa em largura menor, você pode definir max-heighte max-widthpropriedade na imagem:

.img-container img {
    vertical-align: middle;
    display: inline-block;
    max-height: 100%;  /* <-- Set maximum height to 100% of its parent */
    max-width: 100%;   /* <-- Set maximum width to 100% of its parent */
}

Aqui está a demo atualizada .

Hashem Qolami
fonte
1
Oi Hashem, muito obrigado pela sua resposta - isso funcionou como mágica para navegadores de desktop, mesmo ao redimensionar para larguras menores. Infelizmente, porém, as imagens estão fora de posição, abaixo da div do contêiner, no celular (Android v2.3.5). Alguma idéia de uma correção para isso?
user1794295
3
@ user1794295 Eu testei esse violino em três dispositivos Android com Android v2.3 (Galaxy S II, Galaxy Note, Motorola Droid 4) via browserstack.com, tudo funciona como eu esperava.Você pode encontrar o resultado aqui: browserstack.com/screenshots / ... . Forneça uma captura de tela ou faça um teste específico do seu problema. Ajudarei o máximo possível.
Hashem Qolami
1
Olá, aqui estão algumas capturas de tela: browserstack.com/screenshots/… - como você pode ver em dispositivos menores (por exemplo, Xperia, LG Nexus 4), as imagens aparecem abaixo dos contêineres ... o que está acontecendo ?!
user1794295
3
@HashemQolami Esta é a coisa mais incrível sobre CSS, desde que comecei a criar sites :).
Alexander Solonik
1
Obrigado por font-size: 0;!
Johannes Liebermann
47

Com o flexbox, isso é fácil:

FIDDLE

Basta adicionar o seguinte ao contêiner de imagem:

.img-container {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex; /* add */
    justify-content: center; /* add to align horizontal */
    align-items: center; /* add to align vertical */
}
Danield
fonte
2
Esta solução funciona e é muito mais elegante no meu caso. CSS3 Flex é incrível!
Daniel Bonnell
2
Não funciona no Safari :( Acho que o problema é flexível
yennefer
1
@yennefer para uso safari -webkit-prefixo, ou tentar uma biblioteca como prefixfree.js :)
QUB3X
Isso não funciona quando a altura do contêiner é responsiva (em porcentagem).
jenlampton
1
Solução perfeita!
Nirus
16

Use este css, pois você já possui a marcação:

.img-container {
    position: absolute;
    top: 50%;
    left: 50%;
}

.img-container > img {
  margin-top:-50%;
  margin-left:-50%;  
}

Aqui está um JsBin funcional: http://jsbin.com/ihilUnI/1/edit

Essa solução funciona apenas para imagens quadradas (porque um valor percentual da margem superior depende da largura do contêiner, não da altura). Para imagens de tamanho aleatório, você pode fazer o seguinte:

.img-container {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%); /* add browser-prefixes */
}

Solução de trabalho JsBin: http://jsbin.com/ihilUnI/2/edit

Tibos
fonte
Desculpe, não está funcionando para mim - isso está apenas reduzindo o tamanho das imagens para metade da largura do contêiner.
user1794295
2
Não vejo como isso pode acontecer com o CSS que mencionei. Forneça uma amostra de trabalho que eu possa ver para melhorar minha resposta. PS: Eu também forneci outra solução :)
Tibos
11

Você pode centralizar uma imagem, horizontal e verticalmente, usando margin: autoum posicionamento absoluto. Além disso:

  1. É possível abandonar a marcação extra usando pseudo-elementos.
  2. É possível exibir a parte do meio das imagens GRANDES usando valores negativos à esquerda, superior, direito e inferior.

.responsive-container {
  margin: 1em auto;
  min-width: 200px;       /* cap container min width */
  max-width: 500px;       /* cap container max width */
  position: relative;     
  overflow: hidden;       /* crop if image is larger than container */
  background-color: #CCC; 
}
.responsive-container:before {
  content: "";            /* using pseudo element for 1:1 ratio */
  display: block;
  padding-top: 100%;
}
.responsive-container img {
  position: absolute;
  top: -999px;            /* use sufficiently large number */
  bottom: -999px;
  left: -999px;
  right: -999px;
  margin: auto;           /* center horizontally and vertically */
}
<p>Note: images are center-cropped on &lt;400px screen width.
  <br>Open full page demo and resize browser.</p>
<div class="responsive-container">
  <img src="http://lorempixel.com/400/400/sports/9/">
</div>
<div class="responsive-container">
  <img src="http://lorempixel.com/400/200/sports/8/">
</div>
<div class="responsive-container">
  <img src="http://lorempixel.com/200/400/sports/7/">
</div>
<div class="responsive-container">
  <img src="http://lorempixel.com/200/200/sports/6/">
</div>

Salman A
fonte
Obrigado! seu .responsive-container img css foi o único que funcionou para mim.
Diogo Garcia
4

Tente este

  .responsive-container{
          display:table;
  }
  .img-container{
          display:table-cell;
          vertical-align: middle;
   }

fonte
Desculpe, mas isso não funciona, acho que porque o meu .img-containerestá absolutamente posicionado - isso é necessário para manter a proporção quadrada / altura dinâmica.
user1794295
2

Aqui está uma técnica que permite centralizar QUALQUER conteúdo na vertical e na horizontal!

Basicamente, você só precisa de dois contêineres e verifique se seus elementos atendem aos seguintes critérios.

O recipiente externo:

  • deveria display: table;

O recipiente interno:

  • deveria display: table-cell;
  • deveria vertical-align: middle;
  • deveria text-align: center;

A caixa de conteúdo:

  • deveria display: inline-block;

Se você usar esta técnica, basta adicionar sua imagem (junto com qualquer outro conteúdo que você deseja que ela seja acompanhada) à caixa de conteúdo.

Demo:

body {
    margin : 0;
}

.outer-container {
    position : absolute;
    display: table;
    width: 100%;
    height: 100%;
    background: #ccc;
}

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

.centered-content {
    display: inline-block;
    background: #fff;
    padding : 12px;
    border : 1px solid #000;
}

img {
   max-width : 120px;
}
<div class="outer-container">
   <div class="inner-container">
     <div class="centered-content">
        <img src="https://i.stack.imgur.com/mRsBv.png" />
     </div>
   </div>
</div>

Veja também este violino !

John Slegers
fonte
2

Me deparei com este segmento em busca de uma solução que:

  • usa 100% da largura da imagem fornecida
  • mantém a proporção da imagem
  • mantém a imagem alinhada verticalmente ao meio
  • funciona em navegadores que não suportam totalmente o flex

Testando algumas das soluções postadas acima, não encontrei uma que atendesse a todos esses critérios; por isso, montei essa simples que pode ser útil para outras pessoas que precisam fazer o mesmo:

.container {
  width: 30%;
  float: left;
  border: 1px solid turquoise;
  margin-right: 3px;
  margin-top: 3px;
}

.container:last-of-kind {
  margin-right: 0px;
}

.image-container {
  position: relative;
  overflow: hidden;
  padding-bottom: 70%;
  /* this is the desired aspect ratio */
  width: 100%;
}

.image-container img {
  position: absolute;
  /* the following 3 properties center the image on the vertical axis */
  top: 0;
  bottom: 0;
  margin: auto;
  /* uses image at 100% width (also meaning it's horizontally center) */
  width: 100%;
}
<div class="container">
  <div class="image-container">
    <img src="http://placehold.it/800x800" class="img-responsive">
  </div>
</div>

<div class="container">
  <div class="image-container">
    <img src="http://placehold.it/800x800" class="img-responsive">
  </div>
</div>

<div class="container">
  <div class="image-container">
    <img src="http://placehold.it/800x800" class="img-responsive">
  </div>
</div>

Exemplo de trabalho no JSFiddle

Alexandra
fonte
0

Experimentar

Html

<div class="responsive-container">
     <div class="img-container">
         <IMG HERE>
     </div>
</div>

CSS

.img-container {
    position: absolute;
    top: 0;
    left: 0;
height:0;
padding-bottom:100%;
}
.img-container img {
width:100%;
}
Paramasivan
fonte
0

Código HTML

<div class="image-container"> <img src=""/> </div>

código css

img
{
  position: relative;
  top: 50%;
  transform: translateY(-50%);
 }
William
fonte
Embora esse trecho de código seja bem-vindo e possa fornecer alguma ajuda, ele seria bastante aprimorado se incluísse uma explicação de como ele aborda a questão. Sem isso, sua resposta tem muito menos valor educacional - lembre-se de que você está respondendo à pergunta dos leitores no futuro, não apenas à pessoa que está perguntando agora! Por favor edite sua resposta para adicionar explicação, e dar uma indicação do que limitações e premissas se aplicam.
Toby Speight
0

Faça outra div e adicione 'dummy' e 'img-container' dentro da div

Faça HTML e CSS como segue

html , body {height:100%;}
.responsive-container { height:100%; display:table; text-align:center; width:100%;}
.inner-container {display:table-cell; vertical-align:middle;}
<div class="responsive-container">
    <div class="inner-container">
		<div class="dummy">Sample</div>
		<div class="img-container">
			Image tag
		</div>
	</div>	
</div>

Em vez de 100% para o 'contêiner responsivo', você pode dar a altura que deseja.,

Descobrir
fonte