Centrar imagen de gran tamaño en Div

175

He estado tratando de resolver cómo centrar una imagen de gran tamaño dentro de un div usando solo CSS.

Estamos utilizando un diseño fluido, por lo que el ancho de los contenedores de imágenes varía al igual que el ancho de la página (la altura de div es fija). La imagen se encuentra dentro de un div, con un valor de sombreado de recuadro para que parezca que está mirando la imagen a través de la página.

La imagen en sí ha sido dimensionada para llenar el div circundante en su valor más amplio posible (el diseño tiene un max-widthvalor).

Es bastante fácil de hacer si la imagen es más pequeña que el div circundante:

margin-left: auto;
margin-right: auto;
display: block; 

Pero cuando la imagen es más grande que el div, simplemente comienza en el borde izquierdo y está descentrada a la derecha (estamos usando overflow: hidden).

Podríamos asignar un width=100%, pero los navegadores hacen un pésimo trabajo al cambiar el tamaño de las imágenes y el diseño web se centra en imágenes de alta calidad.

¿Alguna idea sobre centrar la imagen para que overflow:hiddencorte ambos bordes de manera uniforme?

Tom
fuente
2
¿Alguna vez resolviste este problema @Tom? Me encuentro con el mismo problema en este momento. :)
ctrlplusb
Supongo que los anchos de tu imagen varían.
otherDewi

Respuestas:

365

Intenta algo como esto. Esto debería centrar cualquier elemento enorme en el medio vertical y horizontalmente con respecto a su padre, sin importar sus dos tamaños.

.parent {
    position: relative;
    overflow: hidden;
    //optionally set height and width, it will depend on the rest of the styling used
}

.child {
    position: absolute;
    top: -9999px;
    bottom: -9999px;
    left: -9999px;
    right: -9999px;
    margin: auto;

}
hyounis
fuente
44
maravilloso: esto funciona con cualquier elemento. incluso con el video html 5 ... ¡gracias!
taseenb
3
Según tengo entendido: funciona porque crea un elemento (con suerte) más grande que la imagen (2 * 9999px x 2 * 9999px) y centra la imagen dentro de ese elemento (margen: automático). Por lo tanto, siempre que la imagen no supere los 2 * 9999px, debería funcionar.
Michael Krupp
16
¿Por qué no usar -100%para arriba / derecha / abajo / izquierda? Con eso, el contenedor podría tener literalmente cualquier ancho.
Simon
15
Sí, he experimentado el -100% problema ^^. Por cierto: si agrega min-widthy min-heightde 100%usted básicamente obtiene un background-size: cover;comportamiento con etiquetas de imagen -> jsfiddle
Simon
3
@HarrisonPowers Bueno, el padre debe tener una altura, por supuesto, ya sea fija o dinámica. También funcionará si algún otro contenido está llenando el div haciendo que tenga una altura (como el texto, por ejemplo).
hyounis
162

Esta es una antigua Q, pero una solución moderna sin flexbox o posición absoluta funciona así.

margin-left: 50%;
transform: translateX(-50%);

Entonces, ¿por qué funciona?
A primera vista parece que cambiamos 50% a la derecha y luego 50% a la izquierda nuevamente. Eso resultaría en un cambio a cero, ¿y qué?
Pero el 50% no es lo mismo, porque el contexto es importante. Si utiliza unidades relativas, se calculará un margen como porcentaje del ancho del elemento principal , mientras que la transformación será del 50% en relación con el mismo elemento.

Tenemos esta situación antes de agregar el CSS

       +-------------------------------------------+
       | Parent element P of E                     |
       |                                           |
       +-----------------------------------------------------------+
       | Element E                                                 |
       +-----------------------------------------------------------+
       |                                           |
       +-------------------------------------------+

Con el estilo agregado margin-left: 50%tenemos

       +-------------------------------------------+
       | Parent element P of E                     |
       |                                           |
       |                     +-----------------------------------------------------------+
       |                     | Element E                                                 |
       |                     +-----------------------------------------------------------+
       |                     |                     |
       +---------------------|---------------------+
       |========= a ========>|

       a is 50% width of P

Y los transform: translateX(-50%)cambios de vuelta a la izquierda

       +-------------------------------------------+
       | Parent element P of E                     |
       |                                           |
+-----------------------------------------------------------+
| Element E                 |                               |
+-----------------------------------------------------------+
|<============ b ===========|                      |
       |                    |                      |
       +--------------------|----------------------+
       |========= a =======>|

       a is 50% width of P
       b is 50% width of E

Desafortunadamente, esto solo funciona para el centrado horizontal, ya que el cálculo del porcentaje de margen siempre es relativo al ancho. Es decir, no solo margin-lefty margin-right, sino también margin-topymargin-bottom se calculan con respecto al ancho.

La compatibilidad del navegador no debería ser un problema: https://caniuse.com/#feat=transforms2d

Yunzen
fuente
No funciona para la alineación vertical (cuando .inner tiene una altura mayor que .outer)
cronfy
1
@cronfy No. verticalmente no funcionará, porque margin-top: 50%será el 50% del ancho . No la altura deseada.
Yunzen
2
esa es, con mucho, la solución más elegante
Souhaieb Besbes
buscando una solución por un tiempo, la mejor, la más simple; Saludos
lauWM
2
Esto es pura magia de mago. ¡Gracias! Funciona perfectamente en Safari y Chrome (con un añadido -webkit-transform: translateX(-50%);por si
acaso
22

Coloque un div grande dentro del div, céntrelo y centre la imagen dentro de ese div.

Esto lo centra horizontalmente:

HTML:

<div class="imageContainer">
  <div class="imageCenterer">
    <img src="http://placekitten.com/200/200" />
  </div>
</div>

CSS:

.imageContainer {
  width: 100px;
  height: 100px;
  overflow: hidden;
  position: relative;
}
.imageCenterer {
  width: 1000px;
  position: absolute;
  left: 50%;
  top: 0;
  margin-left: -500px;
}
.imageCenterer img {
  display: block;
  margin: 0 auto;
}

Demostración: http://jsfiddle.net/Guffa/L9BnL/

Para centrarlo verticalmente también, puede usar lo mismo para el div interno, pero necesitaría la altura de la imagen para colocarla absolutamente dentro de ella.

Guffa
fuente
Esto terminó con el borde izquierdo de la imagen centrado dentro del "imageContainer". Como comenté anteriormente, nuestro contenedor de imágenes div es ancho de fluido y altura fija.
Tom
1
@ Tom: si elimino la widthconfiguración en el contenedor, será el ancho del elemento primario y la imagen se centrará incluso si la página es más estrecha que la imagen, es decir, se ocultará tanto el borde izquierdo como el derecho. : jsfiddle.net/Guffa/L9BnL/2
Guffa
Gracias por la inspiracion. Yo uso position: relative para .imageCenter. De esta manera no necesito la posición: relativa para el contenedor principal.
user3153298
Hay muchos trucos inteligentes para esta pregunta y todos tienen sus inconvenientes. Algunos funcionan "mejor" pero no son del todo fáciles de entender. Esta solución tiene mucho sentido, la imagen se centra normalmente en un div más amplio que se está recortando. Se siente mal, pero definitivamente funciona sin romper las leyes de la física web. Elegí esta opción sobre varios otros trucos muy difíciles de entender, incluso si se siente un poco sucio.
Radley Sustaire
9

Tarde al juego, pero descubrí que este método es extremadamente intuitivo. https://codepen.io/adamchenwei/pen/BRNxJr

CSS

.imageContainer {
  border: 1px black solid;

  width: 450px;
  height: 200px;
  overflow: hidden;
}
.imageHolder {
  border: 1px red dotted;

  height: 100%;
  display:flex;
  align-items: center;
}
.imageItself {
  height: auto;
  width: 100%;
  align-self: center;

}

HTML

<div class="imageContainer">
  <div class="imageHolder">
    <img class="imageItself" src="http://www.fiorieconfetti.com/sites/default/files/styles/product_thumbnail__300x360_/public/fiore_viola%20-%202.jpg" />
  </div>
</div>
Ezeewei
fuente
3
¡Agradable! También se puede simplificar. El truco se realiza display: flexen el contenedor principal y align-self: centeren la imagen. Aquí hay una versión optimizada: codepen.io/anon/pen/dWKyey
caiosm1005
5

No utilice un ancho o alto fijo o explícito para la etiqueta de la imagen. En cambio, codifíquelo:

      max-width:100%;
      max-height:100%;

ex: http://jsfiddle.net/xwrvxser/1/

chaqueta de cuero4
fuente
1
Esto deja espacio alrededor de la imagen que creo que están tratando de evitar.
Eoin
3

Soy un gran admirador de hacer que una imagen sea el fondo de un div / nodo, entonces solo puede usar el background-position: centeratributo para centrarlo independientemente del tamaño de la pantalla

Shain Lafazan
fuente
9
Esta no es una forma accesible de usar imágenes. Puede funcionar bien para imágenes decorativas, pero cualquier imagen que sea informativa necesita texto alternativo.
user2532030
0

El ancho y la altura son solo por ejemplo:

parentDiv{
    width: 100px;
    height: 100px;
    position:relative; 
}
innerDiv{
    width: 200px;
    height: 200px;
    position:absolute; 
    margin: auto;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}

Tiene que funcionar para usted si la izquierda y la parte superior de su div principal no están en la parte superior e izquierda de la ventana de su pantalla. Esto funciona para mi.

Панайот Толев
fuente
No parecía hacer la diferencia. No estoy seguro de si tiene algo que ver con el hecho de que el ancho es fluido, mientras que la altura se fija en lo que sería el div principal.
Tom
2
Esta técnica funciona si la imagen es más pequeña que el contenedor.
otherDewi
0

Encontré que esta es una solución más elegante, sin flexión:

.wrapper {
    overflow: hidden;
}
.wrapper img {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* height: 100%; */ /* optional */
}
Cezar D.
fuente
0

Sobre la base de la gran respuesta de @ yunzen:

Supongo que muchas personas que buscan este tema intentan usar una imagen grande como imagen de fondo de "héroe", por ejemplo, en una página de inicio. En este caso, a menudo querrían que el texto aparezca sobre la imagen y que se reduzca bien en dispositivos móviles.

Aquí está el CSS perfecto para dicha imagen de fondo (úsela en la <img>etiqueta):

/* Set left edge of inner element to 50% of the parent element */
margin-left: 50%;

/* Move to the left by 50% of own width */
transform: translateX(-50%);

/* Scale image...(101% - instead of 100% - avoids possible 1px white border on left of image due to rounding error */
width: 101%;

/* ...but don't scale it too small on mobile devices - adjust this as needed */
min-width: 1086px;

/* allow content below image to appear on top of image */
position: absolute;
z-index: -1;

/* OPTIONAL - try with/without based on your needs */
top: 0;

/* OPTIONAL - use if your outer element containing the img has "text-align: center" */
left: 0;
Dave Koo
fuente
-1

Una opción que puede usar es que object-fit: coverse comporta un poco como background-size: cover. Más sobre ajuste de objetos .

ignore todos los JS a continuación, eso es solo para la demostración.

La clave aquí es que necesita establecer la imagen dentro de un contenedor y darle las siguientes propiedades.

.wrapper img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

He creado una demostración a continuación donde cambias el alto / ancho del contenedor y lo ves en juego. La imagen siempre estará centrada vertical y horizontalmente. Ocupará el 100% de su ancho y altura principal, y no se estirará / aplastará. Esto significa que se mantiene la relación de aspecto de la imagen. Los cambios se aplican al acercar / alejar.

El único inconveniente object-fites que no funciona en IE11.

// for demo only
const wrapper = document.querySelector('.wrapper');
const button = document.querySelector('button');
const widthInput = document.querySelector('.width-input');
const heightInput = document.querySelector('.height-input');


const resizeWrapper = () => {
  wrapper.style.width = widthInput.value + "px";
  wrapper.style.height = heightInput.value + "px";
}

button.addEventListener("click", resizeWrapper);
.wrapper {
  overflow: hidden;
  max-width: 100%;
  margin-bottom: 2em;
  border: 1px solid red;
}

.wrapper img {
  display: block;
  height: 100%;
  width: 100%;
  object-fit: cover;
}
<div class="wrapper">
  <img src="https://i.imgur.com/DrzMS8i.png">
</div>


<!-- demo only -->
<lable for="width">
  Width: <input name="width" class='width-input'>
</lable>
<lable for="height">
  height: <input name="height" class='height-input'>
</lable>
<button>change size!</button>

voltio
fuente