Центрируйте негабаритное изображение в Div

175

Я пытался разобраться, как центрировать увеличенное изображение внутри div, используя только CSS.

Мы используем гибкий макет, поэтому ширина контейнеров с изображениями зависит от ширины страницы (высота div фиксирована). Изображение находится внутри элемента div со значением вставной тени, чтобы оно выглядело так, как будто вы просматриваете страницу на изображении.

Само изображение было изменено по размеру, чтобы заполнить окружающий элемент с максимально широким значением (дизайн имеет max-widthзначение).

Это довольно легко сделать, если изображение меньше окружающего элемента div:

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

Но когда изображение больше, чем div, оно просто начинается с левого края и смещается от центра вправо (мы используем overflow: hidden).

Мы могли бы назначить width=100%, но браузеры делают паршивую работу по изменению размера изображений, а веб-дизайн сосредотачивается вокруг высококачественных изображений.

Какие-нибудь идеи по центрированию изображения так, чтобы overflow:hiddenобрезать оба края равномерно?

Том
источник
2
Вы когда-нибудь решали эту проблему @Tom? Я сталкиваюсь с той же проблемой в данный момент. :)
ctrlplusb
Я предполагаю, что ширина вашего изображения варьируется.
ДругоеDewi

Ответы:

368

Попробуйте что-то вроде этого. Это должно центрировать любой огромный элемент по центру по вертикали и горизонтали относительно его родителя независимо от их размеров.

.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
источник
4
замечательно: это работает с любым элементом. даже с HTML 5 видео ... спасибо!
taseenb
3
Как я понимаю, это работает, потому что он создает элемент (надеюсь) больше, чем изображение (2 * 9999px x 2 * 9999px) и центрирует изображение внутри этого элемента (margin: auto). Так что, пока изображение не превышает 2 * 9999 пикселей, оно должно работать.
Майкл Крупп
16
Почему бы не использовать -100%для верхней / правой / нижней / левой? При этом контейнер может иметь буквально любую ширину.
Саймон
15
Да, я тоже столкнулся с этой -100%проблемой ^^. Btw: если вы добавляете min-widthи min-heightиз 100%вас в основном получить background-size: cover;поведение с тегами изображения -> jsfiddle
Simon
3
@HarrisonPowers Ну, у родителя, конечно, должна быть высота, фиксированная или динамическая. Это также будет работать, если какой-то другой контент заполняет div, вызывая его высоту (например, текст).
Hyounis
162

Это старый Q, но современное решение без flexbox или абсолютного положения работает следующим образом.

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

Так почему же это работает?
На первый взгляд кажется, что мы сдвигаемся на 50% вправо, а затем снова на 50% влево. Это приведет к смещению нуля, и что?
Но 50% - это не одно и то же, потому что важен контекст. Если вы используете относительные единицы измерения, поле будет рассчитываться в процентах от ширины родительского элемента, а преобразование будет на 50% относительно того же элемента.

У нас есть такая ситуация, прежде чем мы добавим CSS

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

С добавленным стилем margin-left: 50%мы имеем

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

       a is 50% width of P

И transform: translateX(-50%)сдвиг назад влево

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

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

К сожалению, это работает только для горизонтального центрирования, так как процентное соотношение маржи всегда зависит от ширины. Т.е. не только margin-leftи margin-right, но также margin-topи margin-bottomрассчитываются по ширине.

Совместимость браузера не должна быть проблемой: https://caniuse.com/#feat=transforms2d

yunzen
источник
Это не работает для вертикального выравнивания (когда .inner имеет большую высоту, чем .outer)
cronfy
1
@ cronfy Нет. Вертикально это не будет работать, потому что margin-top: 50%будет 50% ширины . не высота, как хотелось бы.
yunzen
2
это, безусловно, самое элегантное решение
Souhaieb Besbes
поиск решения на некоторое время, лучшее, простое; Приветствия
LauWM
2
Это чистая волшебная магия. Спасибо! Отлично работает в Safari и Chrome (с добавленной -webkit-transform: translateX(-50%);для хорошей меры)
Ник Шнебл
22

Поместите большой div внутри div, центрируйте его, и центр изображения внутри этого div.

Это центрирует его горизонтально:

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

Демо: http://jsfiddle.net/Guffa/L9BnL/

Чтобы отцентрировать его по вертикали, вы можете использовать то же самое для внутреннего div, но вам понадобится высота изображения, чтобы поместить его абсолютно внутри него.

Guffa
источник
Это закончилось тем, что левый край изображения был центрирован внутри «imageContainer». Как я прокомментировал выше, наш div контейнера изображений - это ширина жидкости и фиксированная высота.
Том
1
@Tom: Если я удалю widthнастройку для контейнера, это будет ширина родительского элемента, и изображение будет отцентрировано, даже если страница уже, чем изображение, то есть столько левого края, сколько правого края будет скрыто : jsfiddle.net/Guffa/L9BnL/2
Guffa
Спасибо за вдохновение. Я использую положение: относительное для .imageCenter. Таким образом, мне не нужна позиция: относительная для родительского контейнера.
user3153298
В этом вопросе есть много хитрых уловок, и у всех есть свои недостатки. Некоторые работают «лучше», но их совсем не легко понять. Это решение имеет смысл: изображение обычно центрируется в более широком элементе div, который обрезается. Это кажется неправильным, но это определенно работает, не нарушая законы веб-физики. Я выбрал эту опцию из нескольких других очень трудных для понимания трюков, даже если она немного грязная.
Рэдли Сустер
9

Поздно к игре, но я нашел этот метод чрезвычайно интуитивно понятным. 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
источник
3
Ницца! Это тоже можно упростить. Трюк сделан display: flexна родительском контейнере и align-self: centerна изображении. Вот оптимизированная версия: codepen.io/anon/pen/dWKyey
caiosm1005
5

Не используйте фиксированную или явную ширину или высоту для тега изображения. Вместо этого кодируйте это:

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

Например: http://jsfiddle.net/xwrvxser/1/

leatherjacket4
источник
1
Это тогда оставляет пространство вокруг изображения, которое, я полагаю, они пытаются избежать.
Eoin
3

Я большой поклонник создания изображения в качестве фона div / узла - тогда вы можете просто использовать background-position: centerатрибут для его центрирования независимо от размера экрана

Шайн Лафазан
источник
9
Это не доступный способ использования изображений. Это может хорошо работать для декоративных изображений, но любое изображение, которое является информативным, нуждается в тексте.
user2532030
0

Ширина и высота только для примера:

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

Это должно работать для вас, если левая и верхняя часть вашего родительского div не являются самой верхней и левой частью окна вашего экрана. Меня устраивает.

Панайот Толев
источник
Казалось, не имеет значения. Не уверен, что это связано с тем, что ширина плавная, а высота фиксирована на том, что будет родительским div.
Том
2
Этот метод работает, если изображение меньше контейнера.
ДругоеDewi
0

Я обнаружил, что это более элегантное решение без flex:

.wrapper {
    overflow: hidden;
}
.wrapper img {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* height: 100%; */ /* optional */
}
Цезарь Д.
источник
0

Опираясь на отличный ответ @ yunzen:

Я предполагаю, что многие люди, ищущие эту тему, пытаются использовать большое изображение в качестве фонового изображения «героя», например, на домашней странице. В этом случае они часто хотят, чтобы текст появлялся поверх изображения и чтобы он хорошо масштабировался на мобильных устройствах.

Вот идеальный CSS для такого фонового изображения (используйте его на <img>теге):

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

Один из вариантов, который вы можете использовать, - object-fit: coverон немного похож background-size: cover. Подробнее об объекте .

игнорируйте все JS ниже, это только для демонстрации.

Ключевым моментом здесь является то, что вам нужно установить изображение внутри оболочки и дать ему следующие свойства.

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

Я создал демо ниже, где вы меняете высоту / ширину обертки и видите в игре. Изображение всегда будет вертикально и горизонтально. Это займет 100% его родительской ширины и высоты, и не будет растягиваться / сдавливаться. Это означает, что соотношение сторон изображения сохраняется. Изменения применяются путем увеличения / уменьшения масштаба.

Единственным недостатком object-fitявляется то, что он не работает на 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>

вольт
источник