Centra l'immagine sovradimensionata in Div


175

Ho cercato di capire come centrare un'immagine di grandi dimensioni all'interno di un div utilizzando solo CSS.

Stiamo utilizzando un layout fluido, quindi la larghezza dei contenitori di immagini varia in base alla larghezza della pagina (l'altezza del div è fissa). L'immagine si trova all'interno di un div, con un ombretto a riquadro inserito in modo da apparire come se si stesse guardando la pagina nell'immagine.

L'immagine stessa è stata dimensionata per riempire il div circostante al suo valore più ampio possibile (il design ha un max-widthvalore).

È abbastanza facile da fare se l'immagine è più piccola del div circostante:

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

Ma quando l'immagine è più grande del div inizia semplicemente sul bordo sinistro ed è fuori centro a destra (stiamo usando overflow: hidden).

Potremmo assegnare un width=100%, ma i browser fanno un pessimo lavoro di ridimensionamento delle immagini e il web design è incentrato su immagini di alta qualità.

Qualche idea sul centrare l'immagine in modo da overflow:hiddentagliare uniformemente entrambi i bordi?


2
Hai mai risolto questo problema @ Tom? Sto riscontrando lo stesso problema al momento. :)
ctrlplusb,

Presumo che la larghezza delle tue immagini vari.
Dewi,

Risposte:


368

Prova qualcosa del genere. Questo dovrebbe centrare qualsiasi elemento enorme nel mezzo in verticale e in orizzontale rispetto al suo genitore, indipendentemente dalle loro dimensioni.

.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;

}

4
meraviglioso: funziona con qualsiasi elemento. anche con video HTML 5 ... grazie!
taseenb,

3
A quanto ho capito: funziona perché crea un elemento (si spera) più grande dell'immagine (2 * 9999px x 2 * 9999px) e centra l'immagine all'interno di quell'elemento (margine: auto). Quindi, purché l'immagine non superi 2 * 9999px, dovrebbe funzionare.
Michael Krupp,

16
Perché non usare -100%per in alto / a destra / in basso / a sinistra? Con ciò il contenitore potrebbe avere letteralmente qualsiasi larghezza.
Simon,

15
Sì, ho riscontrato anche il -100%problema ^^. Btw: se si aggiunge min-widthe min-heightdi 100%che, fondamentalmente, ottenere un background-size: cover;comportamento con i tag di immagine -> jsfiddle
Simon

3
@HarrisonPowers Beh, il genitore deve avere un'altezza ovviamente, sia fissa che dinamica. Funzionerà anche se qualche altro contenuto sta riempiendo il div causandone l'altezza (come ad esempio il testo).
hyounis,

162

Questa è una vecchia Q, ma una soluzione moderna senza flexbox o posizione assoluta funziona così.

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

Quindi perché funziona?
A prima vista sembra che spostiamo di nuovo il 50% a destra e poi di nuovo il 50% a sinistra. Ciò comporterebbe uno spostamento zero, e allora?
Ma il 50% non è lo stesso, perché il contesto è importante. Se si utilizzano unità relative, un margine verrà calcolato come percentuale della larghezza dell'elemento principale , mentre la trasformazione sarà del 50% rispetto allo stesso elemento.

Abbiamo questa situazione prima di aggiungere il CSS

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

Con lo stile aggiunto margin-left: 50%che abbiamo

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

       a is 50% width of P

E i transform: translateX(-50%)turni tornano a sinistra

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

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

Sfortunatamente questo funziona solo per la centratura orizzontale poiché il calcolo della percentuale di margine è sempre relativo alla larghezza. Cioè non solo margin-lefte margin-right, ma anche margin-tope margin-bottomsono calcolati rispetto alla larghezza.

La compatibilità del browser non dovrebbe essere un problema: https://caniuse.com/#feat=transforms2d


Non funziona per l'allineamento verticale (quando .inner ha un'altezza maggiore rispetto a .outer)
cronfy,

1
@cronfy No. in verticale non funzionerà, perché margin-top: 50%sarà il 50% della larghezza . non l'altezza desiderata.
yunzen,

2
questa è di gran lunga la soluzione più elegante
Souhaieb Besbes,

cercare una soluzione per un po ', la migliore, la più semplice; Cin cin
lauWM il

2
Questa è pura magia magica. Grazie! Funziona perfettamente su Safari e Chrome (con l'aggiunta -webkit-transform: translateX(-50%);per una buona misura)
Nick Schneble il

22

Inserisci un div grande all'interno del div, centralo e al centro l'immagine all'interno di quel div.

Questo lo centra orizzontalmente:

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;
}

demo: http://jsfiddle.net/Guffa/L9BnL/

Per centrarlo anche verticalmente, puoi usare lo stesso per il div interno, ma avrai bisogno dell'altezza dell'immagine per posizionarlo assolutamente al suo interno.


Ciò si è concluso con il bordo sinistro dell'immagine centrato all'interno di "imageContainer". Come ho commentato sopra, il div del nostro contenitore di immagini è la larghezza del fluido e l'altezza fissa.
Tom,

1
@Tom: se rimuovo l' widthimpostazione sul contenitore, sarà la larghezza del genitore e l'immagine sarà centrata anche se la pagina è più stretta dell'immagine, cioè tanto il bordo sinistro quanto il bordo destro saranno nascosti : jsfiddle.net/Guffa/L9BnL/2
Guffa,

Grazie per l'ispirazione. Uso position: relative per .imageCenter. In questo modo non ho bisogno della posizione: relativa per il contenitore principale.
user3153298

Ci sono molti trucchi intelligenti per questa domanda e tutti hanno i loro svantaggi. Alcuni funzionano "meglio" ma non sono affatto facili da capire. Questa soluzione ha perfettamente senso, l'immagine viene centrata normalmente in un div più ampio che viene ritagliato. Sembra sbagliato, ma sicuramente funziona senza infrangere le leggi della fisica del web. Ho scelto questa opzione su molti altri trucchi molto difficili da capire, anche se sembra un po 'sporco.
Radley Sustaire,

9

In ritardo al gioco, ma ho scoperto che questo metodo è estremamente 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>

3
Bello! Può anche essere semplificato. Il trucco viene eseguito display: flexsul contenitore principale e align-self: centersull'immagine. Ecco una versione ottimizzata: codepen.io/anon/pen/dWKyey
caiosm1005


3

sono un grande fan di rendere un'immagine lo sfondo di un div / nodo - quindi puoi semplicemente usare l' background-position: centerattributo per centrarlo indipendentemente dalle dimensioni dello schermo


9
Questo non è un modo accessibile di usare le immagini. Può funzionare bene per le immagini decorative, ma qualsiasi immagine che abbia carattere informativo necessita di testo alternativo.
user2532030

0

La larghezza e l'altezza sono solo per esempio:

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

Deve funzionare per te se la parte sinistra e superiore del div del tuo genitore non sono la parte superiore e sinistra della finestra dello schermo. Per me funziona.


Non sembra fare la differenza. Non sono sicuro che abbia qualcosa a causa del fatto che la larghezza è fluida, mentre l'altezza è fissa su quello che sarebbe il div genitore.
Tom,

2
Questa tecnica funziona se l'immagine è più piccola del contenitore.
Dewi,

0

Ho trovato questa soluzione più elegante, senza flex:

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

0

Sulla base della grande risposta di @ yunzen:

Immagino che molte persone alla ricerca di questo argomento stiano cercando di utilizzare un'immagine di grandi dimensioni come immagine di sfondo di un "eroe", ad esempio su una homepage. In questo caso, vorrebbero spesso che il testo appaia sull'immagine e lo ridimensioni bene sui dispositivi mobili.

Ecco il CSS perfetto per tale immagine di sfondo (usalo sul <img>tag):

/* 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;

-1

Un'opzione che puoi usare è che object-fit: coversi comporta un po 'come background-size: cover. Altro su adattamento agli oggetti .

ignora tutti i JS qui sotto, è solo per la demo.

La chiave qui è che devi impostare l'immagine all'interno di un wrapper e dargli le seguenti proprietà.

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

Di seguito ho creato una demo in cui si modifica l'altezza / larghezza del wrapper e si vede in gioco. L'immagine sarà sempre centrata verticalmente e orizzontalmente. Occuperà il 100% della larghezza e dell'altezza del genitore e non verrà allungato / schiacciato. Ciò significa che vengono mantenute le proporzioni dell'immagine. Le modifiche vengono applicate ingrandendo / rimpicciolendo invece.

L'unico aspetto negativo object-fitè che non funziona su 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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.