Изображения: размеры, пропорции, адаптация.
У любого изображения на странице есть два важных параметра — ширина и высота. Они присущи ему с момента создания, это его физические параметры. На основании этой пары формируется третий, не менее важный, параметр — соотношение сторон или пропорции изображения.
Соотношение сторон представляет собой дробь — отношение ширины к высоте. Возьмем, к примеру, изображение или видеофайл с разрешением FullHD 1920x1080 точек. 1920/1080 — если упрощать эту дробь, то получим 16/9, стандартное кинематографическое соотношение сторон. У изображения (или видео) с физическим размером 1024x768 точек эта пропорция равна 4/3.
Изменение размера
Добавляя изображение на страницу, мы имеем возможность задать размеры для отображения. Эти размеры не связаны с фактическими размерами картинки и могут повлиять на ее вид в браузере.
Ширину и высоту изображения можно менять как в меньшую, так и большую сторону. Однако на скорость загрузки рисунка это никак не влияет, поскольку размер файла остается неизменным. Поэтому с осторожностью уменьшайте изображение, т.к. это может вызвать недоумение у пользователя, отчего такой маленький рисунок так долго грузится. А вот увеличение размеров приводит к обратному эффекту — размер изображения велик, но файл относительно изображения аналогичного размера загружается быстрее. Увеличивать таким способом изображения можно только в особых случаях, поскольку сильно ухудшается качество картинки, вследствии эффекта интерполяции.
Интерполяция изображения
Суть интерполяции заключается в использовании имеющихся данных для получения ожидаемых значений в неизвестных точках. Интерполяция изображений работает в двух измерениях и пытается достичь наилучшего приближения в цвете и яркости пикселя, основываясь на значениях окружающих пикселей. Значения пикселей могут резко меняться от точки к точке. Чем больше вы знаете об окружающих пикселях, тем лучше сработает интерполяция. Вот почему результаты быстро ухудшаются по мере растягивания изображения, а кроме того, интерполяция никогда не сможет добавить изображению детальности, которой в нём нет.
Грубо говоря — попытавшись растянуть картинку размером 100*100 пикселей до размера 150*150 пикселей, мы заставим браузер “досочинить” недостающие пиксели, примерно глядя на соседние. Результатом будет потеря качества изображения.
Искажение пропорций
<body> <img src="images/redcat.jpg" alt="Размеры не заданы"> <img src="images/redcat.jpg" alt="Задана ширина" width="400"> <img src="images/redcat.jpg" alt="Задана ширина и высота" width="400" height="400"> </body>
В примере использовалась одна и та же фотография, для первого <img> размеры явно не указаны, поэтому браузер добавил изображение в исходном виде. Для второй фотографии указана ширина 400 пикселей, что привело к уменьшению её размеров при сохранении пропорций. Третья фотография искажена, поскольку задана одинаковая ширина и высота, при том, что исходное изображение не квадратное.
Расчет пропорций
Как изменить размер изображения не исказив его? Нужно учитывать пропорции и изменив, к примеру, ширину — высоту ставить не произвольную, а в том же соотношении к ширине, что и в исходных данных. Чтобы не считать вручную — можно воспользоваться онлайн калькулятором, которых множество — http://alittlebit.ru/tools/proportsii-izobrazheniya/ , https://ciox.ru/aspect-ratio , http://dimavolkov.ru/resize/index.html . Гуглятся по запросу “пропорции изображения калькулятор”.
Изображение в блоке
Часто встречающаяся в верстке ситуация — изображение в блоке (контейнере). При этом именно контейнеру по факту задаются размеры и пропорции по макету, так как изображения клиент может заливать разные, а дизайн должен оставаться неизменным.
Таким образом, мы имеем два условных прямоугольника, один вписан в другой и каждый со своими пропорциями. Какие варианты возможны?
Идеальный вариант
Идеальный вариант — пропорции контейнера и изображения совпадают. К примеру — изображение 1280*800 пикселей и контейнер 640*400. Считаем — 1280/800=1.6, 640/400=1.6. 1.6=1.6. Profit! Это изображение можно вместить в этот контейнер без пустых зон, искажения и обрезки частей.
Реальный вариант
Однако, к сожалению, идеального в нашем мире не так много, как хотелось бы. Поэтому вариант следующий — неидеальный, но реальный. Контейнер квадратный, или приближенный к квадрату, например 420*400 пикселей. Посчитаем сразу пропорции — 420/400=1,05. Изображение наш уважаемый Пользователь загружает размером 640*480 пикселей. Пропорции выходят 640/480=4/3=1,333(3).
Имея исходные данные, рассмотрим способы размещения данного изображения в данный контейнер. Клиент может хотеть идеального совпадения, но давайте посчитаем — 1,05 = 1,333(3). Возможно ли такое равенство? Ответ можете дать сами. Математика в нашей вселенной строга, неподкупна и одна для всех.
Что ж, если идеально — никак, то как же можно? Есть ровно ТРИ СПОСОБА.
Способ первый, совсем плохой
Искажение. Все просто — принудительно задаем изображению ширину и высоту, равные контейнеру или находящиеся в той же пропорции. Изображение при этом искажается, клиент ругается, зато края совпали идеально. Как это примерно выглядит — выше есть примеры.
Способ второй — пустое пространство
Размещение по большей величине. Берем бОльшую величину (в нашем случае — ширину) и делаем ее равной аналогичному параметру контейнера (ширине). А вот второй параметр расчитываем пропорционально, сами или воспользовавшись упомянутыми калькуляторами. Ширина контейнера — 420px. Подогнав изображение до той же величины, чтобы сохранить пропорции, высоту мы должны дать 315px.
Спонсор точного расчета — сайт http://alittlebit.ru/tools/proportsii-izobrazheniya/.
В результате картинка полностью разместится в контейнере, однако разница в пропорциях никуда не денется и появятся пустое пространство.
Способ третий — обрезка части изображения
Размещение по меньшей величине. В этом способе в качестве базовой величины мы берем меньшее число, в нашем случае — высоту. Высота контейнера — 400px. Уже знакомым калькулятором пропорционально рассчитываем второй параметр
Размещаем и видим, что контейнер теперь заполнен полностью, но часть изображения не поместилась и оказалась обрезана — разница пропорций, куда ж от нее деться.
Вывод
Если пропорции блока и изображения не совпадают, то, размещая изображение в блоке, мы должны сделать выбор — пустые зоны, обрезанные части, искажение.
Инструменты и приемы для верстальщика
Прием с background-image — как НЕЛЬЗЯ делать
Проблема адаптивного контейнера
В макетах адаптивного дизайна не редкость трансформация пропорций контейнера изображения на разных разрешениях. К примеру — на десктопе он квадратный, на планшете растягивается на всю ширину и становится прямоугольным, а на низком разрешении для мобильных снова теряет ширину и приближается к квадрату. Как же разместить изображение, ведь его пропорции неизменны?
Велик соблазн задать контейнеру нужные размеры, а изображение разместить задним фоном, через свойство css background-image. Это очень плохо, то, что называется bad practice, делать подобное нельзя никогда. Точнее можно, но только в одном случае — если изображение в самом деле несет функцию исключительно фоновую, декоративную. Если смысловая нагрузка размещенного изображения отличается от нуля (изображение товара, картинка в контенте, иллюстрация в редактируемом блоке) — оно не должно быть фоном.
Почему нельзя использовать background-image для изображений со смыслом?
Причина 1 — поисковые машины. Индексация страницы производится по ее содержимому, а стили содержимым не являются, следовательно — этого изображения для поисковиков не существует. Оно никогда не попадет в поисковую выдачу.
Причина 2 — шаринг в соцсетях. Ни один парсер, подготавливая превью страницы, не захватит изображение, которое прописано только в стилях. Как итог — очень скучный блок текста, на который мало кто обратит внимание.
Да и вообще — слово семантика — не простой звук, фоновое изображение должно быть фоновым, иллюстрация — иллюстрацией, то есть частью контента.
Если вам досталась правка сайта с background-image в блоке
Если вам так повезло, что перед вами именно такой сайт, с разносторонней адаптацией блока и изображением в нем, подставленным через стили — можно применить лайфхак: не трогать стили и адаптацию — наверняка сайт выглядит красиво, а наш принцип “не навреди”. Вместо этого добавьте в блок тег <img>, выведите туда изображение, родителю установите overflow: hidden; (чтобы не поломалась верстка), и задайте изображению opacity: 0;
Что же получается? И семантика соблюдена (изображение в блоке есть, может быть индексировано и распарсено), и хитрую адаптацию переделывать не пришлось. НО! Это лишь для правок, при верстке настоящие индейцы так не делают!
Адаптивный блок с изображением/видео (неизменные пропорции)
Если изображение, которое нужно адаптировать, сохраняет неизменные пропорции на любом разрешении, или это видео, где пропорции по определению не должны меняться — задача проста. Все, что нам нужно — чтобы при изменении ширины блока, вложенное в него изображение (или видео) изменялось пропорционально.
Приступим.
1. Изображение (видео) обернем в отдельный блок, если это еще не сделано. Именно он и будет адаптироваться.
<div class="thumb-wrap"> <iframe width="560" height="315" src="https://www.youtube.com/embed/Y421bWMelqE" frameborder="0" allowfullscreen></iframe> </div>
2. Пропишем стили:
.thumb-wrap { position: relative; padding-bottom: 56.25%; /* задаёт высоту контейнера для 16:9 (если 4:3 — поставьте 75%) */ padding-top: 30px; height: 0; overflow: hidden; } .thumb-wrap iframe { position: absolute; top: 0; left: 0; width: 100%; }
Паддинг в процентах задан в расчете на соотношение сторон видео. Если у вас изображение — поделите большую величину (ширину или высоту) на меньшую и умножьте на 100, полученное число и есть нужный процент отступа для сохранения пропорций.
Имитация поведения background-size с применением javascript (для настоящих индейцев)
Визуально самый приятный эффект дает размещение изображения задним фоном, но так делать нельзя, мы же договорились? А нельзя ли добиться того же визуального эффекта, но с изображением, добавленным в коде HTML? Можно, если перейти на следующий уровень и задействовать манипуляции jQuery.
Использовать мы будем очень небольшой (1,9kb) плагин. Написан он был давно, когда в ходу был IE версии ниже 9, который не понимал прекрасное свойство background-size. Несмотря на почтенный возраст, и немного не те цели применения изначально, он — то что нам нужно. Приступим.
Страница проекта на GitHUB https://github.com/aramk/CSS-Background-Size-jQuery-Plugin
1. Рективацию скрипта повесим на ресайз окна. Первый вызов осуществим имитацией ресайза. Простой вызов события resize(), как показала практика, срабатывает не всегда безотказно. Чтобы он срабатывало всегда и везде — создадим пользовательское событие (его можно применять не только для описываемой ситуации, но и всегда, когда нужно ):
//Universal resize event function universalResize() { if(typeof(Event) === 'function') { // modern browsers window.dispatchEvent(new Event('resize')); } else { // for IE and other old browsers // causes deprecation warning on modern browsers var evt = window.document.createEvent('UIEvents'); evt.initUIEvent('resize', true, false, window, 0); window.dispatchEvent(evt); } };
Теперь при вызове функции universalResize() всегда выстрелит событие изменения размера окна.
Аналогичным образом, кстати, можно создать ЛЮБОЕ кастомное событие, и вызывать его для срабатывания функций-обработчиков.
2. Подключаем плагин к селектору класса:
$window.resize(function() { $('.background-size-cover').bgdSize('cover'); $('.background-size-contain').bgdSize('contain'); }); // Вызываем вышеупомянутую функцию. universalResize();
Если блоки с изображения подтягиваются по ajax — то на срабатывание события complete добавляем такую инициализацию:
complete: function() { $(".background-size-cover").one("load", function() { $(this).removeAttr('style').bgdSize('cover'); }).each(function() { if(this.complete) $(this).load(); }); $(".background-size-contain").one("load", function() { $(this).removeAttr('style').bgdSize('contain'); }).each(function() { if(this.complete) $(this).load(); }); }
Такая хитрая запись позволяет вызвать функцию именно после загрузки изображения, а не после построения DOM. Берите на заметку.
Все готово! Изображениям, которым требуется поведение аналогичное background-size просто добавляем классы .background-size-cover или .background-size-contain.
Стили для контейнеров и изображений
Часто мы встречаемся с ситуацией, когда изображение обернуто в тег <a href=”…….”> для срабатывания различных галерей и тому подобного. Подобное решение требует некоторого внимания в стилях. Изображение, точнее тег <img> — элемент строчно-блочный (inline-block), в то время как <a href=”…….”> — просто инлайновый. Оборачивать inline-block в строку не семантично, а значит элементу <a> мы должны задать свойство display:inline-block;. Кроме семантики тут есть и элементарная логика — изображение имеет параметры высоты и ширины, и оборачивать его в СТРОКУ неверно. К тому же зачастую ширина и высота изображения относительны (задаются в процентах), а какие проценты ширины можно взять от строки?
Еще одна практика — задавать img стили {width: 100%; height: auto;}. И все идет хорошо, пока ширина изображения больше ширины контейнера и изображение имеет ширину бОльшую чем высоту. Однако как только в контейнер попадает изображение с исходными размерами меньше, чем сам контейнер — его растягивает и оно становится как минимум некрасивым. Если же его высота больше, чем ширина (двери, оконные рамы, одежда) то часть изображения еще и выйдет за пределы контейнера, попытавшись увеличиться пропорционально ширине.
Чтобы таких неприятных неожиданностей не случалось — не задавайте ширину жестко, пропишите {max-width: 100%; max-height: 100%}.