Делаем css-спрайты отзывчивее на retina-дисплеях и не только [less]

  • Tutorial
image

Зачем нам вообще нужны спрайты?


Напишу лишь вкратце зачем это нужно, так как на хабре уже много раз описывали преимущества и недостатки css-спрайтов.
  • Во-первых, используя спрайты, мы ускоряем загрузку страницы; в случае использования иконок, можно создать универсальное средство для применения в проектах;
  • Во-вторых, не все устройства с высоким ppi (например, Windows Phone 7.5-7.8, Android до 4 версии на стоковом браузере) поддерживают использование webfonts.
  • Легкая интеграция, используя специальные сервисы генерации спрайтов

Постановка проблемы или чтобы жизнь малиной не казалась


Используя css-спрайты со множеством элементов встает проблема о создании css-свойств с background-position; Их нужно писать много, иногда очень много. Конечно, нам помогают многие сервисы по генерации спрайтов — они выдают вместе со спрайтом еще и css/less/sass — файл с координатами. Но практически всегда все жестко завязано на пикселях:
  • Изменяя размер (например, для retina-экранов) исходного файла-спрайта все «едет»;
  • Мы не можем изменять размер элемента-контейнера, куда хотим вставить, допустим, иконку, чтобы эта иконка смасштабировалась: свойства background-size: cover/contain/100% не работают по понятным причинам;

Используя спрайты, подготовленные для 72ppi, на телефонах, планшетах и новых retina-ноутбуках вызывает размытие изображений, и выглядят некрасиво...

Дисклеймер о кроссбраузерности, кроссплатформенности и кросс-чего-нибудь-еще-сти
Использовать css3 в данном методе мы будем только для дисплеев с ppi, выше стандартных 72. Подобные дисплеи появились сравнительно недавно, и никакие IE 7.0- IE8.0 и им подобные старые версии Firefox или Opera там стоять не будут. С мобильным сегментом тоже все в порядке, поддержка media запросов реализована везде.

Приступим к формированию less-сниппета


Сразу замечу, что использовать less на рабочем проекте никто не заставляет, все можно скомпилировать в обычный css. Для mac подобных программ куча, для windows будет полезна программа WinLess.
Сейчас я рассматривать буду частный случай спрайта — спрайт с иконками, сгенерированный замечательным ресурсом icomoon.io

Чтобы мы делали с помощью простого css, если б нужно было настроить под ретину спрайт? Скорее всего, мы бы отказались от использовали спрайт с высоким разрешением. Возможно, подключали бы его только для устройств с высоким ppi.
Но здесь мы столкнемся с проблемой масштабирования этого спрайта под подходящий нам размер. А это, кроме как transform: scale(x); просто так не решить, и придется перерисовывать спрайт, переписывать все background-position. И все бы ничего, но иногда количество иконок зашкаливает, да и вообще хотелось бы универсальное решение.

Их есть у меня


Итак, приступим:
  • Первое, что нам нужно — это сгенерировать 2 спрайта (можно 3, если хотим охватить 400+ ppi) и css-код к ним. Делается это легко через приведенный мною выше сервис. Я сгенерировал 145 иконок, размеров 16px (25kb), 32px (62kb) и 64px (163kb)
    Изначально, прилагаемый css-файл для 16px-иконок выглядит так: (я намеренно сократил его до четырех иконок, чтобы не пугать огромными простынями кода)
    .icon-rss,.icon-e-mail,.icon-youtube,.icon-mailru {
    	display: inline-block;
    	width: 16px;
    	height: 16px;
    	background-image: url(sprites.png);
    	background-repeat: no-repeat;
    }
    .icon-rss {
    	background-position: 0 0;
    }
    .icon-e-mail {
    	background-position: -32px 0;
    }
    .icon-youtube {
    	background-position: -64px 0;
    }
    .icon-mailru {
    	background-position: -96px 0;
    }
    

  • Затем узнаем размер картинки-спрайта. Для 16px-иконок он составил 496px. Это значение будет опорным для нашего less-кода. Теперь стоит добавить строчку background-size: 496px;
  • Теперь мы должны избавиться от единиц измерения во всем этом css-спрайте, заменив "px" на переменную, по-умолчанию равную 1px. Пусть она будет называться size. Делается это легко автозаменой. Попутно не забываем переименовать файл в расширение less и заинклудить к главному less-файлу вашего проекта:
    @size: 1px;
    .icon-rss,.icon-e-mail,.icon-youtube,.icon-mailru {
    	display: inline-block;
    	width: 16*(@size);
    	height: 16*(@size);
    	background-image: url(sprites.png);
    	background-repeat: no-repeat;
    	background-size:496*(@size);
    }
    .icon-rss {
    	background-position: 0 0;
    }
    .icon-e-mail {
    	background-position: -32*(@size) 0;
    }
    .icon-youtube {
    	background-position: -64*(@size) 0;
    }
    .icon-mailru {
    	background-position: -96*(@size) 0;
    }
    
  • Важно отметить, что мы не можем просто так добавлять получившиеся миксины к тегам — у нас указана ширина и высота в классах, а значит мы будем добавлять их к псевдоэлементам ::before или ::after
  • @media запросы less поддерживает в любом месте кода: в зависимости от плотности пикселей будем подключать тот или иной файл.
    @size: 1px;
    .icon-rss,.icon-e-mail,.icon-youtube,.icon-mailru {
    	display: inline-block;
    	width: 16*(@size);
    	height: 16*(@size);
    	background-image: url(sprites.png);
    @media
    only screen and (-webkit-min-device-pixel-ratio: 2),
    only screen and (   min--moz-device-pixel-ratio: 2),
    only screen and (     -o-min-device-pixel-ratio: 2/1),
    only screen and (        min-device-pixel-ratio: 2),
    only screen and (                min-resolution: 192dpi),
    only screen and (                min-resolution: 2dppx) { 
    	background-image: url(sprites32.png);
    }
    @media 
    only screen and (-webkit-min-device-pixel-ratio: 4),
    only screen and (   min--moz-device-pixel-ratio: 4),
    only screen and (     -o-min-device-pixel-ratio: 4/1),
    only screen and (        min-device-pixel-ratio: 4),
    only screen and (                min-resolution: 360dpi),
    only screen and (                min-resolution: 4dppx) { 
    	background-image: url(sprites64.png);
    }
    	background-repeat: no-repeat;
    	background-size:496*(@size);
    }
    .icon-rss {
    	background-position: 0 0;
    }
    .icon-e-mail {
    	background-position: -32*(@size) 0;
    }
    .icon-youtube {
    	background-position: -64*(@size) 0;
    }
    .icon-mailru {
    	background-position: -96*(@size) 0;
    }
    

Комментарии для применения на практике


  1. Вам не обязательно генерировать через программу-генератор сразу три разных спрайта. Вы можете сгенерировать один (для очень-retina экранов), получить драгоценный css-файл, а затем через графический редактор сделать уменьшенную версию спрайта для обычных устройств (не retina).
  2. В своих проектах я не использую "px". Вместо этого, я переменной size присваиваю значение в единицах измерения "rem". Это дает свободу изменения размеров иконок до необходимого, а в случае, если мы открываем сайт с планшета, эти самые rem становятся чуть больше, т.к. я задаю чуть больший размер шрифта для планшетов, например:
    @media (min-width: 768px) and (max-width: 1366px) {
         html {font-size: 120%;}
    }
    


Когда стоит использовать данную технику


  • Для возможности подгружать спрайты разного качества для retina/не-retina экранов;
  • Когда предполагается возможное изменение размера иконки при разработке проекта;
  • Когда стоит адаптировать исходный спрайт при создании мобильной версии сайта;
  • В моей практике я данный метод использую только в случае, когда webfonts не поддерживается устройством. В любых других случаях проще использовать иконочный шрифт: здесь и цвет менять можно, и тень ставить, и не париться о размерах и размытии


P.S.: Об орфографических, синтаксических и лексических ошибках просьба писать в ЛС.
P.P.S.: Данный материал не претендует на добавление в палату мер и весов, и используемые примеры не совершенны. Гуру-less/sass в этом посте не найдет ничего особенного, а вот новичкам будет полезно.

Only registered users can participate in poll. Log in, please.

Стоит ли добавлять статьи о less-миксинах и сниппетах?

  • 59.9%Да, less — удобный инструмент, хотелось бы больше примеров190
  • 20.5%Нет, я пишу на sass/scss и не вижу ничего поразительного в этих примерах65
  • 13.2%Стоит делать фокус именно на верстку под мобильные девайсы42
  • 23.3%Я считаю, что препроцессоры для css использовать не стоит и остаюсь верным только css74

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 32

    0
    Не совсем по теме, однако grunt + grunt-spritesmith = автоматическая сборка спрайтов из отдельных файлов, с формированием less. Создаём 2 папки: одну для обычных спрайтов, вторую для увеличенных, добавляем два задания в grunt для формирования двух спрайтов — profit.
    Разобраться с grunt для выполнения подобных задач — дело пары часов, которые потом окупятся сторицей.
      0
      А вот скажите, в чем смысл css спрайтов, когда есть base64? В чем преимущество? И кстати да, ставить обработчиком grunt, который соберет или base64 из файлов и проставит в нужные места заместо имен — это действительно удобно.
        0
        У той или иной задачи есть множество реализаций. В данной статье я не описываю преимущество данного способа над base64.
        А по вашему вопросу — css спрайты наиболее известны, популярны. А в вашем решении необходимо использовать дополнительный обработчик, скрипты. Что, впрочем, соразмерно с использованием less.
          +1
          0
          > Использовать css3 в данном методе мы будем только для дисплеев с ppi, выше стандартных 72. Подобные дисплеи появились сравнительно недавно, и никакие IE7.0 – IE8.0 там стоять не будут.

          В Windows Phone 7 как раз IE 7.0 – IE8.0 и большой ppi.
            0
            Полагаю, вы имеете ввиду самую-самую первую. Я имею ввиду 7.5, так как она, по словам википедии:
            В системе обновился браузер Internet Explorer Mobile до версии 9, который теперь поддерживает HTML5, Canvas, аппаратное ускорение. Появилась возможность использовать фронтальную камеру.
              0
              > Я имею ввиду 7.5, так как она, по словам википедии:

              Нет, вы имеете в виду «дисплеи с ppi, выше стандартных 72», в том числе и WP7.
            • UFO just landed and posted this here
                0
                Да какая разница. Автор написал, что на устройствах с ppi больше 72 не может стоять IE7. Это не так.
                  0
                  Что ж, поделитесь ссылкой, что Windows Phone 7, как вы говорите, с IE8, стоит хотя бы на тысячной доле процента от всех мобильных пользователей. Если такого нет, то можно вполне сказать, так, как я написал в статье.
                    0
                    При чем тут доля. Может стоять же? Причем я не прикапываюсь к словам типа «ага, у меня монитор 92 ppi, на нем ие8 в виртуалке!», я о реальных устройствах с ppi за 200.
                      0
                      Ну, значит у них будет размытые иконки. Доля очень здесь причем. Если для того, чтобы сайт работал на экзотических девайсах, нужно вкладывать много времени на разработку, то на эту долю забивают. И доля пользователей с ppi 200+ и IE 7-8, крайне мала.
                      А вообще, как я понял, вам просто хочется придраться к какой-то мелочи. Можно было написать в ЛС. А в комментариях писать все же по теме, а не придираться к выражениям.
              –1
              Руки оторвать тем, кто ретину сделали.
              Почему блин в андроиде сделали нормальные девайсонезависимые пиксели и совместимо все, а из-за этих дизайнеров с ретиновскими картинками приходится извращаться везде — начиная от того что теперь нужно две картинки, заканчивая тем что есть всякие админки и на том-же html браузеры такого изврата особо не понимают, а учитывая любовь дизайнеров верстать по пикселям (ага — добро пожаловать в 90-е) получается вообще полный…
              Опять получилась фигня когда доверили дизайнерам то что должны были делать технари.
                +1
                Ретина — это лишь маркетинговое словечко. Говоришь «ретина», и окружающие так «оооооооо!». В реальном мире — ретина не такая уж и крутая, есть, например Meizu MX3, HTC One и много всяких других устройств, где плотность пикселей может быть в полтора и более раз выше, чем у самого крутого девайса от яблочка.

                90-е тут не при чём, время идёт, если заглядывать в прошлое веб разработки, то лет 10 назад стандартом было разрешение 800х600 (если даже не 640х480, хотя врятли), лет 5 назад, де-факто, было разрешение 1024х760 и так далее. Сайты разрабатывались с учётом подобных мониторов и размер экрана был практически пропорционален количеству пикселей. Но вдруг технология шагнула вперёд и подобные «мозги» компьютера начали без проблем всовывать в сотовые телефоны, при этом если на Desktop компьютерах на размер экрана пофигу (даже наоборот, чем больше — тем круче), то в планшетных ПК, смартфонах и прочих «приблудах» так не разгуляешься, экран должен быть фиксированного размера +\- (я умолчу о любителях лопат), по-этому следующим шагом было увеличение плотности пикселей на экранах подобных устройств, и если, повторюсь, в эпоху настольных ПК разрешение экранов было примерно пропорционально размеру самого экрана, то на устройстве с разрешением 1920х1080 сайт, заточенный под разрешение 800+, выглядел бы, прямо скажем — не очень (если нет конечно под рукой микроскопа).

                Я предполагаю, что всё рассказанное мной — довольно очевидно и дизайнеры тут совсем не при чём (ну или только частично). В таком случае можно хаять дизайнеров на то, что приходится использовать много цветов, вместо палитры из 8 битов =)
                  0
                  Дополню (не успел во время отредактировать):
                  Попробуйте запустить игру, заточенную под 640х480 на современном мониторе — поймёте почему затачивать решения под пиксели, а не размазывать их — всё же лучше. Хотя в глубине души мне тоже хочется одну, большую, красную кнопку — «сделать всё круто», но увы.
                    –2
                    Я прекрасно знаю что «ретина» это результат деятельности маркетологов огрызка.
                    Я не говорю о том, что повышать плотность и разрешение плохо.
                    Я говорю о том как через большую и круглую это реализовали в эппле «дизайнеры», потому что по тому что они выпускают не похоже что там вообще есть технари.
                    Андроид поддерживает девайсо-независимые пиксели, три варианта плотности точек, кучу различных разрешений экранов, динамическое размещение компонентов по лайаутам, и делать там дизайн вообще отлично.

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

                    И про игру — извините, но на современном мониторе она просто будет размазана, а не просто расползется нафиг из-за того, что половину размерностей мы тупо увеличили в два раза, а половину забыли. Просто яблочники наверное не в курсе, что помимо их отстоя есть и нормальные системы/планшеты/телефоны и компы.
                      +1
                      Не вижу ни одной проблемы в верстке под iOs по сравнению с Android.
                      И да, у вас баттхерт.
                        0
                        > Тут же блин второе разрешение экрана ввести не могут —
                        > это же надо додуматься просто своим идиотизмом поломать
                        > полностью обратную совместимость даже в такой простой задаче.

                        Почему не могут ввести? Ввели. Что поломали?
                      0
                      У вас все в голове смешалось.
                      Мне приятно смотреть на экран с высоким ppi. А контент должен подтягиваться. Вас же не смущает смотреть SD-видео? Вы понимаете, что HD намного комфортнее и лучше.
                      А всякие варианты про «две картинки» — лишь из-за того, чтобы не грузить большие объемы информации там, где она просто не нужна. Хотя в посте я отметил в самом конце о разумности метода, когда мы сразу подгружаем качественные иконки.
                      0
                      Проголосовал за все 4 варианта.
                      Спасибо.
                        0
                        Тем, кто всё ещё не определился с препроцессором, рекомендую не смотреть в сторону Less, а обратить внимание на Stylus+Nib (Node.js) и Sass+Compass (Ruby). Особенно в вопросах генерации спрайтов.
                          0
                          Ну, хочу немного возразить. Less действительно проще и ближе к css. На него легче пересесть, а использование базовых возможностей: вложенности селекторов, миксинов и переменных, сразу почти в два раза ускоряют верстку проектов.
                            0
                            Ни разу не ближе, ни разу не легче, чем на Sass или Stylus, а вот отсутствие функций, if/else, циклов, доступа к файловой системе и расширений, ощутимо уменьшает возможности по ускорению вёрстки. Однажды в них упрётся каждый разработчик и непременно проклянёт «тот день, когда сел за баранку этого пылесоса».
                              0
                              А вот тут я не соглашусь. Less действительно проще и ближе к CSS, правда возможностей из коробки — Вы правы, меньше, чем в Sass (Scss) и Stylus.
                                0
                                Судя по этому комментарию, вы или теоретизируете или же просто троллите меня.
                                Любой фронтенд-разработчик, который использовал в реальных проектах разные препроцессоры, знает, что хоть с коробкой, хоть без коробки less проигрывает по всем фронтам, ещё и отличаясь от конкурентов в худшую сторону в плане читабельности. И да, я говорю не про HelloWorld, а про реальные, сложные стили с кучей условий.
                                  0
                                  Не нужно писать стили с кучей условий. Красота в простоте заключается.
                            0
                            Stylus есть и на руби, а Scss+Compass и Stylus, и Less есть и на PHP =)
                              0
                              Проблема с по́ртами Sass в том, что они не подсасывают config.rb, в который очень удобно добавлять различные плюшки (мини-расширения), написанные на руби.
                                +1
                                Зато могут подсосать (ух какое ядрёное словечко) config.php, config.js, config.coffee, config.*подставить_любимое_расширение*. Плюшки точно так же без проблем пишутся (могу отвечать, правда, только за PHP порт).
                                  0
                                  Дело в том, что в интернетах ну оооочень много сниппетов для конфиг-файлов Sass и Compass, написанных на руби.
                                  В случае порта нужно либо переписывать сниппет на выбранный язык, либо изначально писать свой и вообще не использовать великий и могучий копипаст. И это печально.
                                  Плюс, не знаю, как там на PHP, но на Node.js Compass до сих пор не реализован в полном объёме. Т.е. опять же, в случае порта, вы рискуете наткнуться на баг, которого нет.
                            0
                            Тема относительно старая, но все таки спрошу. Зачем выносить 1пх в переменную?

                            Я бы понял, если рассматривать конкретный пример, если бы вынесли в переменную число 32пх, то есть размер одной иконки и в дальнейшем бы для каждой иконки делали смещение под её позицию, то есть
                            Иконка 1: бгпозишн: size*2 0;
                            Иконка 2: бгпозишн: size*3 0;
                            И так далее…
                              0
                              Для однотипно-элементных спрайтов – да, хорошо. А что если элементы спрайта неодинаковы?

                              Only users with full accounts can post comments. Log in, please.