Привет, Хабр!

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



Предыстория. О трендах

В последнее время все сильнее набирает обороты тренд «отзывчивого дизайна». Идея, заложенная в эту методологию, в режиме реального времени модифицируется, дополняется и обрастает новыми функциями. Я — не фанат трендов и моды как таковой, не сложилась у меня с ними взаимная любовь. Но в профессиональной сфере все иначе: здесь тренды правят бал, и выбросить их просто так не получается.

Тренд первый. Продолжение экспансии Responsive design.

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

Тренд второй. Плоский дизайн.

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

  • Простота восприятия. Минимализм (правильный, конечно же) всегда отличался легкостью фактур и свободой, которой дышит дизайн, контент и структура.
  • Простор и простота разработки. Флэт-дизайн прост, как квадрат и, в большинстве случаев, вам не понадобится иметь трехгигабайтное хранилище с графическими референсами.
  • Легковесность. Особенно ценное свойство в эпоху мобильного интернета. Флэт-дизайн может оперировать изображениями с минимум цветов, либо вообще обходиться без них. А с появившейся в браузерах поддержкой и популяризацией SVG, есть возможность использования векторной графики.

Это основные положительные свойства флэт-дизайна, обуславливающие его нарастающую популярность.

Тренд третий. Icon Fonts.

Совсем свежее течение в мире веб-дизайна. Смысл идеи прост: создаете набор SVG-изображений, а после этого собираете их специальным сервисом, который на выходе выдает набор из нескольких CSS-файлов для разных целей, собственно шрифта в форматах EOT, SVG, WOFF и даже TTF, который можно установить в систему и использовать, например, в графическом редакторе. К сожалению, шрифтовые иконки лишены некоторых прелестей SVG, например, раскрашивания отдельных элементов одной иконки, но на эти жертвы в большинстве случаев можно пойти или обойти их некоторыми ухищрениями.

Adaptive icons

Перехожу к главной теме статьи — о паттерне, который вбирает все вышеперечисленные тренды и идею Джо Харрисона Responsive Icons, суть которой очень проста. При изменении размера окна изменяется и детализация иконки, чтобы всегда соответствовать возможностями экрана и не создавать пикселизированный шум на низком разрешении.
Приступим. Допустим, мы имеем вот такой дизайн в трех размерах:







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

Первый подход к созданию адаптивных иконок

Следуя методологии Progressive enhancement, для начала создадим простую разметку для нашего файла (оставим логотип на потом, займемся сначала нижними иконками):

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="style-480.css" media="screen and (max-width:480px)">
    </head>
    <body>
        <header class="logo-container">
            <div class="logo">Logo</div>                
        </header>
        <div class="content">
             <a href="#" class="icon icon-announces">Announces</a>
             <a href="#" class="icon icon-partners">Partners</a>
             <a href="#" class="icon icon-news">News</a>
        </div>
    </body>
</html>


Далее займемся стилями. Следуя практике Mobile first, сначала создадим стиль для минимального размера:

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    margin-bottom: 20px;    
    width: 100%;
}


Иконок мы пока не имеем, поэтому делаем SVG из значков дизайна для мобильных, называем их в соответствии с нашими классами: announces, partners и news. Обратите внимание, что вся иконка в SVG должна быть одной фигурой (single compound path). Идем на сервис (я пользуюсь fontello.com), создаем там шрифт и называем его, допустим, ittalk-font-small:



На второй вкладке (Customize Names) можно изменить названия по умолчанию, которые будут использованы в сгенерированных css. Т. к. как мы именовали файлы по классам, нам там делать нечего. На третьей вкладке можно изменить Unicode каждого символа в шрифте, таким образом, привязав его, например, к определенным буквам. Но мы не планируем использовать шрифт в операционной системе, т. ч. эту страницу мы тоже пропускаем. Щелкаем на кнопку “Download webfont (3)” и сохраняем на компьютер готовый архив. В архиве нас интересует папка “font” и файл “ittalk-font-small.css” из папки “css”. Копируем их в подпапку “fonts” нашего проекта и добавляем в “style-320.css” строчку в самом начале файла:

@import "fonts/ittalk-font-small.css";

body {
    ...


В самом файле “ittalk-font-small.css” меняем все пути в @font-face с '../font/...' на 'small/'.
Итак, у наших ссылок появились значки. Неплохо. Добавляем немного кода в CSS:

@import "fonts/ittalk-font-small.css";

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    margin-bottom: 20px;    
    width: 100%;
    height: 80px;           /*  Немного магии, смысл которой в том    */ 
    line-height: 80px;      /*  чтобы убрать текст из ссылки          */
    overflow: hidden;       /*  и оставить одну иконку.               */
}

.icon:before {
    width: 100%;
    font-size: 50px;           
}


Ура! У нас остались одни иконки. Проделываем то же самое со средним и большим размерами:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="style-480.css" media="screen and (max-width:480px)">
        <link rel="stylesheet" type="text/css" href="style-720.css" media="screen and (min-width:481px) and (max-width:720px)">
        <link rel="stylesheet" type="text/css" href="style-big.css" media="screen and (min-width:721px)">
    </head>
    <body>
...


Style-720.css:

@import "fonts/ittalk-font-medium.css";

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    width: 32%;
    height: 130px;           
    line-height: 130px;     
    overflow: hidden;       
}

.icon:before {
    width: 100%;
    font-size: 72px;           
}


Style-big.css:

@import "fonts/ittalk-font-big.css";

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    width: 30%;
    height: 210px;           
    line-height: 210px;     
    overflow: hidden;       
}

.icon:before {
    width: 100%;
    font-size: 128px;           
}


Демо промежуточной версии. Смотреть в Chrome или Firefox.
Плюсы:
  • Векторность.
  • Мало кода.
  • Легкость в применении и обновлении.
  • Гибкость.
  • Отсутствие JavaScript.


Минусы:
  • Максимум один цвет на иконку.
  • Дополнительные файлы для загрузки (шрифты).
  • Проблемы с поддержкой старых браузеров.


Второй подход к созданию адаптивных иконок

Теперь разберемся с логотипом, заодно и с проблемы одноцветности иконки. Как видим, он состоит из четырех элементов, которые постепенно исчезают с изменением уровня детализации:





Подготовим четыре SVG (убедитесь, что исходные файлы имеют одинаковую высоту и ширину), в которых каждый элемент стоит на своем месте относительного общей композиции, и составим из них шрифт. Для этого идем на fontello, добавляем SVG и меняем на третьей вкладке привязку к буквам “L”,”o”,”g” и точку, к примеру.



Назовем шрифт “ittalk-logo” и скачаем готовый файл. Выгрузим шрифты в подпапку “logo” и скопируем из файла “ittalk-logo.css” @font-face (не забывая поменять пути).
Добавим во все стили несколько строчек.

Style-480.css:

@import "fonts/ittalk-font-small.css";

@font-face {
    font-family: 'ittalk-logo';
        src: url('fonts/logo/ittalk-logo.eot?39703710');
        src: url('fonts/logo/ittalk-logo.eot?39703710#iefix') format('embedded-opentype'),
             url('fonts/logo/ittalk-logo.woff?39703710') format('woff'),
             url('fonts/logo/ittalk-logo.ttf?39703710') format('truetype'),
             url('fonts/logo/ittalk-logo.svg?39703710#ittalk-logo') format('svg');
    font-weight: normal;
    font-style: normal;
}

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    margin-bottom: 20px;    
    width: 100%;
    height: 80px;           /*  Немного магии, смысл которой в том    */ 
    line-height: 80px;      /*  чтобы убрать текст из ссылки          */
    overflow: hidden;       /*  и оставить одну иконку.               */
}

.icon:before {
    width: 100%;
    font-size: 50px;           
}

.icon-logo {
    font-family: 'ittalk-logo';
    display: inline-block;
    word-wrap: break-word;
    width: 1px;
    line-height: 0px;
    font-size: 180px;
    padding-top: 100px;
    height: 60px;
    margin-left: -0.7em;
}


Style-720.css:

@import "fonts/ittalk-font-medium.css";

@font-face {
    font-family: 'ittalk-logo';
        src: url('fonts/logo/ittalk-logo.eot?39703710');
        src: url('fonts/logo/ittalk-logo.eot?39703710#iefix') format('embedded-opentype'),
             url('fonts/logo/ittalk-logo.woff?39703710') format('woff'),
             url('fonts/logo/ittalk-logo.ttf?39703710') format('truetype'),
             url('fonts/logo/ittalk-logo.svg?39703710#ittalk-logo') format('svg');
    font-weight: normal;
    font-style: normal;
}

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    width: 32%;
    height: 130px;           
    line-height: 130px;     
    overflow: hidden;       
}

.icon:before {
    width: 100%;
    font-size: 72px;           
}

.icon-logo {
    font-family: 'ittalk-logo';
    display: inline-block;
    word-wrap: break-word;
    width: 1px;
    line-height: 0px;
    font-size: 320px;
    padding-top: 200px;
    height: 60px;
    margin-left: -0.75em;
}


Style-big.css

@import "fonts/ittalk-font-big.css";

@font-face {
    font-family: 'ittalk-logo';
        src: url('fonts/logo/ittalk-logo.eot?39703710');
        src: url('fonts/logo/ittalk-logo.eot?39703710#iefix') format('embedded-opentype'),
             url('fonts/logo/ittalk-logo.woff?39703710') format('woff'),
             url('fonts/logo/ittalk-logo.ttf?39703710') format('truetype'),
             url('fonts/logo/ittalk-logo.svg?39703710#ittalk-logo') format('svg');
    font-weight: normal;
    font-style: normal;
}

body {
    background-color: #f0f0f0;	
    text-align: center;
}

a {
    text-decoration: none;
}

.icon {
    display: inline-block;
    color: #919191;
    width: 30%;
    height: 210px;           
    line-height: 210px;     
    overflow: hidden;       
}

.icon:before {
    width: 100%;
    font-size: 128px;           
}

.icon-logo {
    font-family: 'ittalk-logo';
    display: inline-block;
    word-wrap: break-word;
    width: 1px;
    line-height: 0px;
    font-size: 640px;
    padding-top: 300px;
    height: 120px;
    margin-left: -0.75em;
}


NB: Возможно, придется подбирать значения размера шрифта, а под него — и padding-top, height и margin-left.

Логотип одноцветный, поэтому не видно элементов. Самый простой способ решить это — немного испортив семантику html-файла, добавить в него немного «лишних» тегов.

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="style-480.css" media="screen and (max-width:480px)">
    </head>
    <body>
        <header class="logo-container">
            <div class="logo">
                <span class="icon-logo">
                    L<b>o</b><i>g</i><s>.</s>
                </span>
            </div>                
        </header>
        <div class="content">
             <a href="#" class="icon icon-announces">Announces</a>
             <a href="#" class="icon icon-partners">Partners</a>
             <a href="#" class="icon icon-news">News</a>
        </div>
    </body>
</html>


Выглядит ужасно, но напоминаю: мы просто разбираем здесь интересное решение самым быстрым способом =).
Далее добавляем во все стили правила:

Style-big.css

.icon-logo {
    color: #1c82c4;
}

.icon-logo b {
    color: #acd03c;
    font-weight: normal;
}

.icon-logo i {
    color: #fff;
    font-style: normal;
}

.icon-logo s {
    color: #fff;
    text-decoration: none;
}


Style-720.css

.icon-logo {
    color: #1c82c4;
}

.icon-logo b {
    color: #acd03c;
    font-weight: normal;
}

.icon-logo i {
    color: #fff;
    font-style: normal;
}

.icon-logo s {
    display: none;
}


Style-480.css

.icon-logo {
    color: #1c82c4;
}

.icon-logo b {
    color: #acd03c;
    font-weight: normal;
}

.icon-logo i {
    display: none;
}

.icon-logo s {
    display: none;
}


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

Посмотреть демо можно здесь. Можно изменять ширину окна и наблюдать за результатом или открыть на мобильном телефоне и повернуть экран. Смотреть на десктопе лучше в Chrome или Firefox.

Заключение

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

Автор: Артем Маркушев

Комментарии (21)


  1. JSmitty
    07.05.2015 17:41

    А нельзя в коде html просто завести три блока (на три варианта) на каждую вариативную иконку, один из которых показывать по media query? В случае уже готовых шрифтов (типа Fontawesome или встроенных в Bootstrap) даст возможность делать замены малой кровью, не убиваясь в написании пачки css. Да, код html будет менее семантичным.

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


    1. franzose
      07.05.2015 18:31
      +1

      В итоге, когда проект перестанет состоять из трех страничек, получите такой фарш… Всё таки это декорации, а декорации лучше стараться выносить в CSS.


    1. DataArt Автор
      08.05.2015 12:16

      Можно, но идея статьи была в том, чтобы не сделать классный и правильный код\архитектуру, а чтобы показать возможность работы с Font Icons. И да, препроцессор было бы намного лучше использовать, но захотелось сделать связку на чистых html+css.


  1. mr47
    07.05.2015 18:17
    -1

    Использование ванильного css вместо scss или less очень и очень не понятно. Так как экономия в less могла быть большой, читаемость кода, кроме того, резко возрастает (если уж отказываться от 3 блоков как предложил комментатор выше), а что говорить о scss. Велосипед да и только.


  1. i360u
    07.05.2015 19:19
    +1

    Inline SVG + Web components = счастье


    1. DataArt Автор
      08.05.2015 12:16

      Поддержку старых браузеров никто не отменял =) Статья — просто показать, что есть вот такой способ, который вполне неплохо работает в более старых браузерах. Например, его можно использовать как фоллбэк.


      1. i360u
        08.05.2015 19:35

        Не думаю, что для старых браузеров актуальны интерфейсы с адаптивными иконками, для некрофилии — graceful degradation.


  1. fetis26
    07.05.2015 22:30

    Font Icons это вчерашний день. Используйте SVG


    1. BananaBobby
      08.05.2015 02:12
      +1

      Некоторым все еще нужно поддерживать ие8


    1. SelenIT2
      08.05.2015 12:16

      В выборе технических решений надо руководствоваться не только модой, но и другими соображениями:)


      1. fetis26
        08.05.2015 14:38

        Там разница на 1мс в среднем. Я бы вообще эту характеристику не брал в расчет


    1. DataArt Автор
      08.05.2015 12:16

      Ответил выше — поддержка старых браузеров + статья — не руководство, «как надо делать», а «как можно делать».


  1. JeStoneDev
    08.05.2015 04:17
    +1

    когда-нибудь данная задача сведется к простой настройке элемента picture
    когда-нибудь…


    1. SelenIT2
      08.05.2015 12:06

      к простой настройке

      :)


  1. copist
    08.05.2015 13:07
    +2

    А вот такой инструмент не пробовали: icons8.com/responsive-icons?
    Там вся «подкапотня» скрыта и на выход из двух-трёх иконок в формате SVG можно получить одну отзывчивую картинку.

    скриншотик
    50 Responsive Icons
    Responsive Icon Generator


  1. stardust_kid
    08.05.2015 13:21

    icomoon.io — более навороченный сервис, и они умеют многоцветные иконки генерировать, правда кода много получается.


  1. dyadyaSerezha
    08.05.2015 15:12

    1. К сожалению, почти не видел сайтов, которые бы при наличии только одной версии иконок делали их масштабирование, пусть и с «шумом пикселизации», а это все равно гораздо лучше, чем один немасштабируемый вариант. Причина мне искренне не понятна. Лень дизайнеров или веб-программистов? Их графический перфекционизм? Перфекционистам отвечаю: да хрен с ними, с шумами и некрасивостями — зато хоть можно будет прочитать или понять, что там изображено! Мне не шашечки, мне ехать надо. У многих же дизайнеров превалируют шашечки без возможности ехать в половине случаев.

    2. Варианты 480, 720 — это варианты размеров экрана в пикселях? Тогда опять все не правильно. Правильно исходить из плотности пискелей. Потому что размеры экранов в см сейчас отличаются до 10 раз, в то же время при том же физическом размере в см размер в пикселях может отличаться раза в 4. А человеку все равно, сколько пикселей в экране или в иконке — ему надо, чтобы на разных экранах все элементы имели примерно одинаковый угловой размер, а для этого гораздо лучше подходит плоность пикселей на см (и факт того, мобильный это экран или монитор).


    1. copist
      08.05.2015 15:42

      Как сказал мне один верстальщик: штука интересная, тока дизайнерам не говори — они и так с трудом себе представляют поведение страницы при ресайзе, просто рисуют мокапы для разных разрешений. А тут такой простор для фантазии, не привязанной к реальности.


      1. dyadyaSerezha
        08.05.2015 16:57

        Ну как-то же все браузеры на компах ресайзят страницы, причем по желанию юзера: вместе с картинками или без. Ведь разрешение экранов мониторов варьируется от 90 до 300 пикселей на дюйм да и зрение у всех разное — вот и ресайзят люди, чтобы удобно было читать. И вроде все работает прекрасно. Так что не надо создавать трудности там, где их нет.


    1. SelenIT2
      08.05.2015 17:15

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

      В CSS изначально «пиксель» так и определялся — как угловой размер, под которым виден типичный пиксель ЭЛТ-экрана с расстояния вытянутой руки (примерно 0.0213 градуса). Сейчас CSS-пиксель стал абсолютной единицей, равной 1/96 CSS-дюйма, но за браузерами/девайсами оставлено право «подгонять» размер CSS-дюйма (и, соотв-но, CSS-пикселя) так, чтобы элементы имели привычный угловой размер. И плотность физических пикселей устройств (по крайней мере, мобильных) на это не влияет, она влияет лишь на четкость картинки. Так что CSS-пиксели — самое то, хоть и малость неинтуитивно.


  1. Grawl
    12.05.2015 18:20

    Я не согласен с идеей “для больших экранов будут очень детальные и большие значки”. Как правило, при изменении размеров экрана меняется не размер значков, а сетка и размеры шрифтов. То есть отзывчивыми должны быть сами значки – а это значит, что значки уже точно не шрифтом.

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

    А если не размер менять, а подменять рисунки на значках, то те, что не были изменены в размерах для крупных экранов (большинство) стали бы уменьшены до исходных размеров. Рисунки стороной 128 точек, ужатые до 32 в лучшем случае.

    В случае значков шрифтом, проще (и разумнее всего) применять модификаторы размеров:

    .icon-news::before {
    content: '$icon-news-medium';
    }

    .icon-news_large::before {
    content: '$icon-news-large';
    }

    …и так далее.

    Но если взять SVG, то медиа-запросы можно использовать относительно родителя SVG. Следовательно, значок, которому задан размер в 16 точек, будет отрисован рисунком, подготовленным для 16 точек. Вот пример: codepen.io/pukhalski/pen/hszLl

    К сожалению, это работает только со встроенными объектами вроде iframe или embed – вот обсуждение этой проблемы stackoverflow.com/questions/12251750/can-media-queries-resize-based-on-a-div-element-instead-of-the-screen