Почему мы не можем делать по-настоящему адаптивные изображения при помощи CSS или JavaScript

Перевод статьи Why we can’t do real responsive images with CSS or JavaScript с сайта brucelawson.co.uk, c разрешения автора — Брюса Лоусона.

Среда, 21 января 2015

Я пишу доклад на тему <picture>, srcset и их «товарищей» для конференции Awwwards в Барселоне через месяц (да, я знаю, что это неслыханный запас по времени; но я планирую поехать отдохнуть в течении двух недель). Я решил, что, прежде чем перейти к основной теме, я должен ответить на вопрос «Зачем вся эта новая сложная разметка? Почему бы просто не использовать CSS или JavaScript?», поскольку его неизменно задают.

Скорее всего вы не сможете увидеть меня в Каталонии, чтобы это выяснить, из-за того, что почти все билеты проданы. Поэтому отвечу здесь.

У всех браузеров есть такая вещь, как «прелоадер». По мере того, как браузер «перемалывает» HTML — даже не начав еще строить DOM — прелоадер видит «<img>» и мчится доставлять ресурс, пока у него нет даже догадки о мысли о намерении начать что-либо делать с CSS или JavaScript.

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

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

<img id=thingy src=picture.png alt="мужик в купальнике">
@media all and (max-width:600px) {
 #thingy {content: url(medium-res.png);}
 }

@media all and (max-width:320px) {
 #thingy {content: url(low-res.png);}
 }

вы заметите, что правильное изображение выбирается медиа-запросами (предполагая, что ваш браузер поддерживает свойство content в простых селекторах без псевдоэлементов :before или :after), но вы обнаружите, что прелоадер загрузил ресурс, указанный в <img src>, а затем ресурс, на который CSS его заменяет, загрузился тоже. Поэтому вы получите двойную загрузку, а это совсем не то, что вам нужно.

Как вариант, можно воспользоваться <img> без атрибута src, а затем добавить его с помощью JavaScript но тогда вы загрузите ресурс намного позже, задерживая загрузку страницы. Из-за того, что ваш браузер не знает ширину и высоту изображения, которое подберёт JS, он не может оставить под него место при раскладке страницы, поэтому вы можете заметить, что страница перерисовывается и, если в это время пользователь читал какое-то текстовое содержание, он, возможно, обнаружит, что материал, который он читает, оказался за границами видимой области экрана.

Поэтому единственный способ справиться с прелоадером — проставить все потенциальные ресурсы изображения в HTML и предоставить браузеру все данные, которые необходимы, чтобы ему также было из чего выбирать. Вот для чего предназначены дескрипторы w и x в srcset и атрибут sizes.

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

P.S. Это тоже может быть интересно:

13 Комментарии

  1. AQuA

    Но почему же мы не можем продолжать использование старого доброго трюка? Я тут имею в виду следующее:

    в атрибуте src тега img указываем повсюду одну и ту же картинку для всех изображений (например, однопискельную или вариант анимированного loader.gif)
    основную содержательную картинку грузим через CSS подстилаем под тег img в качестве его background-imige.

    1. SelenIT

      К сожалению, при таком подходе при попытке "Сохранить картинку как…" по правой кнопке пользователю на любом экране будет сохраняться именно пустая гифка. И при печати страницы могут быть неприятные сюрпризы.

      На мой взгляд, если уж обращаться к «дедовским способам», то скорее проблему решит динамическая вставка тега <img> с нужными параметрами блокирующим скриптом через document.write(). Нужно тестировать, насколько это замедлит загрузку — возможно, одна коротенькая вставка тяжелой картинки будет и не так уж фатальна…

      1. AQuA

        Несогласен.)) Во-первых, описанный трюк изначально применялся как раз именно с целью "спрятать" от пользователя ту или иную закопирастенную картинку. А уж  возможность подстилать разный фон появилась значительно позднее — лишь с появлением @media. Так что невозможность сохранения картинки при правом клике указывать в качестве недостатка при таких исторических реалиях было бы неверно, ибо это следует как раз рассматривать в качестве достоинства, — теперь побочного, а прежде основного.

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

        Про document.write() вообще промолчу, ибо при наличии @media, — предоставляющего весьма широкие возможности и поддерживающего страницы функциональными при отключённых в настройках барузера скриптах,  — пользоваться write() в данном случае абсолюно неуместно.

        Насколько гибко можно адаптировать страницы лишь при помощи @media, можно посмотреть, на примере проекта музыкального зеркала Анастасии (где в качестве основной технической задачи как раз и было обеспечение функциональности страницы в режиме отключённых скриптов). В частности, фон страницы для мобильных узкоэкранных устройств выбирается маловесный как раз через @media. Аналогичным образом возможно поступить с любой  картинкой, вес которой критичен.

        Для печати же лучше прописывать отдельный стилевой файл.

        1. SelenIT

          Если невозможность сохранить картинку как картинку штатным образом рассматривать как достоинство (правда, непонятно для кого — рассматривать это как защиту контента несерьезно), и для печати картинки не нужны, то зачем вообще использовать img? Это просто другая задача — адаптивность оформления. А вопрос об адаптивности картинок в контенте, которые бывает нужно и сохранить, и распечатать.

          Для отключенных скриптов в тех же исторических реалиях был введен элемент noscript, и HTML5 его не отменяет.

          1. AQuA

            Хотелось бы отметить, что noscript ничуть не решает задачи выбора картинки (нужного размера и веса) в зависимости от параметров экрана. ;-)

            А вот принципиальный отказ от скриптов в решении этой задачи и перекладывание её решения всецело на @media прекрасно позволяет справиться с этой задачей (а также с рядом иных задач).

            Что же до использования тега <img>, то — вот не поверите же!)) — как раз о его бесполезности и анахронизме («дедовском способе») я и подумал почти сразу же, как отправил предыдущий комментарий.

            Небесполезно заметить, я думаю, что уже давно устоявшейся практикой размещения графической информации на веб-странице является следующий приём. В общем контейнере располагают парочку абсолютно-позиционированных с кооординатами (0;0) элементов, которым приписывают 100% ширины и высоты.  (Обычно span или div, хотя подойдёт практически что угодно; более того, они могут быть разными, если кому-то угодно поизвращаться, или даже в качестве верхнего пожно использовать псевдоэлемент ::after или ::before.) Различаются они лишь значением z-index и, конечно же, своим содержимым: верхний из элементов несёт картинку в качестве своего фона, а нижний содержит полноценно отформатированный замещающий текст. Когда картинки в браузере отключены, то в подобной конструкции не возникают уродливые иконки отсутствующих изображений, помещаемых обычно браузерами вместо отсутствующих картинок; отсутствует также и проблема с форматированием текста, размещаемого в параметре alt (весьма уродующего порой страницу в режиме отключённых картинок).

            Что может быть изящней, функциональней и удобней этой конструкции?! Наверняка, Вам она тоже встречалась. Мне она впервые попалась несколько лет назад в дизайне сайта w3.org (обратите внимание на их логотип в верхнем левом углу). Затем стал обращать внимание, что эта конструкция уже практически стала стандартной на сайтах, изготавливаемых профессионально. По приведённой выше ссылке на сайт Анастасии Вы также сможете это решение найти в топе страницы; причём, размеры и сама картинка меняются при помощи @media, как это уже было описано выше, — давая полноценный адаптивный дизайн (т.е. без той проблемы выбора подходящего веса картинки, что описана в обсуждаемой переводной статье).

            Ну, и по поводу "рассматривать это как защиту контента несерьезно" — это смотря для кого. К примеру, я могу стащить практически что угодно, хотя в некоторых случаях для этого мне приходилось весьма серьёзно перекапывать текст CSS или JS; лишь в нескольких случаях, которые можно пересчитать по пальцам, мне не удалось разыскать желаемое (когда адрес был зашифрован, и мне было лениво заниматься дешифрованием). Однако абсолютное большинство посетителей веб-страниц практически безграмотны в вопросах веб.

            И, собственно, это уже совсем иной вопрос — вопрос этики и вопрос отношения к авторскому и пиратскому правам как таковым. Он требует совершенно отдельного рассмотрения. Поэтому тут лишь вскользь отмечу, что меня подобное "ослоумие" вебмастеров тоже раздражает. К примеру, жутко раздражает также, когда при копировании текста со страницы мне навязчиво в буфер обмена подсовывают ссылку на сайт (ещё притом и убирая абзацы, как это делают на rbc.ru), вынуждая меня затем совершать дополнительные действия по удалению ненужной мне ссылки. Конечно же, проблема решается элементарным отключением JS для такой проблемной страницы… С сохранением картинок примерно такая же ситуация. Именно поэтому я и предлагаю описанную здесь хтмл-конструкцию оборачивать тегом <A> с прямой ссылкой на качественное изображение, и при этом способе решается одновременно обе проблемы: и экономия трафика (т.к. большая картинка загружается лишь по специальному запросу посетителя), и возможность/невозможность сохранения картинки правым кликом мыши.

            1. SelenIT

              <noscript> рассматривался как крайний аварийный случай. Естественно, он не адаптируется, но с ним пользователь гарантированно получит (по правому клику или при печати) хоть что-то, пусть и не идеального качества — а не ничего,как в CSS-варианте.

              То, что вы описываете, называется Image Replacement (IR), точнее, это одна из его техник. Не самая худшая (по крайней мере, при отключенных/недогрузившихся картинках можно хотя бы прочитать текст, в отличие от не менее популярных методов с text-indent:-9999px или font-size:0), но и не универсальная (напр. нельзя или очень сложно использовать картинку с прозрачностью). Мне из способов IR больше всех нравится этот.

              А вот идея и впрямь совсем отказаться от <img>, заменив его интерактивной CSS-превьюшкой и ссылкой на полноразмерную картинку, и впрямь интересная! Осталось только додумать вопрос насчет печати.

              1. AQuA

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

                Про печать, честно признАюсь, ещё никогда не задумывался по-серьёзному. Ну, не волновала меня печать) Хотя одним из вариантов всё ещё весьма распространённых и, я думаю, достаточно удачных, является пересылка на специальную страницу с облегчённым дизайном (на важно, по ключу ли строки запроса или в иную папку). В общем, я этой техники и придерживаться намерен.

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

                Ведь поглядите, что на практике имеем — имеем две совершенно разных задачи, определяемых назначением сайта.

                Вариант 1-й — это когла сайт (или его часть) являет собой фотогалерею (или нечто подобное), и тогда проблема адаптации не стоит как таковая, поскольку посетитель и идёт на такой сайт как раз с целью получения тяжёлых качественных изображений.

                Вариант 2-й — общий, т.е. когда изображения используются лишь для оформления GUI сайта. В этом варианте следует принципиально отказаться от использования тега img, и пременять Image Replacement. (Кстати, благодарю за подсказку термина — погляжу подробнее, что это за зверь; а то с теорией, конечно же, у меня есть некоторые проблемы))

                Итак, в результате обсуждения мы вроде как приходим к выводу, что сформулированаая автором переводной статьи проблема с адаптацией img является надуманной! Не так ли?

                1. SelenIT

                  На заре обсуждения адаптивных картинок так думал и редактор спецификации :). Но проблема есть, и именно в варианте 1-м. Суть ее в том, что критерии «тяжести» и «качества» картинок очень различаются у пользователя iMac Retina с 5k-экраном и у пользователя древнего смартфона вне зоны действия 3G :). Каждому из них нужен свой компромисс между качеством и трафиком. И средствами CSS, без хаков или новых элементов типа <picture> в разметке, это полноценно не решить. Есть, конечно, остроумный вариант на базе SVG и CSS уже в нем, но это в общем-то тоже хак…

                  1. AQuA

                    Благодарю за ссылки. Весьма интересно было узнать, над чем сейчас передовые разработчики головы ломают.)

                    Однако единственный вывод из всего я извлёк: не следует торопиться с использованием новшеств.)) Ведь, судя по наполнению веба (во всяком случае рунета), едва ли потребители услуг вебразработки сколь-нибудь обеспокоены проблемой адаптивных картинок. Во всяком случае, если и обеспокоены, то единицы, а основной массе даже невдомёк, что там и как происходит прежде чем вебстраница станет видимой на экране. Стало быть, если потребитель не готов оплачивать дополнительные усилия вебразработчика, то нет смысла и слишком усердстовать.)

                    Следует помнить, что помимо проблемы оптимизации качества и веса картинки существует ещё и проблема оптимизации трудозатрат вебразработчика.)

                  2. cow

                    Тег <img>  применяется исключительно в первом варианте, когда картинка является контентом.

                    В мире ( в том где ходят 99% денег за веб) вообще не существует проблемы " смартфона вне зоны действия 3G".

                    В странах 3 мира, например в Польше, еще пока есть проблема "смартфона вне зоны 4G" и то не в крупных городах.

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

                    На серьезных проектах ее решение экономит большие деньги.

                    На практике, никто не заставляет сразу грузить тяжелую картинку .

                    Она может быть достаточно низкого качества, но правильного размера.

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

                    на клиенте ( например при попытке ее ресайза).

                     

                     

                    1. SelenIT

                      В принципе, логично. Прогрессивное улучшение как оно есть: по умолчанию — хоть что-то, но побыстрее, по желанию и возможности — конфетку. Но делать это скриптами для всех случаев не так уж тривиально, к тому же скрипты тоже что-то весят. Если можно переложить эту логику на сам браузер, почему бы этого не сделать?

  2. cow

     Если можно переложить эту логику на сам браузер, почему бы этого не сделать?  — боюсь мы это сможем

    сделать только для очень ограниченного списка случаев.  Для всех остальных понадобятся сценарии написаные

    человеком для конкретного сайта.

    1. SelenIT

      Сценарии, естественно, задаются человеком. Просто этому человеку предоставляется более высокоуровневый механизм описания этих сценариев, позволяющий сосредоточиться на самом желаемом поведении, а не технических подробностях реализации. По крайней мере, такова задумка. Получится ли и приживется ли — время покажет…

Оставить комментарий

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

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

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