Статьи Архив статей

Автор: Мациевский Николай aka sunnybear
Опубликована: 1 апреля 2009

CSS Sprites 2.0

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

Обзор технологии

CSS Sprites, на самом деле, — всего лишь расширенное использование технологии background, заложенной еще в спецификации CSS1. Все, до чего додумалось прогрессивное человечество за эти годы — это множественный фон у элементов (как он будет совместим с концепцией CSS Sprites еще придется проверить). Основные свойства, которые мы используем для задания фонового изображения.

  • background-image — основная «рабочая лошадка». Именно за ней будущее в виде data:URI, который в конце концов победит CSS Sprites. Но произойдет это нескоро.
  • background-repeat — вторая не менее важная составляющая при использовании фонового изображения. Ведь задавая no-repeat для данного свойства, мы намеренно подчеркиваем, что допустимо использование CSS Sprites для «склейки» изображений (по умолчанию используется repeat).
  • background-position — «волшебная палочка» для CSS Sprites, позволяющая спрятать или показать определенные части фонового изображения.

Кроме заявленных свойств также есть еще несколько (например, background-color), но они к спрайтам имеют посредственное отношение.

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

Прикладные тонкости

Естественно, рассматривая набор возможных эффектов при использовании фоновых изображений стоит отметить следующие:

  • Объект, полностью заполненный фоновым изображением. Здесь основную роль играют конечные размеры объекта (конечно, если изображение не повторяется по всем осям сразу: в таком случае использовать его для CSS Sprites не представляется возможным). Довольно часто фон под объектом может меняться в зависимости от каких-либо условий (преднамеренный акцент или действия со стороны пользователями), но для логики создания CSS Sprites это несущественно. Здесь же можно выделить три подслучая, соответствующих неповторяющемуся фону и повторяющему по оси X или Y.
  • Фоновое изображение заполняет не весь предоставленный ему объем (либо размеры объекта не заданы, либо заданы в относительных — em, % — единицах). Тут нам необходимо либо прикреплять повторяющееся изображение «в конец» спрайта, чтобы на той части объекта, что осталась без фонового изображения, не проявлялось никаких дефектов. Либо (в случае no-repeat) расположить изображения «лесенкой» (это особенно актуально в случае фона для элементов списка). Стоит отметить, что в зависимости от значения background-position CSS Sprites здесь могут быть как возможны, так и не возможны в принципе (например, в случае 100% 100%). Тут можно выделить еще несколько случаев, различающихся по background-position, background-repeat и линейными размерами блока.
  • Изображение является анимированным. Поскольку далее речь пойдет о применении PNG и JPEG-изображений для CSS Sprites, то анимированные изображения придется сразу выбросить из рассмотрения: поддержка анимированных PNG-изображений находится сейчас на самом зачаточном уровне в браузерах.

Все описанные примеры можно более четко структурировать по следующим группам.

  1. background-repeat: no-repeat, background-position: абсолютные числа, и заданы линейные абсолютные размеры.
  2. background-repeat: no-repeat, background-position: абсолютные числа, линейные размеры не заданы или заданы в относительных единицах.
  3. background-repeat: repeat-x, задана высота элемента.
  4. background-repeat: repeat-x, высота элемента не задана.
  5. background-repeat: repeat-y, задана ширина элемента.
  6. background-repeat: repeat-y, ширина элемента не задана.
  7. background-repeat: no-repeat, background-position: 100% 0, задана высота элемента.
  8. background-repeat: no-repeat, background-position: 0 100%, задана ширина элемента.
  9. background-repeat: no-repeat, background-position: 100% 0, высота элемента не задана.
  10. background-repeat: no-repeat, background-position: 0 100%, ширина элемента не задана.
  11. background-repeat: repeat.
  12. background-repeat: repeat-x или background-repeat: repeat-y, размеры элемента указаны в относительных единицах.
  13. background-repeat: no-repeat, background-position: в относительных единицах.
  14. изображение является анимированным GIF-файлом.

Глядя на эту спецификацию становится, в общем, понятно, в каком направлении двигаться для автоматизации создания CSS Sprites.

Практическое решение

Далее речь пойдет уже об инструменте Auto Sprites, который был положен в основу разработки Web Optimizer. После описанных выше умозаключений оставались чисто технические вопросы: как все это закодировать.

Для начала нам нужно разобрать все дерево CSS-правил, потом отобрать из них относящиеся к фоновым изображениям и линейным размерам объектов, уже потом произвести над ними требуемые действия. Идеально для этой задачи подходит CSS Tidy, который был замечательно испробован, протестирован и улучшен после пары небольших ошибок.

Дальше начинается самое интересное: как нам вышеописанные группы «склеивать»? Для этого используется следующий алгоритм:

  1. repeat-x изображения (группа 3) объединяются все вместе по вертикали. Попутно правится ширина фоновых изображений (приводится к общему знаменателю). В самое начало такого файла добавляются no-repeat изображения, подходящие по ширине (группа 1). Далее в самый них файла записывается 1 изображение из группы 4 (больше 1 все равно никуда не войдет).
  2. Производятся абсолютно аналогичные действия с repeat-y.
  3. Далее изображения из группы 7 объединяются по вертикали (0 100% означает, что фон должен быть прижат к правому краю элемента, соответственно, весь спрайт будет «прижат» к правому своему краю).
  4. Аналогично с группой 8 — прижимаем все к низу. Естественно, что для всех групп мы учитываем первоначальный background-position.
  5. Рассчитываем позиционирование для изображений группы 1 (для этого подойдет и просто перебор отсортированных по площади изображений: готовим матрицу, в которую пытаемся «вписать» очередное изображение, если не получается, то матрицу увеличиваем).
  6. Строим «лесенку» из изображений второй группы. Лесенку лучше строить внизу уже созданного спрайта из предыдущего пункта: тогда легко найти минимальный размер «дырки» между двумя группами изображений, чтобы сдвинуть «лесенку» вверх (и потом, возможно влево). Конечно, поиск наиболее оптимального расположения — нетривильная задача. Но ее можно решить и в достаточно грубом приближении, которое описано выше.
  7. Изображение из пункта 3 прикрепляются к правому верхнему углу нашего сложного изображения (результат действия пунктов 5 и 6). Так как у каждого такого изображения задана допустимая высота и все они находятся вне «рабочей» зоны остальных no-repeat-изображений, то никаких рудиментов не возникнет.
  8. Аналогичным образом поступаем с изображением из пункта 4 — его располагаем в нижнем левом углу нашего спрайта.
  9. На выходе мы получаем 3 спрайта со всеми возможными случаями. В среднем, размеры такоих спрайтов будет лишь незначительно превосходить (если вообще будет) аналогичные «ручные» аналоги (в том числе, за счет использования PNG). Естественно, что можно в автоматическом режиме пропустить через pngcrush или jpegtran. Стоит также предусмотреть, в каком виде будут создаваться полноцветные изображения: JPEG или PNG (последние больше по размеру, но гарантирует отсутствие потерь качества).

Все описанные шаги уже применены в Web Optimizer (веб-приложении для автоматизации клиентской оптимизации), одна из финальных версий алгоритма работает для инструмента Auto Sprites, а с исходным текстом можно ознакомиться в SVN.

Эту логику можно применить на любом этапе веб-разработки (как при начальном создании дизайна, так и при пост-релизной оптимизации сайта). Библиотека для автоматического создания спрайтов распространяется по лицензии MIT (как мне правильно указали на CodeCamp, она позволяет использовать продукт где угодно и как угодно, но обязательно должна присутствовать ссылка на первоисточник, даже если используется не вся библиотека, а только ее существенная часть).

Живые примеры

Все картинки получены на реальной конфигурации известных CMS.

Пример CSS Sprites (PNG)

Пример CSS Sprites (JPEG)

P.S. Новости по поводу Web Optimizer будут публиковаться теперь и на Twitter.

Читать дальше

Все комментарии (habrahabr.ru)