Сохраняйте соотношение сторон изображения при изменении высоты

114

Как с помощью модели гибкого бокса CSS заставить изображение сохранять свое соотношение сторон?

JS Fiddle: http://jsfiddle.net/xLc2Le0k/2/

Обратите внимание, что изображения растягиваются или сжимаются, чтобы заполнить ширину контейнера. Это нормально, но можно ли растянуть или уменьшить высоту, чтобы сохранить пропорции изображения?

HTML

<div class="slider">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
</div>

CSS

.slider {
    display: flex;
}
.slider img {
    margin: 0 5px;
}
coderMe
источник
1
Насколько я знаю, лучшее решение - использовать a <div>с CSSbackground-image: url(...);background-size:contain; background-repeat:no-repeat
Blazemonger
1
Здесь есть несколько интересных выводов, но что делать, если изображения уже не в таком же соотношении? Добавление и «лишний» div - это последнее, о чем нам нужно беспокоиться. Почему бы не использовать тестовый пример , как это вместо: jsfiddle.net/sheriffderek/999Lg9qv
sheriffderek

Ответы:

68

Для тегов img, если вы определяете одну сторону, размер другой стороны будет изменен, чтобы сохранить соотношение сторон, и по умолчанию изображения расширяются до своего исходного размера.

Используя этот факт, если вы оберните каждый тег img в тег div и установите его ширину на 100% от родительского div, тогда высота будет соответствовать соотношению сторон, как вы хотели.

http://jsfiddle.net/0o5tpbxg/

* {
    margin: 0;
    padding: 0;
}
.slider {
    display: flex;
}
.slider .slide img {
    width: 100%;
}
Мухаммад Умер
источник
2
Я знаю, что есть два ответа, предлагающих использовать div, но я отмечаю этот ответ как правильный, потому что он объясняет, почему высота изображения отличается от того, что я ожидал. Фактически, это нормальное и правильное поведение, которое вряд ли будет «исправлено», поскольку это не ошибка.
coderMe
18
Но этот ответ ничего не говорит о flexbox, потому что изображения в контейнере flexbox ведут себя по-разному. Установка одной стороны не приведет к пропорциональному изменению размера другой. Помогает их упаковка в контейнер, отличный от flexbox, но это добавляет ненужную разметку, теряющую семантику.
Роберт Коритник
3
Не похоже, что вам нужен оборачивающий div, чтобы эта работа работала: jsfiddle.net/xLc2Le0k/120
Rick Strahl
4
Но как насчет этого? jsfiddle.net/xLc2Le0k/15 Я думаю, что это решение - случайность, которая работает только потому, что все изображения имеют одинаковое соотношение. примечание: при размещении изображения в div для позиционирования / особенно при работе с отзывчивыми изображениями не теряется «семантичность».
sheriffderek
1
Серьезно самое чистое решение, и оно работает с изображением!
shaneonabike
64

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

Вы можете попробовать использовать подгонку объекта к изображению, например

object-fit: contain;

http://jsfiddle.net/ykw3sfjd/

Или вы можете добавить правила гибкости, которые в некоторых случаях могут работать лучше.

align-self: center;
flex: 0 0 auto;
Мэтти Валаам
источник
4
объектная подгонка могла бы быть хорошим решением, если бы в нем не отсутствовала поддержка в IE и Edge даже до Edge 14
Дэниелс
1
Ознакомьтесь с этим резервным вариантом объектно-подходящей версии для Edge в IE .
Андрей Тельтеу
Сам использовал этот запасной вариант, работает очень хорошо.
Мэтти Валаам,
1
У @daniels Edge теперь есть объектно-подходящая разработка: developer.microsoft.com/en-us/microsoft-edge/platform/status/…
AMDG
1
object-fit: contain;помогло мне, когда у меня была проблема только в хроме, ff было в порядке.
Бенджамин Питер
53

Нет необходимости добавлять содержащий div.

По умолчанию для свойства css "align-items" установлено значение "stretch", которое заставляет ваши изображения растягиваться до полной исходной высоты. Установка свойства css "align-items" на "flex-start" устраняет вашу проблему.

.slider {
    display: flex;
    align-items: flex-start;  /* ADD THIS! */
}
Марвин Хербольд
источник
3
Ах ... спасибо за то, что все делали поддерживаемым способом. Я читал ответы до этого и не мог поверить, что все, что у нас было, было грязным хаком ...
Феликс Ганьон-Гренье
35

Большинство изображений имеют внутренние размеры , то есть естественный размер, как jpegизображение. Если указанный размер определяет как ширину, так и высоту, недостающее значение определяется с использованием внутреннего соотношения ... - см. MDN .

Но, насколько мне известно , это не работает должным образом, если изображения устанавливаются как элементы прямой гибкости с текущим модулем макета гибкой коробки уровня 1 .

Просмотрите эти обсуждения, и отчеты об ошибках могут быть связаны:

  • Flexbugs №14 - Внутренний размер Chrome / Flexbox реализован неправильно.
  • Ошибка Firefox 972595 - контейнеры Flex должны использовать «flex- base » вместо «width» для вычисления внутренней ширины гибких элементов.
  • Chromium Issue 249112 - В Flexbox разрешите внутренние соотношения сторон для информирования при вычислении основного размера.

В качестве обходного пути вы можете обернуть каждый символ <img>a <div>или a <span>или около того.

jsFiddle

.slider {
  display: flex;
}

.slider>div {
  min-width: 0; /* why? see below. */
}

.slider>div>img {
  max-width: 100%;
  height: auto;
}
<div class="slider">
  <div><img src="https://picsum.photos/400/300?image=0" /></div>
  <div><img src="https://picsum.photos/400/300?image=1" /></div>
  <div><img src="https://picsum.photos/400/300?image=2" /></div>
  <div><img src="https://picsum.photos/400/300?image=3" /></div>
</div>

4.5 Предполагаемый минимальный размер гибких элементов

Чтобы обеспечить более разумный минимальный размер по умолчанию для гибких элементов , эта спецификация вводит новое значение auto в качестве начального значения свойств min-width и min-height, определенных в CSS 2.1.


В качестве альтернативы вы можете использовать tableвместо этого макет CSS , который вы получите аналогичные результаты, поскольку flexboxон будет работать в большем количестве браузеров, даже для IE8.

jsFiddle

.slider {
  display: table;
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

.slider>div {
  display: table-cell;
  vertical-align: top;
}

.slider>div>img {
  max-width: 100%;
  height: auto;
}
<div class="slider">
  <div><img src="https://picsum.photos/400/300?image=0" /></div>
  <div><img src="https://picsum.photos/400/300?image=1" /></div>
  <div><img src="https://picsum.photos/400/300?image=2" /></div>
  <div><img src="https://picsum.photos/400/300?image=3" /></div>
</div>

Наклейки
источник
Первый фрагмент требуется .slider > div{min-width:0}в новых браузерах, поддерживающих min-width: auto.
Oriol
3
Спецификация flexbox ввела новое autoзначение в качестве значения по умолчанию для min-widthи min-height(ранее было 0). Chrome еще не реализует его, поэтому ваш первый фрагмент работает. Но новым браузерам это необходимо для того, чтобы гибкие элементы могли уменьшаться меньше, чем ширина изображений по умолчанию.
Oriol
2
+1 это должен быть принятый ответ, потому что он говорит об изображениях в модели flexbox, что является основной проблемой в данном случае ...
Роберт Коритник
Таблица хороша, если ваш макет не меняется в различные моменты останова, но в наши дни это маловероятно.
sheriffderek
1
А что насчет того, когда изображения не имеют одинакового соотношения? jsfiddle.net/sheriffderek/5u7y21we
sheriffderek
6

В последнее время я играл с flexbox, и я пришел к решению этой проблемы путем экспериментов и следующих рассуждений. Однако на самом деле я не уверен, что происходит именно так.

Если на реальную ширину влияет гибкая система. Таким образом, после того, как ширина элементов достигает максимальной ширины родительского элемента, дополнительная ширина, установленная в css, игнорируется. Тогда безопасно установить ширину на 100%.

Поскольку высота тега img зависит от самого изображения, установка высоты на 0% может кое-что сделать. (здесь я не понимаю, что ... но для меня имело смысл исправить это)

DEMO

(помните, что впервые увидел это здесь!)

.slider {
    display: flex;
}
.slider img {
    height: 0%;
    width: 100%;
    margin: 0 5px;
}

Работает пока только в хроме

Мухаммад Умер
источник
Интересно, но похоже на баг. Согласно спецификации , « Процент рассчитывается относительно высоты содержащего блока сгенерированного блока. Если высота содержащего блока не указана явно (т. Е. Зависит от высоты содержимого), и этот элемент не позиционируется абсолютно , значение вычисляется какauto ". Вот что происходит в Firefox.
Oriol
jsfiddle.net/xLc2Le0k/8 объясните разницу в ff и chrome. для этого
Мухаммад Умер
ширина, кажется, делает в ff, что высота делает в chrome.
Мухаммад Умер,
Это интересно, но я боюсь, что решения только для X-браузера на самом деле не являются решениями. Ваша прокомментированная скрипка здесь: jsfiddle.net/xLc2Le0k/8 , тем не менее, абсолютно захватывающая в FF. Кажется, это показывает, что FF делает высоту изображения «пропорциональной» высоте изображения, если бы она была действительно 100%. Другими словами, img «не знает» об отображении контейнера: flex. Это объясняет, почему в FF, если вы установите ширину img на 100%, изображение будет выше, чем если вы установите ширину на auto.
coderMe
Это своего рода близко ... но работает только в Chrome: jsfiddle.net/sheriffderek/xLc2Le0k/270
sheriffderek
2

Это ожидаемое поведение. flex-контейнер по умолчанию растягивает всех своих дочерних элементов. Изображение не исключение. (т.е. у родителя будет align-items: stretchсобственность)

Чтобы сохранить соотношение сторон, есть два решения:

  1. Либо замените align-items: stretchсвойство по умолчанию на align-items: flex-startили align-self: centerт.д., http://jsfiddle.net/e394Lqnt/3/

или

  1. Установите свойство align исключительно для самого дочернего элемента: like, align-self: centerили align-self: flex-startт. Д. Http://jsfiddle.net/e394Lqnt/2/
Асим КТ
источник
-1

На самом деле я обнаружил, что контейнер тега изображения должен иметь высоту, чтобы сохранить пропорции изображения. например>

.container{display:flex; height:100%;} img{width:100%;height:auto;}

тогда в вашем html ваш контейнер обернет изображение тега

<div class="container"><img src="image.jpg" alt="image" /></div>

эта работа для IE и других браузеров

kengreg
источник
-1

У меня была такая же проблема. Используйте выравнивание гибкости, чтобы центрировать элементы. Вам нужно использовать align-items: centerвместо align-content: center. Это сохранит соотношение сторон, в то время как align-content не сохранит соотношение сторон.

Клинтон Грин
источник