Подписывайтесь на мой твиттер, там всегда что-нибудь интересное!

CSS свойство background-image как антипаттерн

CSS свойство background-image позволяет нам делать крутые вещи, но в большинстве случаев наступило время оставить его позади. На всякий случай — что такое антипаттерн.

Перевод статьи The CSS background-image property as an anti-pattern

Многие из нас набили руку, используя такое свойство CSS как background-image, делая c ним всё, что только можно. Для многих оно стало просто старым хорошим товарищем, но уже видимо тем, с которым пора распрощаться.

Сама проблема заключается не в свойстве background-image как таковом. Зачастую оно используется там, где ему совсем не место, например в CTA изображениях или для графики, имеющей отношение к элементам UI.

Если использовать его неправильно, то оно вполне может стать антипаттерном. Но есть ли подходящие кейсы для использования background-image? Несомненно есть.

Однако, есть несколько серьёзных недостатков при использовании background-image и что куда важнее, уже сейчас у нас есть способы действительно лучше подходящие для работы с изображениями.

Давайте не будем вспоминать дни танцующих хомячков на фоне.

Перейдем к делу и поговорим о конкретных недостатках использования background-image и затем о том, что мы можем использовать вместо него.

Вот несколько причин почему использованием background-image может быть плохой практикой в вёрстке:

Это плохо для SEO

Изображения, которые лежат в background-image не краулятся или не индексируются Google. Не велика проблема, да? Тогда посмотрите эту цитату из статьи How to Rank in Google Image Search на moz.com:

Треть всех поисковых запросов в Google выходит на изображения и 12.5% страниц с результатами поиска показывают блоки(карточки) с результатами для изображений.

Давайте призадумаемся. Одна треть или 33% всех запросов в Google выходит на изображения. Если картинка релевантна теме страницы или бизнес направлению вашего клиента (а если и нет, то возможно должно быть), вам точно нужно быть проиндексированным.

Если вы используете background-image, то тут вы в пролёте и у вас не может быть тега alt=«», чтобы отдать Google описание и контекст изображения.

Это плохо для доступности (Accessibility)

Свойство background-image не очень хорошо сказывается на доступности. Скринридеры будут полностью его игнорировать.

Посмотрите на ограничения с доступностью в этом случае:

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

Даже если скринридеры не полностью игнорируют изображения, в фонах которых нет текста alt="", который может дать полезное описание об изображении или передать его контекст.

Совет: Если вы хотите, чтобы скринридер пропустил изображение (ну вдруг это просто элемент дизайна), просто оставьте alt="" пустым (использование role="presentation" тут не самый оптимальный вариант, так как оно нарушает первое правило ARIA).

Плохо для производительности

Как свойство background-image может негативно влиять на производительность?

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

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

Тут ощутимая разница будет заметна на мобильных устройствах или при медленных интернет соединениях, так же как и на вычислительной мощности, требуемой для масштабирования изображений. Посмотрите статью Post-Mortem: Applied Image Optimization.

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

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

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

Так как это всё слишком замудрено, люди просто забивают на этот момент и в итоге имеют одну версию изображения для всех размеров экранов и разрешений.

Хотя и есть всякие JavaScript библиотеки как bgset, но зачем добавлять ещё больше JavaScript для решения проблемы у которой и так много недостатков?

Добавьте к этому желание использовать фишки следующего поколения, такие как WebP, как прогрессивное улучшение и всё станет реально плохо с подходом на background-image.

Ваш браузер просто не может начать скачивать изображение до того, как он не скачает и не запарсит CSS.

Ещё одна польза в том, что если ваши изображения вставлены в CSS через background-image, браузеру нужно скачать и запарсить ваш CSS, перед тем, как он сможет запросить изображения.

Это говорит о том, что ваше “основное” изображение будет понижено в очереди загрузок и довольно медленно загрузится, имея низкий приоритет. Если вы используете изображения через HTML элементы, то браузер может запросить их куда быстрее, иногда даже перед началом загрузки стилей страницы.

Плохо для CMS и CDN

Свойство background-image также не очень хорошо, если дело касается CMS’ок и CDN’ов.

Давайте представим, что у нас есть главное изображение на сайте, которое я показываю с помощью background-image в div.

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

Если у меня есть ссылка на изображение, вставленная в CSS, то я сделаю глобальный поиск в редакторе и заменю все свои изображения, а вернее ссылки на них с локальных на CDN’овские.

Если вы предварительно выставили ссылки на изображения, как переменные с помощью CSS Variables, то вам повезло! Но большинство людей так не делает и необходимость в создании и деплое CSS с обновленными ресурсами, всякий раз как вы хотите обновить ваши изображения кажется ну уж слишком избыточной для работы с таким таском. Но придется делать либо так, либо генерить инлайновый CSS, но давайте уже обойдемся без этого.

Куда проще просто дать вашей CMS добавить URL префикс, но это может стать грубоватым подходом, если вы делаете это через CSS background-image, требующим генерацию инлайновых стилей или же если вы прибегаете к другим махинациям с вёрсткой.

Вообще, вставка ссылок на изображения в CSS сейчас мне кажется каким-то хардкодингом.

Ну так, а когда это выходит хорошим подходом?

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

Это покажется слишком очевидным, но если вам надо просто добавить декоративное изображение как фон, то это именно тот кейс, в котором нужно использовать background-image!

Хорошо использовать background-image тогда, когда вам нужно просто фоновое изображение и ничего более.

Если вы так делаете, то рассмотрите использование image-set() вместе с background-image(), чтобы уменьшить проблемы с производительностью, упомянутые выше.

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

Используйте <picture>!

Я полагаю, что весьма весомой причиной широкого использования background-image является сопутствующее свойство — background-size: cover;, которое точно даст вам знать, что заданное изображение покрывает всю положенную область, к которой оно прикреплено.

Свойство object-fit уже спешит на помощь!

Если вы используете семантически верный элемент в купе со свойством object-fit, то вы получите тот же самый эффект, что и в случае с background-size: cover;, но также вы получите ещё и такие плюшки: SEO-friendly изображения.

Изображения, которые будут читаемы скринридерами. Тут нужно просто использовать свойство alt="".

Отличную работу с CMS сгенерированными ссылками на изображения и CDN’ами.

Этот подход будет отлично работать с srcset для оптимизированных изображений

Вы сможете использовать <source> для передовых форматов изображений, таких как .webp.

Это вообще не сложно сделать, а профитов немерено! Свойство object-fit указывает изображению или видео то, как оно должно умещаться в родительский контейнер. Вам нужно просто поменять это:

<div style="background-image: url('/some/man-with-a-dog.jpg');
            background-size: cover;">
</div>

На это:

<picture>
  <img src="/some/man-with-a-dog.jpg"
       alt="Man with a dog"
       style="object-fit: cover;"
  />
</picture>

Очевидно, что в обоих случаях вы бы не стали использовать инлайновые стили, но к нашей радости вы можете видеть то, какой гибкий подход у нас есть под рукой, если бы мы оставили background-image свойство и использовали бы действительно семантические HTML элементы, такие как <picture> и <img>.

Затем мы можем в лёгкую добавить адаптированные по размерам изображения через srcset. Мы также можем легко использовать передовые форматы, такие как .webp на выбор браузера из <source>.

Более того, мы можем воспользоваться преимуществом таких плюшек, как нативная ленивая загрузка в Chrome, ну и в других бразуерах тоже, как только они её внедрят.

Вот как бы выглядел код, который делает все эти вещи:

<picture>
    <source
        srcset="/some/_1170x658_crop_center-center/man-with-a-dog.webp 1170w,
                /some/_970x545_crop_center-center/man-with-a-dog.webp 970w,
                /some/_750x562_crop_center-center/man-with-a-dog.webp 750w,
                /some/_320x240_crop_center-center/man-with-a-dog.webp 320w"
        sizes="100vw"
        type="image/webp"
    />
    <source
        srcset="/some/_1170x658_crop_center-center/man-with-a-dog.jpg 1170w,
                /some/_970x545_crop_center-center/man-with-a-dog.jpg 970w,
                /some/_750x562_crop_center-center/man-with-a-dog.jpg 750w,
                /some/_320x240_crop_center-center/man-with-a-dog.jpg 320w"
        sizes="100vw"
    />
    <img
        src="/some/man-with-a-dog-placeholder.jpg"
        alt="Man with a dog"
        style="object-fit: cover;"
        loading="lazy"
    />
</picture>

Так мы получаем:

Ленивую загрузку, если браузер её поддерживает (в противном случае они не происходит, всё нормально)

webp, если браузер его поддерживает.

srcset из оптимизированных адаптивных изображений на выбор браузера.

SEO-friendly, прогрессивное улучшение, доступность и производительность — всё это обернуто в одной, хорошо сделанной компактной вундервафле.

Boom!

И все эти изображения могут быть автоматически заресайзены прямо из CMS, с помощью таких инструментов, как ImageOptimize, упрощая ссылаемость на CDN или Amazon S3. И в конце концов, вы же можете делать обрезку изображений с помощью object-fit.

Со старым в новое!

Поддержка бразуерами <picture> и scrset фантастически хороша! (есть даже полифиллы, если они вам нужны.) и такая же хорошая поддержка для object-fit (тоже есть полифилл). Ещё один хороший паттерн для использования через polyfill.io.

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

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

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

Я думаю, что в конечном итоге вы поймете то, что ваши сайты станут более SEO-friendly, более доступны и куда более производительнее… а еще у вас будет ощущение удовлетворенности от написания на семантически грамотном HTML.

Свойство CSS background-image никогда не подразумевалось для использования основных изображений или UI элементов. Но сейчас для этого уже есть способы получше, так что давайте их просто использовать.

Если все это заинтересовало вас в плане оптимизации изображений, обратите внимание на отличную книгу images.guide, чтобы узнать об этом ещё больше!

Enjoy your object-fit!