Изображения на сайтах составляют основную массу передаваемых данных, и оптимизация изображений — это хороший способ эту массу уменьшить.
В этой статье мы будем рассматривать автоматические способы оптимизации изображений, без необходимости отвлекаться на рутинные действия во время разработки.
Практическая реализация будет представлена на примере использования в теме оформления для Drupal 8, но принцип, лежащий в основе, будет общим для любой технологии.
Дополнительным поводом к написанию статьи послужила нативная поддержка формата WebP в самых популярных браузерах, появившаяся с недавних пор.
Но, думаю, что начать будет лучше с обзора ситуации до начала повсеместной поддержки WebP.
Немного истории
Основными графическими форматами в вебе сейчас являются JPEG и PNG, как и на заре появления интернета. Тогда, правда, к ним можно было отнести еще и GIF, который сейчас уже практически не актуален. Всем этим форматам уже более 20 лет.
И тем не менее, оба формата неплохо себя зарекомендовали. JPEG, формат с потерями качества — для изображений фотографического типа. PNG, без потерь — для пиктограмм, иконок и изображений с альфа каналом (прозрачностью). Для обоих форматов есть способы уменьшить размер файла, например, использование современных кодеков для JPEG (Guetzli, MozJPEG), или использование меньшей разрядности (квантование) для PNG изображений с небольшим количеством цветов. Об этом уже написано сотни статей.
Но технологии шагнули далеко вперед, веб вышел на новый уровень, и графические форматы в том числе. Новые прогрессивные форматы также появлялись, но главной проблемой оставалась именно поддержка их браузерами. До недавнего времени…
Формат WebP
WebP был разработан в Google и представлен в 2010 году как универсальный формат для веб изображений с открытым исходным кодом. WebP может использоваться как с потерями качества, так и без, с поддержкой альфа канала для обоих случаев.
При этом в обоих вариантах размер файла в той или иной степени будет меньше по сравнению с JPEG и PNG. Это достигается за счет более современных алгоритмов кодирования и сжатия. В определенных случаях размер файла может быть снижен даже в 10 раз, но в среднем это будет порядка 30%.
То есть да, WebP действительно способен заменить растровые веб форматы и стать единым стандартом.
Приводить примеры изображений, чтоб вы могли попытаться увидеть разницу, я не буду. С высокими уровнями качества (70-99) вы ее все равно не увидите. Использование же совсем уж низкого качества ради экономии нескольких десятков байт — это довольно редкий случай, и мы не будем на него отвлекаться.
Сейчас WebP поддерживается основными браузерами: Chrome, Firefox, Edge. На момент написания статьи — это порядка 75%, актуальная информация тут.
Да, пока мы все же не можем полностью отказаться от JPEG и PNG, они понадобятся для браузеров без поддержки WebP, из актуальных это только Safari.
В графических редакторах нативная поддержка WebP есть в Sketch. Для Photoshop и Gimp существуют плагины от сторонних разработчиков.
По поводу Photoshop замечу, что плагин, который появляется на первой позиции в поиске у меня не заработал (пробовал на версиях CC 2018 и СС 2019 для macOS), но в любом случае, он выглядит довольно устаревшим и содержит ряд ограничений. Мне подошел менее известный плагин, хоть он и в стадии beta.
Еще полноценная поддержка WebP есть в кроссплатформенном просмотрщике/конвертере XnView MP — это удобный инструмент с графическим интерфейсом для пакетной работы с изображениями. Кстати, с его помощью можно производить и оптимизацию изображений, в том числе и в других форматах, программа очень мощная.
Сам же разработчик предоставляет консольные утилиты для работы с форматом WebP, это может быть полезно при работе без графического интерфейса, например, на сервере.
Команды для конвертации и оптимизации изображений
В рамках статьи команды для конвертации нам не понадобятся, но они могут иногда пригодиться в работе, поэтому пусть тоже будут:
Установка пакетов для конвертации и оптимизации в Ubuntu:
sudo apt install optipng libjpeg-turbo-progs imagemagick php-imagick webp
Установка в macOS c помощью Homebrew:
brew install optipng jpeg imagemagick webp
Конвертация из PNG в WebP (здесь и далее используется коэффициент качества 90 из 100):
cwebp -q 90 SOURCE.png -o RESULT.webp
Пакетная конвертация всех PNG файлов в папке в WebP:
for F in *.png ; do cwebp -q 90 $F -o `basename ${F%.png}`.webp ; done
Конвертация из PNG в JPEG:
convert SOURCE.png pnm:- | cjpeg -quality 90 > RESULT.jpg
Пакетная конвертация всех PNG файлов в папке в JPEG:
for F in *.png ; do convert $F pnm:- | cjpeg -quality 90 > `basename ${F%.png}`.jpg ; done
Пакетная оптимизация всех PNG файлов в папке:
find -name '*.png' -print0 | xargs -0 optipng -nc -nb -o7
Пакетная оптимизация всех JPEG файлов в папке:
find . -regex ".*\.\(jpeg\|jpg\)" -print0 | xargs -0 -I filename jpegtran -copy none -optimize -outfile filename filename
Как видите ничего сложного нет, но запускать каждый раз эти команды вручную, согласитесь, было бы неправильно, ведь это можно поручить машине.
Использование изображений в качестве контента
Важно понимать, что изображения могут использоваться в разметке, тег img
— для изображений, являющихся контентом, а также в CSS, свойство background-image
— для изображений, являющихся оформлением.
Все дальнейшие изыскания связаны с тем, что нам нужно не просто указать изображение в формате WebP, а еще и предоставить запасной вариант (фолбэк) в виде JPEG/PNG изображения, если WebP не поддерживается браузером. В идеале было бы предоставлять запасные варианты стандартными средствами, но это не всегда возможно.
В Drupal оформление сосредоточено в темах, этот вариант использования мы разберем подробно на практике, в следующей части статьи.
Изображения в разметке могут быть добавлены разработчиком/контент-менеджером сайта как в виде непосредственно самой разметки (в редакторе), так и с помощью полей, в которые могут загружаться файлы изображений. В последнем случае за формирование разметки будет отвечать один или несколько модулей Drupal. Эти варианты мы разберем поверхностно, ниже.
В стандарте HTML5 был представлен элемент picture
, который может содержать пути к нескольким изображениям, и отображать нужное в зависимости от контекста. В основном это используется для показа нужного изображения в зависимости от ширины и плотности экрана. Но этот механизм может применяться и для показа WebP, если формат поддерживается браузером или показа JPEG/PNG, если не поддерживается.
Вариант использования элемента picture
с двумя типами изображений в виде разметки:
<picture>
<source type="image/webp" srcset="image.webp">
<img src="image.jpg">
</picture>
Это рабочий способ, который иногда приходится использовать, хоть готовить изображения и добавлять такую разметку вручную, не очень удобно.
Получить рабочую конфигурацию, в случае с изображениями, загружаемыми в поля, у меня пока не получилось, но в сообществе ведутся работы в этом направлении.
Существует модуль WebP (на момент написания статьи в стадии beta), который может автоматически генерировать WebP версии загружаемых изображений, и с помощью файла конфигурации веб сервера Apache подменять пути к изображениям. Этот способ лично мне не подошел, так как я использую веб сервер Nginx. Да и просто я не уверен, что это правильный подход.
Но для модуля так же существует патч с попыткой реализации подхода с элементом picture
на основе ядерного модуля Responsive Image. Ему я уделил самое пристальное внимание, но в моем случае он тоже не сработал. Изображения ведь могут использоваться в различных контекстах, в представлениях, в слайдере, в галерее, и пр., и, видимо, мне просто не повезло.
Будем держать руку на пульсе и следить за поддержкой формата WebP в ядре и контрибных модулях. Думаю, что скоро хорошее решение появится, и тогда я дополню эту статью.
Обновление
Подробное описание использования контекстных изображений, включая WebP, читайте в статье Отзывчивые изображения в Drupal 8.Использование изображений в теме оформления
Предположим, что в нашей теме оформления уже используются изображения в формате PNG и JPEG. Пока мы не будем отходить от этой практики, а просто предложим браузеру загрузить вместо этих изображений другие, в формате WebP, если он его поддерживает.
Объединить запись в одно свойство, как в случае с элементом picture
, в CSS, к сожалению, не получится, но можно сделать, например, так:
.element-with-bg {
background-image: url('image.jpg');
}
.webp .element-with-bg {
background-image: url('image.webp');
}
Добавить класс webp
к корневому элементу (тег html
) может JS библиотека Modernizr, которая кстати присутствует в ядре Drupal 8, но в практически минимальном виде, без поддержки WebP.
Это можно исправить, скачав собственную сборку библиотеки на странице загрузки. Перейдя по этой ссылке, будет отмечен пункт "Webp" а так же пункты "Touch Events" и "details Element", которые как раз используются в ядре Drupal. В результате скачается файл modernizr-custom.js
, который надо положить в папку js
вашей темы оформления MYTHEME
.
Теперь надо определить этот файл как библиотеку в файле MYTHEME.libraries.yml
:
modernizr:
js:
js/modernizr-custom.js: { preprocess: 0, weight: -21 }
И переопределить аналогичный файл, который идет в составе ядра, в файле MYTHEME.info.yml
:
libraries:
— core/modernizr
libraries-override:
core/modernizr: MYTHEME/modernizr
Хорошо, класс добавили, но как вы помните, в нашей теме присутствуют только объявления изображений в классических форматах. То есть нам нужно для каждого объявленного изображения создать экземпляр в формате WebP, и создать дополнительное правило с новым классом.
С этим хорошо справится сборщик проектов Gulp и его плагины. О Gulp я уже писал, и если вы его еще не используете, то самое время начать. Статья по ссылке уже немного устарела, вышел Gulp версии 4, его мы и будем использовать.
Для пакетной генерации WebP изображений есть плагин gulp-webp.
Для автоматического добавления класса webp
к объявлениям картинок есть плагин gulp-webpcss.
Первым делом нужно будет установить пакеты для конвертации и оптимизации, команды я приводил выше.
Процесс установки Gulp и плагинов я опущу, но приведу фрагмент описания задачи в gulpfile.js
:
var gulp = require('gulp');
var webp = require('gulp-webp');
var webpcss = require("gulp-webpcss");
var CSS = 'css';
var IMG = 'img';
gulp.task('webp', done => {
gulp.src(IMG + '/src/*')
.pipe(webp({quality: 90}))
.pipe(gulp.dest(IMG));
done();
});
gulp.task('sass', done => {
gulp.src(SASS + '/**/*.scss')
.pipe(webpcss({})
.pipe(gulp.dest(CSS));
done();
});
Добавление класса webp
в моем примере происходит в рамках задачи по компиляции SASS, но фактически преобразования совершаются уже на скомпилированном CSS, так что в данном случае это не принципиально.
На этом этапе мы уже решили обе основные задачи, создание WebP изображения и добавление объявления для него. Но это решение можно улучшить.
По умолчанию, плагин gulp-webpcss генерирует правила подобные тому, что приведено в качестве примера выше. И получается, что до отработки JavaScript мы имеем объявления с ненужными изображениями, даже если браузер поддерживает WebP. Думаю, что в теории возможна ситуация, когда ненужное изображение даже начнет загружаться. Так мы ничего не оптимизируем. Нужно действовать в интересах прогресса и большинства. Настройки gulp-webpcss позволяют переопределить классы как для WebP объявлений, так и для исходных:
gulp.task('sass', done => {
gulp.src(SASS + '/**/*.scss')
.pipe(webpcss({ webpClass: '', noWebpClass: '.no-webp' })
.pipe(gulp.dest(CSS));
done();
});
Это даст нам в итоге CSS вида:
.no-webp .element-with-bg {
background-image: url('image.jpg');
}
.element-with-bg {
background-image: url('image.webp');
}
Класс no-webp
будет добавлен библиотекой Modernizr, если формат WebP не поддерживается. И теперь по умолчанию будут загружаться именно WebP изображения.
Причем остальные свойства сохранят исходную специфичность, то есть плагин делает свою работу с умом. Правда есть одна особенность CSS, которая все же не учитывается. Если свойство определено в сокращенном виде (как background
), то повторное определение обнулит объединенные значения (background-color
, background-repeat
, background-size
и прочие). При использование отдельных свойств такой проблемы не будет.
Но и это решение можно улучшить. Хоть JPEG и PNG и отошли на второй план, почему бы их все равно не оптимизировать?
Для этого есть плагин gulp-imagemin. Плагин использует под капотом уже упомянутые выше optipng
и jpegtran
. Все шикарно работает даже с настройками по умолчанию:
var imagemin = require('gulp-imagemin');
gulp.task('imagemin', done => {
gulp.src(IMG + '/src/*')
.pipe(imagemin())
.pipe(gulp.dest(IMG));
done();
});
И раз уж мы используем Gulp, то поручим ему и всю остальную рутинную работу: сборку SASS c составлением карт (sourcemaps), расстановку браузерных префиксов и отслеживание изменений в файлах для запуска задач.
Полный код файла gulpfile.js
приводить, пожалуй, не буду, но зато, я подготовил стартовый шаблон темы оформления со всеми необходимыми файлами, описанными выше. Я назвал его Dr Webper.
Webper 8.x (ZIP, 506 Кб)
Для его использования надо иметь установленный node.js и Gulp. Сначала надо скачать все зависимости выполнив команду:
npm install
Файлы изображений нужно поместить в папку img/src
либо отредактировать путь в файле gulpfile.js
.
Запуск сборки выполняется командой:
gulp build
Запуск отслеживания изменений:
gulp watch
или просто:
gulp
Мысли на тему оптимизации изображений
WebP хороший формат, но и его надо использовать по назначению. Для иконок, логотипов и подобных им простых изображений лучше использовать SVG. Это векторный формат, с отличной поддержкой браузерами, и при правильном использовании не требует оптимизации или сжатия. Формат имеет текстовую структуру XML и иногда может содержать служебные данные графических редакторов, но обычно они исключаются при экспорте. Сжатие же может производить веб сервер при отправке файла.
Второй важный момент — это использование размеров изображений, соответствующих отображаемым. Чтобы устройствам с маленькими экранами не приходилось загружать большие изображения, которые потом отображаются в уменьшенном виде. Даже с учетом двойной или даже тройной плотности пикселей на мобильных устройствах, изображения должны предоставляться в нескольких разрешениях, каждое в соответствующем медиа запросе. Это актуально больше для контентных изображений и может быть эффективно автоматизированно на стороне Drupal c помощью модуля Responsive Image. Но пренебрегать этими принципами в теме оформления тоже не стоит.
Обновление
Подробное описание использования модуля Responsive Image, читайте в статье Отзывчивые изображения в Drupal 8.Если вы использовали PageSpeed Insights для оценки производительности сайта, то наверняка замечали, что он постоянно жалуется на недостаточную оптимизацию изображений. Это могло происходить даже с оптимизированными изображениями, потому что сервис очень строг к файлам JPEG и PNG. C WebP этого скорее всего не будет. Но не радуйтесь раньше времени, PageSpeed всегда найдет к чему придраться :)
Итоги
По иронии так получилось, что статья про изображения не содержит ни одной картинки. Ну что ж пусть так, главное, чтобы у меня получилось донести смысл.
Автоматизировать генерацию и объявление WebP изображений в теме оформления довольно просто. При этом вам даже не понадобится менять свой привычный способ написания стилей. Сборщик все сделает сам. Использование WebP можно добавить как в существующие темы оформления, так и начать использовать при разработке новой.
Оптимизация изображений — это забота о пользователях, и поверьте, они это оценят. Быстрая загрузка изображений и всего сайта — это и удобно, и приятно, и именно так должен работать современный веб.
Спасибо,статья реально помогла. Была проблема с обнулением background-size из за сокращенного указания св-ва background.
Спасибо! Хорошая статья! Отдельное спасибо за
.pipe(webpcss({ webpClass: '', noWebpClass: '.no-webp' })
. Не мог найти как предотвратить загрузку двух изображений. Загружалось и в .png and .webp