Переменная плотность пикселей

Одной из особенности устройств является то что существует очень широкий спектр плотности пикселей. Некоторые устройства имеют очень высокое разрешение дисплея. Разработчики веб-приложений должны учитывать переменную плотность пикселей, что довольно сложно. В мобильном интернете, существует ряд проблем:

  • Большое разнообразие устройств с разными размерами мониторов.
  • Ограниченная пропускная способность сети интернет.

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

Избегайте изображений, если возможно

Прежде нужно, помнить, что есть мощные технологий, которые независимы от разрешений DPI. А именно текст, SVG и CSS поскольку функция автоматически масштабирует пиксель в интернете (через devicePixelRatio). Не всегда можно обойтись без растровых изображений. Например, у вас есть активы, которые сложно сделать в SVG/CSS, или вы имеете дело с фотографией. Хотя вы можете преобразовать изображение в SVG, но в оцифровке цифровой фотографий нет смысла.

Короткая история плотности дисплея

Сначала, компьютерные мониторы были с плотностью 72 пикселя или 96 dpi (96 точек на дюйм). Изображение постепенно улучшалось с ним росла плотность пикселей, в основном из-за мобильного использования, когда пользователь подносит свой телефон ближе к лицу, пиксели становятся более заметней.

К 2008 году телефоны с 150dpi стали новой нормой. Тенденция к увеличению плотности дисплея продолжалась, и теперь новые телефоны 300dpi (фирменная Retina от Apple ). Святой Грааль, конечно, будет тот дисплей, в котором плотность пикселей невидно. Нынешнее поколение дисплеев Retina/HiDPI близки к идеалу.

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

Разная плотность пикселей Разная плотность пикселей
Павианы, с разной плотностью дисплея.

Пиксели для интернета

Когда всемирная сеть была разработана, 99% показов были 96dpi. Из-за большого набора разных размеров дисплеев и их плотности, появилась потребность создать стандартный способ для просмотра изображений с разной плотности пикселей и на разных размерах дисплеев в хорошем качестве. Спецификация HTML5 недавно решала эту проблему, спецификация определяет какие пиксели используют производители, чтобы указать размер пикселя.

Рекомендуется опорный пиксель для угла зрения одного пикселя на устройстве с плотностью пикселей 96dpi и расстояние от читателя на расстоянии вытянутой руки. Для длины руки номинального от 28 дюймов, угол зрения, следовательно, от 0,0213 градуса.

С помощью связи пикселей, производитель может определить размер физического пикселя относительно устройства к стандартным или идеальным пикселям. Это соотношение называется: соотношение пикселя к устройству.

Рассчитать соотношение пикселя к устройству

Предположим, что смартфон имеет экран с физическим размером 180 пикселей на дюйм (PPI). Расчет соотношения пикселя к устройству включает три этапа:

  1. Сравнить фактическое расстояние, на котором находится устройство от опорного пикселя. Мы знаем что: для 28 дюймах, идеально подходит плотность 96dpi. Но так как это смартфон, а люди его держат ближе к лицу, чем ноутбук. Значит размер приблизительно 18 дюймов.
  2. Умножьте соотношение расстояния от стандартной плотности 96dpi, чтобы получить идеальную плотность пикселей для данного расстояния. idealPixelDensity = (28/18) * 96 = 150 пикселей на дюйм (приблизительно)
  3. Возьмём физическое соотношение плотности пикселей к идеальной плотности пикселей, чтобы получить соотношение пикселя к устройству.
    
    
    devicePixelRatio = 180/150 = 1,2
    
    
    
Диаграмма, показывающая одну ссылку углового пикселя
Диаграмма, показывает связь пикселя, для расчета devicePixelRatio 

Теперь, когда браузер знает, как изменить размер изображения до размеров экрана в соответствии с идеальным или стандартным разрешением, браузер обращается к устройству соотношений пикселя 1.2, каждый пиксель идеальный и устройство имеет 1.2 физический пиксель. Формула для перехода между идеальным (как определено в веб-спецификации) и физическим (точек на экране устройства) пикселем заключается в следующем:



physicalPixels = window.devicePixelRatio * idealPixels


Исторически сложилось так, что производители устройств, как правило округляют devicePixelRatios (DPRS). IPhone от Apple и IPAD report DPR 1, и их эквиваленты Retina. Может быть и лучше округлять, потому что может уменьшиться количество артефактов на изображении. Но в реальности, устройства  гораздо более разнообразны и телефоны Android часто имеют DPRS 1.5. Планшет Nexus 7 имеет DPR от ~ 1,33 результат вычислений, аналогичный. В будущем будет несколько устройств с переменным DPRS.

Обзор методов HIDPI

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

  1. Оптимизация одного изображения для всех устройств
  2. Оптимизация изображения выбранного устройством из нескольких изображений для отображения.

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

  • Сильно сжать HiDPI изображение
  • Разный формат изображений
  • Прогрессивный формат изображения

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

Сильное сжатие HIDPI

Изображения составляет 60% пропускной способности, больше половины тратится на загрузку веб-страницы. HiDPI изображение увеличит это число.

Пропускная способность
Изображения составляет 60% пропускной способности

Проведены несколько тестов, которые генерируются 1x и 2x. Вот скрипт для этого он работает с  ImageMagick :



#!/usr/bin/env bash
QUAL_HI=90
QUAL_MID=50
QUAL_LOW=20
ORIG=hq2x.jpg
# Create 2x version.
convert original.jpg -quality $QUAL_HI hq2x.jpg
# Create 1x version.
convert hq2x.jpg -resize 50% hq1x.jpg
# Create compressed versions.
convert hq2x.jpg -quality $QUAL_MID lq2x.jpg
convert hq1x.jpg -quality $QUAL_MID lq1x.jpg
# Create very compressed versions.
convert hq2x.jpg -quality $QUAL_LOW ulq2x.jpg
convert hq1x.jpg -quality $QUAL_LOW ulq1x.jpg
# Crop everything into little samples for clarity.
for img in *1x.jpg
do
convert $img -crop 160x120+0+0 preview/$img;
done
for img in *2x.jpg
do
convert $img -crop 320x240+0+0 preview/$img;
done
# Tile into a preview.
montage -label '%f, %b -- quality: %Q' preview/*x.jpg -shadow -border 5 -geometry 320x240+5+5 preview/tile.jpg


Фрагменты изображения с качеством JPEG — 90, 50 и 20

Образцы изображений с различным сжатием и плотности пикселей Образцы изображений с различным сжатием и плотности пикселей Образцы изображений с различным сжатием и плотности пикселей
Образцы изображений с различным сжатием и плотности пикселей

На мой взгляд, сильно сжатое изображение 2x на самом деле выглядит лучше, чем несжатое изображение 1x. Конечно, изображение низкого качества, с высокой степенью сжатия изображений 2x 2x для устройств хуже, чем с хорошим качеством. Если вы сравните качество: изображения 90 с качеством изображения 20, вы увидите уменьшение четкости и увеличение зернистости. Эти артефакты не нужны в тех случаях, когда высокое качество изображения являются ключевым моментом (например, приложение для просмотра фотографий). Сравнение было сделано исключительно со сжатым изображением в формате JPEG. Стоит отметить, что существует много подходов, которые широко применяются для сжатия графических форматов (JPEG, PNG, GIF).

Удивительный формат изображений

WebP является довольно убедительным форматом изображения, который сжимается очень хорошо, сохраняя при этом высокую четкость изображения. Конечно, он еще не везде реализован ! Одним из способов проверки поддержки браузером WebP осуществляется с помощью JavaScript. Вы загружаете изображение 1px с данным URI, и ждём либо отобразится или будет ошибка события. Modernizr  со  сценарием функции обнаружения  доступен через Modernizr.webp. Но лучший способ сделать это, непосредственно в CSS с помощью функции image() . Если у вас есть изображение WebP и JPEG как запасной вариант, вы можете написать следующее:



#pic {
  background: image("foo.webp", "foo.jpg");
}


Есть несколько проблем с этим подходом. Во-первых, свойство  image()  не распространено. Во-вторых, дует WebP и сжатый JPEG, улучшает меньше чем на 30%, основываясь на галереи WebP. Таким образом, изображение WebP еще не достаточно для решения этой проблемы.

Прогрессивный формат изображений

Полные графические форматы, такие как JPEG 2000, Progressive JPEG, PNG и Progressive GIF. Они могут отображаться с наложенным размером, хотя существуют противоречивые свидетельства об этом. Джеф Этвуд утверждает, что прогрессивный режим, добавляет около 20% к размеру изображения PNG, и около 10% размер для изображений JPEG и GIF. Тем не менее, Стоян Стефанов заявил, что для больших файлов, прогрессивный режим является более эффективным (в большинстве случаев).

На первый взгляд, прогрессивное изображение выглядит очень перспективным в контексте, где отображается лучшие качество изображения. Идея состоит в том, что браузер может остановить загрузку и декодирование изображений, он знает, что дополнительные данные не приведут к увеличению качества изображения (т.е. все улучшения точности являются суб-пикселями). Для сайта с большим количеством изображений, наиболее эффективный подход, сохранить соединение HTTP так долго, как это возможно. Если соединение будет закрыто преждевременно, потому что одно изображение не было до конца загружено, браузеру необходимо создать новое соединение, которое может быть очень медленным в низкой латентности . Один из способов для этого является использование запроса HTTP Range , который позволяет браузерам указать диапазон байтов для выборки. Смарт-браузер может сделать запрос, чтобы получить ответ сколько изображения действительно необходимо, а затем отображать. К сожалению, HTTP Range слабо поддерживаются на веб-сервере, что делает этот подход непрактичным. Наконец, такой подход является ограниченным, потому что вы не сможете выбрать, какие изображения должны отображаться. В результате, это не решение для применения » художественного направления «.

JavaScript для изображения

Можно применить JavaScript на стороне клиента, что бы выбрать, какие изображения должны грузится для отображения на странице. Вы можете определить соотношение пикселя устройства через window.devicePixelRatio, получить ширину и высоту экрана, и даже потенциально сделать некоторые подключение к сети через navigator.connection или выдачу поддельных запросов, как это делает библиотека foresight.js . После того как вы собрали всю эту информацию, вы можете решить, какой образ должен отображаться.

Есть приблизительно один миллион библиотек  JavaScript , которые делают это, и все они с недостатками. Один большой недостаток в этом подходе, что при использовании JavaScript, у вас будут медленно грузится изображения до тех пор, пока после look-ahead парсер закончен. Это означает, что изображения не будут даже начинать загрузку, сразу после события PageLoad. Подробнее об этом в статье Джейсон Григсби .

Решить, какие изображения для загрузки на сервер

Вы можете отложить принятие решения на серверах путем написания пользовательских обработчиков запроса для каждого изображения. Такой обработчик проверит поддержку Retina на основе User-Agent (только часть информации передается на сервер). Затем, в зависимости от логики на стороне сервера заработают активы HiDPI, вы загрузите соответствующий актив (названы в соответствии с некоторыми известными конвенциями). К сожалению, User-Agent  не всегда даёт достаточно информация устройству, какое изображение должно грузится высокого или низкого качества. Также, само собой разумеется, что все, что относится к User-Agent — это Хак, и его следует избегать, если это возможно.

Использовать CSS media queries

CSS media queries указывает браузеру как сделать всё правильно. К media queries можно добавить devicePixelRatio. Если вы хотите загрузить изображение с высоким разрешением и соотношение пикселей к устройству, вот что нужно сделать:



#my-image { background: (low.png); }

@media only screen and (min-device-pixel-ratio: 1.5) {
  #my-image { background: (high.png); }
}


Это становится немного сложнее со всеми префиксами, особенно из-за безумного  различия в размещении с «min» и «max» префиксами:



@media only screen and (min--moz-device-pixel-ratio: 1.5),
    (-o-min-device-pixel-ratio: 3/2),
    (-webkit-min-device-pixel-ratio: 1.5),
    (min-device-pixel-ratio: 1.5) {

  #my-image {
    background:url(high.png);
  }
}


Такой подход хорош тем что избавит вас от применения JS. Но это еще немного громоздко, и приводит к странному виду кода в CSS (или требует предварительной обработки). Кроме того, этот подход ограничен свойствами CSS, тег <img src> не принимает этот подход и все ваши изображения должны быть элементом фона. Наконец, опираясь исключительно на соотношение пикселей к  устройству, вы можете оказаться в ситуации, когда ваш смартфон заканчивает загрузку изображений 2x, из-за  EDGE соединение . Это не лучший пользовательский способ.

Использовать функции браузера

image-set () — это функции CSS WebKit. В результате, Safari и Chrome поддерживают её. Так как image-set() функция CSS, она не имеет отношения к тегам <img>. Функция @ srcset на момент написания этой статьи, не имеет никакого отношения к реализации (пока!).

Функции браузера для изображения

В конечном счете, решение принимать вам что делать с изображениями, и зависит от ваших конкретных требований. Но имейте в виду, что все перечисленные подходы имеют свои недостатки. Заглядывая вперед, как только image-set и srcset будут полностью поддерживаться, они будут решать эти проблемы.

В настоящее время, давайте поговорим о некоторых лучших способах, которые помогут нам как можно ближе быть к идеалу будущего, на сколько это возможно. image-set() является функцией CSS, подходит для использования в качестве значения свойств CSS для фона. srcset является атрибутом, с аналогичным синтаксисом и похожим на элемент <img> . К обоим этим тегам можно подключить изображение, но атрибут srcset  позволяет также настроить выбор из набора изображений для отображения в зависимости от размера окна.

Способ выбрать изображение

CSS функция image-set() доступна с  префиксом  -webkit-image-set() . Синтаксис довольно прост, с одним или несколькими изображениями, который состоит из строки url или url() адрес изображения с соответствующим разрешением. Например:



background-image:  -webkit-image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);


Это говорит браузеру, что есть два изображения на выбор. Один из них оптимизирован для 1x дисплеев, а другой для 2x дисплеев. Затем браузер делает выбор, какое изображение загружать для отображения на дисплее. Выбор отображения основан по целому ряду факторов, которые могут даже учитывать скорость сети, если браузер достаточно умен (в настоящее время не реализовано, насколько я знаю). В дополнение к загрузке правильного изображения, браузер также будет масштабировать его соответствующим образом. Другими словами, браузер, предполагает, что 2x изображение в два раза больше чем изображение 1x, выбор будет соответствовать размеру окна.

Не обязательно указывать 1x, 1.5x или Nx, вы также можете указать определенную плотность пикселей устройств в точках на дюйм. Это хорошо работает, кроме браузера, который не поддерживает свойство набора изображений, он будет показывать изображение не везде! Поэтому нужно использовать резерв:



background-image: url(icon1x.jpg);
background-image: -webkit-image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);
/* This will be useful if image-set gets into the platform, unprefixed.
   Also include other prefixed versions of this */
background-image: image-set(
  url(icon1x.jpg) 1x,
  url(icon2x.jpg) 2x
);


Этот код отобразит соответствующие изображение в браузерах, которые поддерживают набор изображений. Единственное что, свойство image-set() браузерами почти не поддерживается, в большинстве запросов пользователь увидят актив 1x.

В  этом примере  используется свойство CSS  image-set() , чтобы отобразить правильное изображение, если эта функция CSS не поддерживаются браузером, будет видно только актив 1x. Вы можете подключить поддержку для  image-set()  помощью JavaScript . Как оказалось, это довольно сложно реализовать эффективно polyfills для функций CSS. (Почему см. на  WWW-стиль обсуждения ).

Изображение srcset

Вот пример srcset:



<img alt="my awesome image" src=
http://pixelcom.crimea.ua/"banner.jpeg" srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x" />


В дополнение к значению  х,  элемент srcset  также принимает значение   w , которое соответствуют размеру окна. Изображение banner-phone.jpeg 640w  — для устройств с шириной окна до 640px, banner-HD.jpeg 2x  — для маленького окна с высоким разрешением, banner-phone-HD.jpeg 640w  — для экрана по больше, чем 640px,  banner.jpeg  — для всех остальных.

Подключить изображения

Напомню что атрибут srcset для тега  <img>  не реализован в большинстве браузеров, можно заменить элемент изображения тегом <div> с фоном и использовать множественный подхода. Но тег  <img> имеет семантическое значение, и важен в основном для поисковых роботов. Если вы будете использовать -webkit-image-set , у вас может возникнуть потребность использовать свойство CSS для фона. Недостатком такого подхода является то, что вам нужно указать размер изображения, которое неизвестно, если вы используете изображение не 1x. Вместо этого, вы можете использовать содержимое свойств CSS следующим образом:



<div id="my-content-image" style="content: -webkit-image-set(
    url('icon1x.jpg') 1x,
    url('icon2x.jpg') 2x);"></div>


Это автоматически масштабирует изображение, основанное на devicePixelRatio из вышеперечисленных действии, с дополнительным url() для браузеров, которые не поддерживают набор изображений.

Polyfilling srcset

Одна удобная особенность srcset является то, что у него есть запасной вариант. Даже если атрибут srcset в браузере не реализован, всё равно браузеры знают как обработать атрибут scr . Кроме того, это атрибут HTML, для него можно создать polyfills с JavaScript .



<img alt="" src=
http://pixelcom.crimea.ua/"small.jpg" srcset="small.jpg 320w, medium.jpg 960w, large.jpg" />


Polyfill тестился чтобы убедиться, что он близок к спецификации srcset насколько это возможно. Кроме того Polyfill не работает, если свойство srcset в браузере реализовано изначально.

Заключение

Простым решением может оказаться обойтись без изображений в целом, или применить SVG и CSS. Но выбор за вами, всегда можно применить способы выше, особенно если на вашем сайте есть изображения с высоким качеством. Подходы JS, CSS имеют свои сильные и слабые стороны. Наиболее перспективный подход, это в использовании новых функций браузера. Но поддержка браузером набор изображений и атрибута srcset еще не завершена. Мои рекомендации заключаются в следующем:

  • Для фонового изображения, использовать image-set с резервом для браузеров, которые не поддерживают функцию image-set.
  • Для изображения в содержании, использовать Polyfill srcset, или возврат к using image-set (см. выше).
  • В ситуациях, когда требуется качество изображения, рассмотрите вариант сжатия изображения 2x.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML -теги и атрибуты: <a href= http://pixelcom.crimea.ua/"" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>