Техника Clown Car: изображения в адаптивном вебдизайне

Техника Clown Car: изображения в адаптивном вебдизайне

От автора: Сейчас изображения – «горячая» тема споров в адаптивном вебдизайне. Почему? Потому, что еще никому не понравились существующие решения. Для облегчения нашей сильной головной боли – обеспечить пользователя одним изображением, оптимизированным к размеру и разрешению его дисплея, без потери времени, памяти или пропускной способности и на стороне клиента – обсуждаются новые элементы и атрибуты.

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

Некоторые впустую тратят пропускную способность (и память), посылая изображения в высоком разрешении на все устройства. Прочие всюду рассылают обычное разрешение, при этом изображения выглядят неотчетливо на высококачественных экранах. На самом деле очень хочется отыскать святой Грааль: единственное вполне доступное решение, при котором, в зависимости от запрашивающих браузера и устройства, изображение посылается идеально подходящего размера и разрешения.

Ближе всех подходит к понятию святого Грааля техника «clown car»: использование хорошо поддерживаемых медиазапросов, формата SVG и элемента object для подачи адаптивных изображений одним запросом. Это решение пока неидеально, но уже совершенствуется.

Фоновые изображения и медиазапросы

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

К сожалению, для изображений переднего плана решения не существовало – до этих пор. Технология существует уже долгое время. Методика clown car – это просто новинка, использующая уже существующую технику.

Предлагаемые с помощью новой техники решения

НОВЫЕ ЭЛЕМЕНТЫ И АТРИБУТЫ

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

Также был предложен еще один метод, использующий атрибут srcset к элементу img. Вышеприведенный элемент picture будет записываться как тут:

У этих решений есть достоинства и недостатки. Выбрать что-то одно сложно — но нам это больше не нужно. Они оба были объединены в то, что называется компромиссом Флориана (Florian’s Compromise). Однако поддержка еще не совсем работает. Google предложил хинты клиентской стороны как часть верхнего колонтитула HTTP, чтобы подавать нужные изображения серверной стороной.

НЕОЖИДАННОЕ РЕШЕНИЕ – SVG

Многие не знают, что технология создания и подачи адаптивных изображений уже существует. SVG уже долгое время поддерживает медиазапросы, а браузеры поддерживают SVG … ну, тоже довольно давно. Большинство браузеров поддерживают медиазапросы в SVG (можете протестировать свой браузер). Когда речь идет об адаптивных изображениях, единственные браузеры в мобильной среде, которые не поддерживают SVG – это старые версии Android’а (поддержка SVG началась с версии Android 3.0).

Для создания адаптивных изображений мы можем использовать браузерную поддержку SVG и SVG-поддержку как медиазапросов, так и растровых изображений, применяя для подачи нужного изображения медиазапросы в SVG. Мой эксперимент теоретически изначально обязан работать – и действительно работает – в Internet Explorer (IE) 10 и Opera. При разметке HTML вы добавляете к файлу SVG единственный вызов.

Простой код, не так ли? SVG поддерживают растровые изображения, включенные с помощью элемента image и свойства CSS background-image. В свой адаптивный SVG мы включили бы все изображения, которые нужно доставить, а затем показали бы из них на основе медиазапросов только соответствующее.

СКАЧАЙТЕ ОДНО РАСТРОВОЕ ИЗОБРАЖЕНИЕ

Моей первой попыткой в SVG стало применение image с медиазапросами и скрытие их с помощью display: none.

Тогда как с точки зрения сохранения активного состояния SVG работает идеально, у него есть некоторые проблемы. К сожалению, установка display: none на image в SVG, как и в HTML, не предотвращает от закачивания ресурса. Если открыть SVG image в своем браузере, все четыре PNG будут извлечены с сервера, сделано четыре запроса HTTP, зря потратится пропускная способность и память.

На примере фоновых изображений CSS мы знаем, что на самом деле возможна закачка только нужных изображений. Точно так же, чтобы предотвратить закачку всех включенных изображений, в своем файле SVG мы бы использовали фоновые изображения CSS вместо изображений переднего плана:

Вышеприведенный код можно напрямую включить как встроенный svg, или вставить с помощью атрибута src тэга img или атрибута data тэга object. Если вы знакомы с медиазапросами и CSS, то вышеприведенный код обязан звучать для вас осмысленно. Техника clown car использует те же медиазапросы, которые вы применили бы где угодно в своем адаптивном вебсайте. Чтобы сохранить соотношение размеров содержащего элемента и гарантировать его равномерное масштабирование, мы включаем атрибуты viewbox и preserveAspectRatio.

Значение атрибута viewbox – это список из четырех чисел, разделенных пробелом или запятой: min-x, min-y, width и height. Определяя ширину и высоту своего параллелепипеда видимости, мы определяем форматное соотношение изображения SVG. Значения, которые мы устанавливаем для атрибута preserveAspectRatio — 300 × 329 — сохраняют определенное во viewbox соотношение размеров.

Проблемы добавления вышеописанного: 1) Chrome и Safari не поддерживают соотношение размеров, когда svg встроен: вместо этого svg по умолчанию становится 100% ширины и высоты. Этот дефект был представлен на рассмотрение. 2) Webkit и Firefox не разрешают включение растровых изображений или скриптов в SVG, вставленных посредством элемента img, и 3) поддержка SVG отсутствует в IE <=8 и Android <=2.3.3.

При открытии файла SVG с заданными только фоновыми изображениями растровое изображение займет все окно просмотра. Тогда как версия с image может выглядеть лучше как отдельный файл, потому что поддерживает свое соотношение размеров, а версия с background-image заполняет окно просмотра, когда вы включаете SVG как отдельный извлеченный в HTML документ, соотношение размеров сохраняется по умолчанию. Нормально работают background-size для contain, cover или 100%: выберите то, что лучше всего подходит к вашим требованиям.

Свойство CSS background-image решает проблему с запросом HTTP. Откройте файл SVG с одними фоновыми изображениями PNG (или версию JPEG), посмотрите на закладку Сеть (Network) в инструментах разработчика, и вы увидите, что SVG сделал всего два запроса HTTP, а не пять. Если у вас большой монитор, то браузер скачает маленький файл SVG (676 байт) и огромный huge.png или huge.jpg.

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

Чудеса происходят при включении SVG в гибкую разметку. Вы заметите, что при первом же изменении размера изображения браузер может мигнуть белым, когда запрашивает следующий нужный PNG — из-за того, что не загружает автоматически все материалы. Вместо этого он скачивает только нужный ему материал. Просто заявите ширину или высоту контейнера (img, svg или object) с помощью CSS в своих медиазапросах к разметке, и SVG извлечет единственное нужное ему растровое изображение.

У нас все еще есть сам файл SVG, которому требуется запрос HTTP, когда тот не встроен внутрь с помощью svg. В третью очередь мы решим и эту проблему.

Проблемы безопасности контента

Откройте в Opera или Windows 9 или 10 файл HTML, содержащий растровое изображение SVG, привязка к которому сделана с помощью тэга img. Обратите внимание в панели Ресурсы (Resources) инструментов разработки, что скачивается только один JPEG или PNG. Измените размер браузера. Заметьте, что img — адаптивный. Дополнительные JPEG’и или PNG’и (также можно было бы использовать GIF или WebP) скачиваются только когда нужны.

Если открыть файл HTML, содержащий растровое изображение SVG в Firefox’е или WebKit’е, скорее всего, вы не увидите никакого изображения. SVG работает во всех современных браузерах, но img, вызывающий SVG, который извлекает растровые изображения, работает только в Opera и IE 9+. Сначала мы рассмотрим, как он работает в IE и Opera, а затем раскроем проблемы с WebKit’ом и Firefox’ом. Код простой:

Когда вы включаете SVG в своего HTML с гибкой шириной, такой как 70% окна просмотра, при увеличении и уменьшении контейнера путем изменения размера окна или с помощью CSS изображение будет реагировать соответственно. Медиазапрос width в SVG базируется на родительском элементе, в котором содержится SVG — в данном случае img — не на ширине окна просмотра.

По мере увеличения и уменьшения окна изменяется изображение, отображаемое SVG. В файле SVG изображения определены, как имеющие 100% высоты и ширины родительского элемента, которым в вышеприведенном случае, когда мы напрямую открыли SVG, было окно просмотра. Теперь контейнером стал элемент img. Так как мы включили атрибуты viewbox и preserveAspectRatio, то пока определена хотя бы одна длина, SVG будет увеличиваться или уменьшаться в соответствии с ней, поддерживая заявленное соотношение размеров в SVG, каким бы ни был размер изображения.

Такие изображения переднего плана идеально работают в Opera и IE 9+ (в версиях, которые можно обнаружить в мобильных устройствах). В Chrome и Safari, если вы сначала откроете файл SVG, таким образом кэшируя его, то файл HTML, содержащий изображение переднего плана SVG, тоже может сработать.

Тогда как ранее мы видели, что браузер действительно может визуализировать SVG, если SVG включен в наш документ посредством тэга img, этот отдельный вид SVG не сможет быть отображен. Почему? Для предотвращения кроссдоменных скриптовых атак в некоторых браузерах установлена стратегия безопасности контента для того, чтобы удержать SVG от импорта информации или скриптов на тот случай, если они по своей природе носят угрожающий характер.

Блокирование SVG от импортирования скриптов и изображений имеет смысл: чтобы предотвратить кроссдоменные скриптовые атаки, вам не нужно, чтобы файл извлекал потенциально опасный контент. Поэтому SVG поддерживается, но, в случае с WebKit’ом и FireFox’ом, ограждается от извлечения внешних растровых изображений. Я представил на рассмотрение отчет о дефекте в Chrome, чтобы снять запрет на импорт растровых изображений в SVG.

В Firefox’е адаптивный SVG также работает сам по себе. Firefox полностью поддерживает SVG. Однако в целях безопасности Firefox блокирует импорт внешних растровых изображений, даже если они находятся на одном и том же домене. Объясняется это тем, что возможность посетителей выгружать, а затем отображать эти изображения и скрипты как часть SVG составляет риск обеспечения безопасности. Я бы сказал, что если вебсайт использует небезопасный контент, созданный пользователями, то он уже поступает плохо. Эта простая строка…

… блокируется в некоторых браузерах и, таким образом, не является жизнеспособным решением. Все браузеры поддерживают медиазапросы SVG. Все поддерживают SVG в качестве изображений переднего плана или «контентных» изображений. Все они поддерживают SVG как фоновые изображения. Просто из-за браузерных стратегий безопасности поддержка не одинаковая. Все браузеры поддерживают тэг object. Без изменения браузерных политик безопасности один img еще не будет работать. Мы можем применять тэг object.

С ПОМОЩЬЮ ТЭГА OBJECT

Элемент object дает внешнему ресурсу возможность применяться как изображение. Он может позаботиться о браузерной безопасности, которые ставятся элементу img, не позволяя ему импорт изображений или скриптов в файл img. Элемент object дает возможность делать и то, и другое. Код не очень сложный:

По умолчанию object будет таким же по ширине, как и родительский элемент. Однако по отношению к изображениям можно заявить ширину или высоту с помощью атрибута width или height, или с помощью свойства CSS width или height. В методике clown car для поддержания заявленного соотношения размеров нужно просто объявить одно из значений длины.
Из-за заявлений viewbox и preserveAspectRatio в файле SVG по умолчанию object будет поддерживать заявленное соотношение размеров. Переписать его можно с помощью атрибутов HTML или CSS.

Как уже об этом упоминалось, медиазапросы в SVG соответствуют контейнеру SVG, а не окну просмотра. Подходящие медиазапросы в файле SVG будут отражать родительский элемент тэга object, а не окно просмотра. Если посмотреть на SVG, извлеченный как данные object, вы увидите, что он работает во всех браузерах, поддерживающих SVG.

С ПОМОЩЬЮ ТЭГА SVG

Вместо включения внешнего файла SVG можно также включить svg как встроенный контент с помощью тэга svg. Преимущество метода – отсутствие дополнительного запроса http к внешнему файлу .svg. К сожалению, Chrome и Safari визуализируют SVG как полноэкранный блочный элемент изображения и, похоже, не поддерживают атрибут preserveAspectRatio, когда тот включен подобным образом (они поддерживают preserveAspectRatio,когда SVG включен посредством тэга object).

Еще один недостаток состоит в том, что в отличие от object, мы не можем включить альтернативный контент для браузеров, не поддерживающих SVG. Вместо того нам понадобилось бы включить background-image с height и width к svg для тех браузеров, которые не поддерживают SVG.

АЛЬТЕРНАТИВНЫЙ ВАРИАНТ ДЛЯ IE

Элемент object поддерживается всеми браузерами, даже мобильными. Но эта техника работает, только если браузер также поддерживает SVG. Следовательно, она не работает в IE 8 и ниже или в Android 2.3 и ниже. Для этих старых браузеров имеется альтернативный вариант. Также мы делаем два запроса HTTP для извлечения нужного изображения — один для файла SVG и второй для растрового изображения, которое нужно показать – для этого тоже имеется решение.

object более интересен, чем img или svg тем, что он – непустой элемент, который может содержать альтернативный контент, когда браузер неспособен поддерживать тип данных object. Если хотите, для тех браузеров, которые не поддерживают SVG, можно включить тэг img, вложенный в object. Для IE 8 и ниже мы включим растровое изображение среднего размера, потому что при нормальном DPI отображаются на мониторах обычно они:

К сожалению, содержимое, вложенное в object, скачивается, даже если объект визуализируется и вложенный контент не нужен или не отображается. Таким образом, добавляется закачка изображения среднего размера вне зависимости от того, нужна она или нет. Чтобы справиться с этой проблемой, можно применить условные комментарии для IE.

Единственный запрос HTTP

Мы ограничили SVG до закачки одного растрового изображения. Способом object скачиваются и растровое изображение, и файл SVG. У нас получается два запроса HTTP вместо одного. Для предотвращения дополнительных запросов HTTP можно создать URI – унифицированный идентификатор ресурса данных SVG – вместо вызова внешнего файла SVG.

Вышеприведенный код кажется беспорядочным, но вкратце это просто data:image/svg+xml, за которым следует содержимое файла SVG. Это тот же код, который мы включили бы, если бы пользовались svg контента, но этот метод поддерживает атрибут SVG preserveAspectRatio.

Он работает во всех браузерах, поддерживающих SVG, кроме IE. Сплошное расстройство, но на самом деле это из-за того, что Microsoft пытается в точности следовать спецификации. В ней определено, что следует избегать URI данных. Поэтому чтобы заставить поддерживать URI данных все браузеры, включая IE 9 и 10, мы его избегаем:

Уродливая разметка, но она работает! Откройте первую и вторую страницы, а затем откройте инструменты разработки для пристального изучения запросов HTTP. Вы заметите два запроса HTTP: файл HTML и PNG, который извлекает SVG. Инспектор также покажет вхождение файла SVG. Но обратите внимание, что никакого запроса HTTP не было сделано: статус SVG — “success”, а размер над сетью – 0 байт при размере унифицированного индикатора ресурса данных SVG менее 600 байт.

Альбомная ориентация против книжной

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

Волшебство этой методики в том, что визуализируемое изображение меняется в зависимости от размера контейнера. Можно установить изображение переднего плана в альбомной ориентации на 33% или 240 px или что-нибудь еще, а ширину объекта в книжной ориентации на 25% или 180 px или как-то еще. Размер объекта определяется CSS к вашему HTML. Подаваемое растровое изображение основано на медиазапросах, соответствующих размеру объекта.

Соотношение размеров остается тем же, но вы можете контролировать, какое растровое изображение предоставляется, меняя пропорции контейнера SVG, сопоставляющего медиазапросы в CSS вашего HTML с медиазапросами в CSS вашего SVG.

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

Прочие преимущества

Еще одно преимущество техники clown car заключается в том, что вся логика остается в файле SVG. Подобно тому, как мы отделяем контент от его презентации и поведения, этот метод дает нам возможность отделить логику изображения от содержимого. Элемент img или object — часть контента, но логика, посредством которой это все работает, может быть отделена от уровня содержимого: она находится в изображении SVG вместо засорения ею CSS и HTML. Это преимущество может побудить некоторых выбрать вариант с URI без данных метода object несмотря на дополнительный запрос http, потому что он очень простой и чистый.

Методика позволяет нам аккуратно организовать свои изображения, отделяя поведение от презентации, контента и изображений. Я представляю себе структуру файлов адаптивного изображения примерно так:

Все материалы отдельного изображения находятся в одной обособленной директории. Имена файла изображения последовательны, тогда как имена папок меняются. Получить адаптивные изображения переднего плана можно без засорения своего HTML дополнительным неиспользуемым кодом, облегчая таким образом управление изображением и его обновление.

Недостатки техники Clown Car

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

Я серьезно интересуюсь тем, почему возникающие из методики clown car изображения неспособны вести себя как обычные PNG’и, JPEG’и и GIF’ы. Основные отмеченные мной проблемы – это порядок загрузки, альтернативный вариант для Android 2.3.3 и ниже, доступность и возможность щелчка правой кнопкой по изображению.

РАЗМЕТКА СТРАНИЦЫ

Согласно Джону Уилкинсу (John Wilkins), методике clown car требуется, чтобы разметка CSS полностью визуализировалась до начала загрузки изображений. У меня не было возможности сравнить загрузку обычных изображений переднего плана и элемента object с SVG, извлекающим растровые изображения, поэтому пока не могу комментировать влияние этой проблемы.

ANDROID 2.3 И НИЖЕ

Android 2.3 и ниже не поддерживает SVG. Я отыскал три возможных решения, которые мне еще предстоит детализировать.
SVG с background-image Можно использовать svg как встроенный контент вместо object. Тогда как IE 8 и Android 2.3 и ниже не поддерживают SVG, с помощью CSS эти браузеры могут выдать разметку svg с высотой и шириной, а затем заявить растровое изображение как значение background-image.

Так как наша цель – создание адаптивных изображений переднего плана без применения фоновых изображений CSS, этот хак обратной совместимости нам не подходит. Если мы так решили, то почему бы не применить для всех браузеров и устройств фоновые изображения CSS вместо методики Clown Car?

Условные комментарии

Сначала нужно включить условные комментарии для включения среднеразмерного альтернативного варианта для IE 8 и ниже и малоразмерную альтернативу для всех браузеров, игнорирующих условные комментарии (включая IE 10):

Этот альтернативный вариант будет показывать маленький PNG во всех телефонах с Android. К сожалению, все браузеры, кроме IE 9 и ниже, скачают small.png, даже если изображение не будет показываться. В попытке решить эту проблему для старого Android’а мы без всякой на то необходимости скачиваем маленький PNG на большинство устройств.

Обнаружение свойства с помощью JavaScript

Другое решение – обнаружение свойства с помощью JavaScript — т.е. тестирование поддержки SVG. Включите класс .no-svg в элемент html, если браузер не поддерживает SVG. Используйте медиазапрос с префиксом WebKit для того, чтобы исключить браузеры не-WebKit, определяя объекты как показано здесь:

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

ДОСТУПНОСТЬ

Преимущество img в том, что сделать его доступным способен простой атрибут alt. У элемента object нет атрибута alt. Идея сделать изображения clown car общедоступными включает следующее:

Добавьте в файл SVG title и desc.

Добавьте role=»img» и другие атрибуты ARIA, такие как aria-label и aria-labeled-by.

Включите tab-index=»0″ для того, чтобы object попал в фокус без изменения порядка закладок.

Добавьте атрибуты alt к альтернативным изображениям.

Добавьте альтернативный текст между открывающими и закрывающими тэгами object.

Функция VoiceOver универсального доступа в Mac OS X читает содержимое title SVG и значение атрибута aria-label к object, когда object включает tabindex=»0″. Пока еще нужно провести тестирование страницы проверки доступности с помощью настоящих экранных дикторов.

ЩЕЛЧОК ПРАВОЙ КНОПКОЙ ДЛЯ СОХРАНЕНИЯ

При щелчке правой кнопкой по изображению в браузере десктопа вы получите меню, в котором можно сохранить изображение. В некоторых телефонах приглашение к сохранению вызывается длительным нажатием на изображение. Это не работает с object или фоновыми изображениями, из чего сделан наш SVG.

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

Если невозможность щелкнуть правой кнопкой для сохранения – это ваш основной аргумент против этой техники, то припомните, что тогда как пользователи могут щелкнуть правой кнопкой по изображениям WebP в тех браузерах, которые поддерживают WebP (только Chrome и Opera), с этими изображения мало что можно сделать из-за того, что исходные приложения не поддерживают новый формат. Но это не должно препятствовать нам двигать вперед методики экономии пропускной способности и свойства.

Почему «Clown Car»?

С подачи Кристофера Шмитта (Christopher Schmitt) и Эми Грегори (Amie Gregory) я называю эту технику «clown car» (классический цирковой номер, когда из очень маленького автомобиля выходит огромное количество клоунов – прим. перев.), потому что она помещает множество больших изображений (клоунов) в единственный крошечный файл изображений SVG (автомобиль). Нам приходится пользоваться несемантическим элементом object для стимуляции браузерных вендоров к поддержке растровых изображений в SVG как источника img через CORS или CSP.

Техника clown car – то решение, которым можно пользоваться уже сейчас. Клеветники говорят, что решением являются picture и/или srcset, не убеждая меня в том, что методика clown car является неправильным ответом. Некоторые спорят, что недостаток поддержки в Android’е – это его погибель, забывая при этом, что picture или srcset в Android 2.3.3 и IE 8 тоже не поддерживаются.

Я верю, что элемент object можно сделать общедоступным. Хотя недостаток семантики и является его недостатком, я с удовольствием стану применять эту технику, как только будет гарантирована ее общедоступность. Ее тестирование станет моим следующим приоритетом. Хотя я предпочту видеть этот элемент работающим с более простым и семантическим тэгом img, как только решится проблема доступности, и эта техника будет полностью готова.

Автор: Estelle Weyl

Источник: //coding.smashingmagazine.com/

Редакция: Команда webformyself.

Метки: , ,

Похожие статьи:

Комментарии Вконтакте: