Нечёткость значков истомляет нас

в 13:51, , рубрики: android, Firefox, inline SVG, iOS, opera, OS X, PNG, retina display, shape-rendering, svg, webkit, векторная графика, значки, иконки, Иконосказ, спрайты, субпиксельная отрисовка, субпиксельный антиалиасинг, субпиксельный рендеринг, типографика, шрифты

После появления сетчаточных дисплеев люди ищут альтернативы PNG-значкам, не зависящие от разрешения. Кто-то влюбляется в шрифтовые значки, другие кричат «SVG». Сожалею, но если вы ищете панацею, то я боюсь, что её не существует. Давайте поближе поглядим, какие у нас есть варианты.

Шрифты со значками восхитительны, но…

они размыты. В них нет настоящей, попиксельной резкости. Да, использование @font-face для значков обрело заметную популярность. Я и сам рекомендовал и даже стал коллекционировать их. Но в таких значках есть изъян, который меня достаёт. Они всё ещё немного размываются на несетчаточных дисплеях (а таких до сих пор подавляющее большинство). Попробуйте поуправлять размером у Криса в демонстрации и вглядитесь попристальнее. Эффект по-разному проявляется у разных размеров, но все они имеют одну и ту же проблему «полупиксельной размытости». Возможно, её заметить не так просто, так что вот здесь я увеличил скриншот пятнадцатипиксельного размера (а заодно и фоновый шум убрал):

Нечёткость значков истомляет нас

Субпиксельное сглаживание превосходно срабатывает на кривых линиях, но не на прямых — они просто перестают выглядеть чёткими. В теории можно было бы использовать хинтование шрифтов, чтобы контуры значков приближались к целопиксельным. Но до сих пор я не знаю ни одного такого шрифта значков, который бы так и сделал. Я также догадываюсь, что хинтование потребовало бы существенного дополнительного труда автора шрифта и заметно увеличило бы объём файла.

Довесок: @thijs подмечает, что хинтование работает только в тех системах, которые его поддерживают — а в OS X, iOS и Android не поможет.

SVG спешит на помощь?

Да нет, на самом-то деле. У использования SVG-значков есть большое преимущество: в своём первоначальном размере они выглядят чётко, с точностью до пикселя. Однако, стóит лишь начать изменять их размер, как они всё так же субпиксельно размываются, покуда вы не достигнете размера, кратного их первоначальному размеру. Обратите внимание на вид внутреннего креста:

Нечёткость значков истомляет нас

На практике использованием только кратных размеров можно обойтись. Создаёте все свои значки в основном размере (скажем, 16 пикселов), а на крупных кнопках используете увеличенную версию в размере 32 пиксела или 48 пикселов.

Довесок: @erikdahlstrom да @Marco_Rosella упомянули свойство «shape-rendering: crispEdges». Если его наложить на отдельные прямоугольники в SVG, то оно принудит их стать целопиксельными. Пропорции могут исказиться, зато чёткость останется. Можете попробовать в jsFiddle.

Нет проблем? Хотел бы я этого; но есть и другие трудности:

  • Не так много хороших наборов значков в SVG.
     
  • Нехватка средств создания SVG-спрайтов.
     
  • Нельзя менять цвет значка при помощи CSS. То есть можно, но только если код SVG — внутренний (inline), а меня добавление кусков SVG в разметку документа не радует.
     
  • Нельзя накладывать эффекты — например, тень. (Есть фильтры в SVG, но их, опять же, с лёгкостью через CSS не поменяешь.)
     
  • И вот крупнейший облом: плохая поддержка в браузерах Firefox и Opera, когда SVG используется в качестве background-image. Оказывается, SVG на самом деле преобразуется в растр, и когда размер фона меняется, то браузер его не перерисовывает — только растягивает, и фон выглядит необыкновенно размытым. Язык не повернётся назвать это масштабируемой векторной графикою.

Нечёткость значков истомляет нас

Вот фиддл, можете сами проверить.

Можно, конечно, использовать inline SVG или поместить SVG в элемент <img>, но тогда SVG сложно сделать спрайтом. Разве что размещать элементы друг в друге и внешнему задать «overflow: hidden»? Но это всё же не такое прямое и гибкое решение, как «background-image».

Довесок: David Bushell нашёл обходной путь, делая размер SVG крупным и прибегая только к уменьшению, а не к увеличению.

PNGs

У многих шрифтов со значками также есть PNG-версия, которую можно использовать заместо шрифта, но вам придётся решить проблему показа высокочёткого варианта на сетчаточных дисплеях. Помочь делу может медиазапрос «device-pixel-ratio». Ну а Apple только что реализовала «-webkit-image-set» — выглядит многообещающе, но внедрение потребует времени.

Так что же делать? Как я и говорил… панацеи нету, но…

Вот небольшой рецепт, который может помочь.

  1. Начиная новый проект, в разработке и развитии прототипа используйте шрифты со значками. Ничто не сравнится со свободою быстрой и нетрудной замены значков, их перекрашивания, отбрасывания тени и наложения других эффектов.
     
  2. Затем в какой-то момент придётся принять решение: стоит ли перейти на значки в формате SVG или PNG со всеми их недостатками. Решить не так просто; всё зависит от требований и приоритетов. Может, даже план нарисовать придётся ;-) Вы должны быть готовы смириться с вышеперечисленными ограничениями форматов. Поглядите, уложится ли дополнительная работа в имеющийся бюджет, сосчитайте, сколько всего значков, понадобятся ли они в различных размерах или нет.

Одного формата картинок, годящегося для всех применений, нет на свете; возможно, никогда и не будет. Так что почему бы не использовать их вперемешку? Возможно, лучше всего использовать PNG (во множестве различных размеров) для высокочёткого разноцветного логотипа, а значки в SVG для навигационных кнопок одного и того же размера (но выглядящих чётче на сетчаточных дисплеях). Отзывчивый inline SVG для графиков и диаграмм, шрифт со значками для всех ваших кнопок различного размера. Мы ведь примерно так и действуем.

Взгляд в грядущее

Есть ли выход из нынешней томительной ситуации с её нечёткими значками? Ну… давайте просто обождём немного… как только повсюду будут сетчаточные дисплеи (да, пару лет это займёт), проблема субпиксельной чёткости окончится, а браузеры, возможно, исправят свои проблемы увеличения SVG, и тогда все мы отпразднуем появление значков, никак не зависящих от разрешения? Но и тогда нам придётся решать проблему зависимости детальности от размера.

Автор: Mithgol

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js