SVG, Iconfonts vs PNG

image

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

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

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


SVG


Самую бурную реакцию вызвало именно применение SVG. Сначала юзер franzose заметил что:

Только вот вес у сложного вектора гораздо больше. И шансов подвесить браузер тоже

Так как в статье речь шла преимущественно о иконках — такой коммент для меня совершенно непонятен. Да, я сам несколько раз получал от дизайнера ужасные иконки, которые представляли собой нагромождение примитивов, налепленных друг на друга. Но ничего не мешает подойти к дизайнеру и сказать, — “что за херня, мужик?!”, ну или самому зафиксить это дело в том же иллюстраторе, объединив в какой-нибудь общий shape (ну это конкретно мой случай, других “сложных векторов” я не видел пока). Еще для этих целей можно использовать SVGO. Кажется объединение в общий shape — это единственная его часть, которая действительно драматически влияет на производительность.

На самом деле даже если забыть про все эти вещи с иконками — я не могу представить какого-нибудь хоть минимально часто встречающегося кейса про “сложный вектор”. Да все равно вектор, применительно к задачам сегодняшнего веба будет меньше растра (это про вес).

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

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

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

Я пообщался с парой людей, которые занимаются SVG частью в Chrome и Firefox и показал им вот это демо, которое Adrian Osmond делал еще год назад для, в принципе, таких же целей. Но тогда все было на порядки хуже. Почему, можно почитать в его статье и багтрекере вебкита.

Итак:

Chrome



FPS проседает примерно раза в полтора, два. Печально конечно, но не 10x все же. Так что же происходит под капотом Хрома в этот момент?
Я немного почитал исходники на chromium.org, нашел кое-какой кэширующий код для SVG, и это меня запутало еще сильнее. Тут я решил спросить у знающих людей.

Philip Rogers из Google, который в общем то и пишет большую часть всяких дел с SVG в хромиуме, сказал что различия отрисовки SVG и PNG несколько сложнее. Во-первых PNG декодируется в отдельном потоке, а SVG в главном, а во-вторых помимо производительности есть еще такие вещи, как например, память. В общем они решили отказаться от хранения кэша для svg чтобы сэкономить памяти. Как по мне — так это какой-то сомнительный план. Не совсем понимаю почему бы не кэшировать все это дело. Bitmap, которым заканчивается рендер не будет каких-то неприличных размеров, с сегодняшними то объемами памяти, даже на мобильных устройствах. Ну и грядет же вектор, тема перспективная. Но видимо поэтому в Google работают они, а не я.

Так что да, в хроме SVG отсчитывается заново каждый фрейм. Правда Philip сказал что они там что-то придумали, что “should bring it much closer to png performance”. Будет в следующей Canary. Посмотрим. Тем не менее производительность на уровне чуть меньшем чем 60 FPS (а у меня в общем средний такой конфиг) на огромной куче иконок одновременно находящихся на экране — это вполне себе адекватная производительность.

Firefox

Я не знаю чем померить FPS в FF (видел какую-то софтину, но процесс инсталляции был не совсем тривиален и я не стал возиться), но на глаз производительность PNG и SVG одинаковая. Так же думает и Robert Longson, контрибьютор SVG в Firefox. По словам Роберта, в Firefox есть кэш для всех изображений и разница между SVG и PNG может заключаться разве что в том, что SVG немного дольше “декодируется” при первой отрисовке, что вполне закономерно.

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

IE



Новые IE часто бывают очень хороши во всяких неочевидных местах, например WebGL. Тут такая же ситуация. В IE демо работает намного лучше чем в 2-х предыдущих браузерах, показывает одинаковый framerate для SVG и PNG. Но делает это по каким-то магическим причинам не сразу.

К сожалению я не знаю кто занимается разработкой SVG в IE, а в багтрекер писать сомнительно как-то такие вещи, поэтому эта часть останется без комментариев с другой стороны.

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

С практиками верстки SVG все более-менее понятно. Я предпочитаю рисовать SVG спрайты. Техника такая же как и для растровых спрайтов. Проблемы решаемые ими в принципе такие же. Естественно есть куча разных плагинов для этих целей, например вот.
Еще можно делать это с помощью data url. Тут я рекомендую вот такую штуку и их же софтину вот тут, для тех, в чей процесс Grunt по каким-то причинам не входит. Ну еще можно прям файлами на background-image, но не нужно.

Единственный современный браузер где я видел проблемы с рендерингом SVG — это IE на Windows Phone. Но там эта проблема решаема.

Iconfonts


Если в SVG мы в принципе можем нарисовать все что душе угодно, то с помощью шрифтов ограничены монохромными иконками (если не брать во внимание извращения вроде stackicons), что в рамках текущих веяний в дизайне не представляется таким уж недостатком. Зато перед нами открывается куча возможностей начиная от банальной смены цвета и размера, заканчивая пачкой CSS манипуляций с шрифтами, вроде тенюшек и т.д.

Техника с иконочными шрифтами сложнее чем те же SVG. Тут нужно обладать некоторым объемом знаний в областях, где не каждый дизайнер ориентируется. Казалось бы, делов то, запихай свои SVG-хи в один из кучи онлайн-упакавщиков типа того же Icomoon-а или настрой какой-нибудь Grunt\Gulp плагин, и будет тебе счастье.

В комментариях к статье главным обвинением относительно шрифтов было что-то вроде
рендеринг ужасный в мелких размерах (явные лесенки) (с) designiac
А что вы хотели, ребят? Нарисовать огромную иконку приблизительно кегля так 48-го, проработать мелкие детали, потом воткнуть ее кеглем так 12-м и вместо удивления о каком-то плохом рендере этих ужасных вебшрифтов, наслаждаться идеальными чистыми иконками?

Хинтинг!

Вот основная вещь, которую нужно знать про iconfonts. Вот он, святой грааль иконок в вебе! Я считаю что если вы точно знаете что скажем, цвет иконок или их размер не изменятся (вероятно бывает и такое), нужно брать SVG и не морочить голову. Использовать шрифты без необходимости — какой-то не очень критичный конечно, но все равно overhead.

Чтобы собрать годный шрифт нам понадобятся:
  1. иконки в векторе
  2. аналог icomoon-а
  3. профессиональная штуковина для работы со шрифтами. Я использую FontLab Studio


Чтобы было понятно зачем нам это вообще нужно — вот такой пример: берем модный Font Awesome и одним хинтом делаем из вот такой иконки pinterest:



вот такую:



Лучше всего видно на мелком кегле, естественно.

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



немного сложнее чем в такой:



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

Субпиксельное сглаживание

Ну, все что нужно знать о субпиксельном сглаживании — это то, что оно есть. Версию назад с этим были проблемы в хроме, но сейчас все работает так, как должно.

PNG


Недостатки растровой графики с такой необходимостью учитывать HDPI устройства, какая есть сейчас — очевидны. Возможно, если бы плотность ограничивалась 2 вариантами ретина\не ретина — это было бы достойным вариантом, и мало кому в голову пришло бы заморачиваться со всеми неоднозначностями вектора, существующими сейчас в вебе. Но у нас есть 1.5x, 2x, 3x устройства. И собирать спрайты под каждое из них уже не кажется достаточно изящным вариантом.

С другой стороны у растра без потерь есть достоинство, которое, лично для меня, перекрывает все недостатки в обслуживании — он стабилен. Можно быть точно уверенным в том, что как ты иконку нарисуешь — так она и будет выглядеть в итоге. Пиксель в пиксель. Вопрос лишь в том, нужна ли такая точность в каждом конкретном случае.

Итог


Я работаю над системой мониторинга и управления всяким серьезным оборудованием, вроде электрических подстанций или котельных. У нас есть солидная пачка иконок, обозначающих те или иные неисправности на объектах. Причем иконки эти встречаются в разных местах, разного размера и разного цвета. И мы на самом деле убили бы кучу времени, если бы делали все это в PNG, еще и под HDPI.

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

Пари


Так вот, зачем я все это написал? Я предлагаю юзерам, негативно отозвавшимся о производительности и рендере векторных иконок, в том посте, с которого все началось, или сочувствующих им и их точке зрения, пари.

Вы предоставляете мне верстку или какой-то конкретный сайт (что лучше), иконки на котором сейчас заверстаны в PNG и под ретину и под простые дисплеи, исходники иконок которого у вас есть в векторе, который при любых эффектах выдает 60FPS на средней машине. Сразу оговоримся что объективно это должен быть обычный сайт. Не онлайн софтина по работе с иконками и не пример из этой статьи.
Я заменяю растр на вектор и оптимизирую какими хочу способами.

В итоге должна получиться страница, на которой FPS проседает не больше, скажем, 30%. О дальнейших условиях договоримся в процессе. Как вам? Докажем ущербность SVG?

Similar posts

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

More

Comments 28

    +1
    А что доказывать ущербность того, что не ущербно? И если уж говорить об ущербности, то я вот всегда пасую перед иконками в шрифтах, так как не уверен в них никогда на 100%.
    В последнем проекте ради эксперимента я использовал иконки и в svg, и в png(в svg некоторые иконки весили более 30 — 40кб). Но вместе c растром я всегда храню и вектор, чтобы в случае необходимости я мог заменить одно на другое. Если вдруг станет необходимо поддерживать устройства, которые с svg не дружат — то запускаем любой рендерер svg(imagemagick, batik, phantomjs, etc), и конвертируем как угодно.
    Кстати, самый простой способ отсеять браузеры, которые svg не поддерживают точно, и наверняка не имеют ретина-дисплей — это хитрое задание бекграунда:

    background: url(image.png);
    background: url(image.svg) center / auto auto;
    /* auto auto - это background-size, старые версии браузеров хоть и знают про background-size, но background в такой записи проигнорируют, и отображаться будет image.png */
    
      +1
      в svg некоторые иконки весили более 30 — 40кб
      Это что-то за гранью добра и зла уже. You do it wrong.

      Можно конечно быть не уверенным в шрифтах, например, но это не дает право рассуждать о них в категориях «ущербности». Тут скорее
      я вот всегда пасую перед иконками в шрифтах, так как не уверен в них никогда на 100%.
      В статье об этом и речь в общем.
        0
        Кстати, больше года назад я на эту тему писал статью «Кроссбраузерный SVG логотип» (http://blog.g63.ru/?p=1738), рекомендую ознакомиться. Разумеется, прием описанный в статье, можно использоваться не только для логотипа.
        0
        Переход на svg иконки практически исключает дизайнеров в будущем рисовать полноцвет в растре, ведь обратно уже никто не будет нарезать под каждый дисплейчик ничего. То есть растр будет умирать в вебе из за невозможности поддержки кучи устройств. Будет вектор с кучей фильтров и градиентов, пытающихся заменить то что так просто рисовать в растре -тени.
        Че за херня, яндекс, давай сведи все в один шейп)
        image img.yandex.net/i/wiz6.png
        image img.yandex.net/i/wiz1.png
        А он и рисует уже кстати в svg давно.
        Еще вопрос не понятен на счет размера спрайта с svg иконками. Gzip спасает?

        Да и иконка pinterest для теста совсем не подошла, разницы я не вижу. Вижу что она есть у обоих, но кто лучше… не скажу.
          –1
          Ну, допустим вот эти 2 иконки все равно вероятно были векторными в процессе создания. Чем проще рисовать в растре тени — я понятия не имею. Это градиент. SVG поддерживает градиенты. Все. По части оптимальности конечно да, есть вопросы. Но ситуация сегодня такова, что даже такой вектор нормально отрисуется и FPS почти не просядет. Тем не менее тут растр будет удобнее. Зачем за уши притягивать вектор сюда? Подождем когда ребята из гугла наконец вернут назад SVG кэш. Вот тогда можно будет говорить о том, чтобы выбрасывать растр вообще.
          А что с размером? Для png спрайта спасает?

          Ну про иконку pinterest мне сказать нечего, если не видно разницы на 15-м и 16-м кеглях.
          • UFO just landed and posted this here
              0
              Ха, спасибо! Тут я тупанул, да. На самом деле ничего сам не рисую. Думал что там есть какие-нибудь градиенты по контуру. Погуглил, можно как-то с Blend извращаться, но все равно костыль как надо.
                +1
                Такие тени рисовать можно через gradient mesh, но этой вещи нет в SVG а что касается ее производительности могу только догадываться.
          • UFO just landed and posted this here
              +2
              Ну вот нарисуйте первую от яндекса с облачком. Вектор вектору рознь, в илюстраторе нариcуете (там есть градиентная сетка), а в SVG — нет.
              А главное, не забудьте сравнить размер выходного файла, не будет ли он весить раз в 10 больше при такой детализации.
              Вектор изначально был разработан для полиграфии, а потом он все развивался и развивался и главная его пролема — что достигая детализацию растра он становиться все более медленным. Вектор изначально ущербен в плане худ. возможностей. Он значительно требователен к себе.
            +1
            По опыту моей имплементации SVG в Sciter

            В Sciter:
            1. <img src="something.svg"> продуцирует DOM элемент у которого картинка есть фактически [cached] bitmap который получается путем «проигрывания» SVG на bitmap surface. Такой bitmap живет в GPU (как текстура) Последующие paint команды это сугубо rendering той bitmap на уровне GPU — крайне эффектвно. При изменении размеров img элемента «проигрывание» SVG осуществляется по новой. Растеризация в этом случае делается CPU — может быть затратно ибо CPU он один на всех.

            2. Inline SVG вида <svg>... svg DOM elements... </svg> всегда транслируется в живое DOM под-дерево host документа. DOM access методы позволяют модифицировать содержимое такого svg island стандартным образом. CSS правила описанные в host html document позволяют стилировать в том числе элементы внутри такого <svg>. Rendering inline svg не использует caching — SVG dom элементы рисуются покомпонентно в процессе исполнения paint ( WM_PAINT на Windows, NSView.drawRect на Mac ). На Windows используется Direct2D поэтому примитивы транслируются в DirectX/GPU команды (не все, но в основном).

            Мое личное мнение по поводу SVG:

            Я бы ввёл метрики:
            source byte / bandwidth — per pixel — сколько байт исходного SVG текста требуется на один пиксель изображения. Скажем вот для этого примера:
            image
            16kb source рендерится в 48*48 RGBA bitmap (9kb) — ratio = 1.7. Чем больше [единицы] это оношение тем SVG хуже если сравнивать с PNG у которого это ratio практически всегда меньше 1. bandwidth — per pixel это кстати не только про bandwidth, но также и про CPU-per-pixel и RAM-per-pixel.

            Чем проще SVG и чем больше прямоугольник куда этот SVG выводится тем выгоднее его использование. Для небольших (по размерам) икон SVG не выгоден.

            Собственно поэтомуя в Sciter наравне с SVG и сделал поддержку @image-map (a.k.a. CSS sprites с человеческим лицом) и expandable images — эффективность bitmaps с возможностью рендеринга на разные DPI.

            Примеры из Sciter SDK: /samples/svg/, samples/css++/backgrounds++.htm и samples/image-map/
              0
              1. <img src="something.svg"> продуцирует...
              Да, все так и работает в Firefox, например. Да сколько там графики будет на среднюю страницу не контентной? Ну может быть в конце получится bitmap в метров 10. В GPU памяти хранить конечно вообще win. Но даже если решили сэкономить ее, ну можно в простую этот кэш бросить.
              Вот расскажите, как человек, который имплементил это. Насколько критично дела с памятью обстоят в таких случаях?
                0
                Реальный выигрыш SVG, как я уже сказал, получается когда SVG заливает большую поверхность дисплея чем нибудь простым типа набора paths которые после tessellations (в GPU) превращаются в набор треугольников — эффективных примитивов рисования. Рисование треугольника это одна машинная команда в GPU если можно так выразиться — практически не зависит от количества закрашиваемых пикселей.

                На high-dpi дисплеях (300 dpi) вектор (SVG) в принципе может быть выгоден даже на иконах. Угловые размеры икон в принципе одинаковые на любом мониторе, т.е. количество пикселей ими занимаемое становится больше в 9 раз — (300dpi/96dpi)²

              0
              А вот интересно кто-нибудь всерьез тестировал на совместимость расширенный юникод в котором 32 чемодана символов? )
              например
              ☯ ☭ ☣ ☀ ⚽ ⏰ ✔ ✠ ✌ ☕
                +3
                И че с этими наскальными рисунками делать?)
                • UFO just landed and posted this here
                  0
                  Еще такая штука developer.mozilla.org/en-US/docs/Web/CSS/image-rendering

                  image-rendering:-moz-crisp-edges; 
                  image-rendering: -o-crisp-edges; 
                  image-rendering:-webkit-optimize-contrast;
                  -ms-interpolation-mode:nearest-neighbor;
                  


                  Позволит убрать интерполяцию при увеличении на ретине, к примеру. Может быть растр простых иконок без бикубической интерполяции будет смотреться не так как «мыло»)
                    0
                    Есть. Как мыло конечно не выглядит, но и красотой не блещет тоже, что закономерно. Ну, тут принципиальная же разница с вектором.
                      0
                      Для SVG есть подобное сглаживание
                      developer.mozilla.org/ru/docs/Web/SVG/Attribute/shape-rendering
                      Оно позволяет увеличить производительность или качество отрисовки в ущерб скорости.
                      0
                      По части вещей вроде SVGO — я отношусь к ним довольно скептически
                      SVGO не только убирает лишние пробелы и строки, но и оптимизирует фигуры. Например, вот два пересекающихся квадрата, экспорт из Скетча:

                      Было
                      <rect x="0" y="48" width="110" height="110"></rect>
                      <rect x="48" y="0" width="110" height="110"></rect>
                      
                      Стало
                      <path d="M0 48h110v110h-110zM48 0h110v110h-110z"/>

                      Если почитать содержимое d="…" в «Стало», то там, по сути, то же самое, но такой формат записи кажется оптимальнее для машины, плюс одна нода вместо двух.
                        0
                        Ну я видел лист с фичами, да.
                        Еще для этих целей можно использовать SVGO. Кажется объединение в общий shape — это единственная его часть, которая действительно драматически влияет на производительность.
                        Он там атрибуты какие-то и мета-инфу удаляет и вообще больше про парсинг. Еще правда близкие к целым координаты округляет — хорошая штука.
                        0
                        Сжатие должно творить чудеса, но вот вопрос: шрифтовые иконки: стоит ли игра свеч?
                        Вектор уже есть, сконвертить в SVG обычно тривиально, а вот получить качественный шрифт в GNU может быть проблематично, мы обязательно теряем цвета, всегда встаёт вопрос браузеров (особенно в РФ, где самые дорогие сайты требуют 8-ого ослика), ресайз немного не очевиден. А каковы плюсы?
                          0
                          Зато перед нами открывается куча возможностей начиная от банальной смены цвета и размера, заканчивая пачкой CSS манипуляций с шрифтами, вроде тенюшек и т.д.
                            –1
                            Это не преимущество шрифтовых иконок, CSS можно применять и к SVG.
                              +1
                              Ну, строго говоря — нет. Т.е. если в DOM ее положить, то да, можно использовать специфичный CSS этот. Мы ведь не о таком варианте говорим, надеюсь? Но если подключать спрайт, допустим, через background-image — ничего там не изменишь уже.
                                0
                                Кажется, самый удобный и оптимальный вариант использовать именно в DOM внешний SVG-спрайт с помощью: d.froloff.me/B0Gv (не дают вставить код).
                                Можно и к шейпам такой иконки потом обращаться. Единственный минус — тень нормально не отбросить, кажется.
                          0
                          удалено
                            0
                            Спасибо, что продолжил поднятую мной тему! Добавил ссылку в пост.

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