Centrer l'image surdimensionnée en Div


175

J'ai essayé de déterminer comment centrer une image surdimensionnée dans un div en utilisant uniquement css.

Nous utilisons une mise en page fluide, donc la largeur des conteneurs d'image varie comme la largeur de la page (la hauteur de div est fixe). L'image se trouve dans un div, avec une valeur d'ombre de boîte en médaillon de manière à apparaître comme si vous regardiez l'image à travers la page.

L'image elle-même a été dimensionnée pour remplir le div environnant à sa valeur la plus large possible (le dessin a une max-widthvaleur).

C'est assez facile à faire si l'image est plus petite que la div environnante:

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

Mais lorsque l'image est plus grande que le div, elle commence simplement au bord gauche et est décentrée vers la droite (nous utilisons overflow: hidden).

Nous pourrions attribuer un width=100%, mais les navigateurs font un mauvais travail de redimensionnement des images et la conception Web se concentre sur des images de haute qualité.

Avez-vous des idées pour centrer l'image de manière à overflow:hiddencouper les deux bords uniformément?


2
Avez-vous déjà résolu ce problème @Tom? Je rencontre le même problème pour le moment. :)
ctrlplusb

Je suppose que vos largeurs d'image varient.
autreDewi

Réponses:


368

Essayez quelque chose comme ça. Cela devrait centrer tout élément énorme au milieu verticalement et horizontalement par rapport à son parent, quelle que soit leur taille.

.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
merveilleux: cela fonctionne avec n'importe quel élément. même avec la vidéo html 5 ... merci!
taseenb

3
Si je comprends bien: cela fonctionne parce qu'il crée un élément (espérons-le) plus grand que l'image (2 * 9999px x 2 * 9999px) et centre l'image à l'intérieur de cet élément (margin: auto). Donc, tant que l'image ne dépasse pas 2 * 9999px, cela devrait fonctionner.
Michael Krupp

16
Pourquoi ne pas utiliser -100%pour haut / droite / bas / gauche? Avec cela, le conteneur pourrait avoir littéralement n'importe quelle largeur.
Simon

15
Ouais, j'ai aussi rencontré le -100%problème ^^. BTW: si vous ajoutez min-widthet min-heightde 100%vous obtenez fondamentalement un background-size: cover;comportement avec des balises d'image -> jsFiddle
Simon

3
@HarrisonPowers Eh bien, le parent doit avoir une hauteur bien sûr, qu'elle soit fixe ou dynamique. Cela fonctionnera également si un autre contenu remplit le div, ce qui lui donne une hauteur (comme du texte par exemple).
hyounis

162

C'est un ancien Q, mais une solution moderne sans flexbox ni position absolue fonctionne comme ça.

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

Alors pourquoi ça marche?
À première vue, il semble que nous nous déplaçons de 50% vers la droite, puis de 50% vers la gauche. Cela entraînerait un décalage nul, et alors?
Mais les 50% ne sont pas les mêmes, car le contexte est important. Si vous utilisez des unités relatives, une marge sera calculée en pourcentage de la largeur de l' élément parent , tandis que la transformation sera de 50% par rapport au même élément.

Nous avons cette situation avant d'ajouter le CSS

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

Avec le style ajouté que margin-left: 50%nous avons

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

       a is 50% width of P

Et les transform: translateX(-50%)décalages vers la gauche

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

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

Malheureusement, cela ne fonctionne que pour le centrage horizontal car le calcul du pourcentage de marge est toujours relatif à la largeur. Ie non seulement margin-leftet margin-right, mais aussi margin-topet margin-bottomsont calculés par rapport à la largeur.

La compatibilité du navigateur ne devrait pas poser de problème: https://caniuse.com/#feat=transforms2d


Cela ne fonctionne pas pour l'alignement vertical (lorsque .inner a une hauteur plus grande que .outer)
cronfy

1
@cronfy No. verticalement cela ne fonctionnera pas, car ce margin-top: 50%sera 50% de la largeur . pas la hauteur souhaitée.
yunzen

2
c'est de loin la solution la plus élégante
Souhaieb Besbes

chercher une solution pendant un certain temps, la meilleure, la plus simple; Cheers
lauWM

2
C'est de la pure magie de sorcier. Je vous remercie! Fonctionne parfaitement dans Safari et Chrome (avec un ajout -webkit-transform: translateX(-50%);pour faire bonne mesure)
Nick Schneble

22

Mettez un grand div dans le div, centrez-le et centrez l'image à l'intérieur de ce div.

Cela le centre horizontalement:

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

Démo: http://jsfiddle.net/Guffa/L9BnL/

Pour le centrer verticalement également, vous pouvez utiliser la même chose pour la div interne, mais vous auriez besoin de la hauteur de l'image pour la placer absolument à l'intérieur.


Cela s'est terminé avec le bord gauche de l'image centré dans le "imageContainer". Comme je l'ai commenté ci-dessus, notre div de conteneur d'image est une largeur fluide et une hauteur fixe.
Tom

1
@Tom: Si je supprime le widthparamètre sur le conteneur, ce sera la largeur du parent, et l'image est centrée même si la page est plus étroite que l'image, c'est à dire autant du bord gauche que le bord droit sera masqué : jsfiddle.net/Guffa/L9BnL/2
Guffa

Merci pour l'inspiration. J'utilise position: relative pour .imageCenter. De cette façon, je n'ai pas besoin de la position: relative pour le conteneur parent.
user3153298

Il y a beaucoup de trucs intelligents à cette question et ils ont tous leurs inconvénients. Certains fonctionnent «mieux» mais ne sont pas du tout faciles à comprendre. Cette solution est parfaitement logique, l'image est centrée normalement dans une division plus large qui est rognée. Cela semble faux, mais cela fonctionne définitivement sans enfreindre les lois de la physique du Web. J'ai choisi cette option plutôt que plusieurs autres astuces très difficiles à comprendre, même si cela me semble un peu sale.
Radley Sustaire

9

Tard dans le jeu, mais j'ai trouvé cette méthode extrêmement intuitive. 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
Agréable! Cela peut également être simplifié. L'astuce se fait par display: flexsur le conteneur parent et align-self: centersur l'image. Voici une version optimisée: codepen.io/anon/pen/dWKyey
caiosm1005

5

N'utilisez pas de largeur ou de hauteur fixe ou explicite pour la balise d'image. Au lieu de cela, codez-le:

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

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


1
Cela laisse alors un espace autour de l'image que je crois qu'ils essaient d'éviter.
Eoin

3

Je suis un grand fan de faire d'une image l'arrière-plan d'un div / nœud - alors vous pouvez simplement utiliser l' background-position: centerattribut pour le centrer quelle que soit la taille de l'écran


9
Ce n'est pas une manière accessible d'utiliser les images. Cela peut fonctionner correctement pour les images décoratives, mais toute image informative nécessite un texte alternatif.
user2532030

0

La largeur et la hauteur ne sont qu'à titre d'exemple:

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

Cela doit fonctionner pour vous si la gauche et le haut de votre div parent ne sont pas tout en haut et à gauche de la fenêtre de votre écran. Ça marche pour moi.


Cela ne semblait pas faire de différence. Je ne sais pas si cela est dû au fait que la largeur est fluide, alors que la hauteur est fixée sur ce que serait la div parent.
Tom

2
Cette technique fonctionne si l'image est plus petite que le conteneur.
autreDewi

0

J'ai trouvé que c'était une solution plus élégante, sans flex:

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

0

S'appuyant sur la bonne réponse de @ yunzen:

Je suppose que de nombreuses personnes qui recherchent ce sujet essaient d'utiliser une grande image comme image d'arrière-plan "héros", par exemple sur une page d'accueil. Dans ce cas, ils souhaiteraient souvent que le texte apparaisse sur l'image et qu'il soit bien réduit sur les appareils mobiles.

Voici le CSS parfait pour une telle image de fond (utilisez-le sur la <img>balise):

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

Une option que vous pouvez utiliser est object-fit: coverqu'il se comporte un peu comme background-size: cover. Plus d'informations sur l' adaptation aux objets .

ignorez tous les JS ci-dessous, c'est juste pour la démo.

La clé ici est que vous devez définir l'image dans un wrapper et lui donner les propriétés suivantes.

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

J'ai créé une démo ci-dessous où vous modifiez la hauteur / largeur de l'emballage et voyez en jeu. L'image sera toujours centrée verticalement et horizontalement. Il occupera 100% de sa largeur et de sa hauteur parentes et ne sera pas étiré / écrasé. Cela signifie que le rapport hauteur / largeur de l'image est conservé. Les modifications sont appliquées par un zoom avant / arrière à la place.

Le seul inconvénient object-fitest que cela ne fonctionne pas sur 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>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.