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

Все современные цифровые шрифты в своей анатомии строятся по принципам физических аналогов. Те шрифтовой дизайнер разрабатывает пропорции и отрисовывает литеры также, как он это делал 80 100 и 1000 лет назад. 

Для вывода на печать, на LT монитор, Oled и e-ink дисплей мы используем одно и то же начертание шрифта, скажем гарнитуры Helvetica. Которое в свойствах файла не несет разницы между отраженным и прямым источником света. 

А поскольку шрифт разрабатывается по старинке «черным по белому» параметры в его анатомии анатомии подгоняются под оптические искажения и иллюзии именно под черную заливку. Это раззз.

Оптические иллюзии могут показаться не существенными, при разборе конкретной буквы, но в общем восприятии текста играют большую роль. Просто, но наглядно об этом рассказывает документация Google Material Design на примере иконок, где для соблюдения визуального баланса радиус для круглых иконок рекомендуют использовать больше чем ширину квадратной. Типографика вся из этого состоит.  

Рендеринг шрифтов

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

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

Все это кажется неважным пока мы не смотрим на результат нашими глазами. И в первом приближении — это снимок экрана через объектив на фотокамеру. 

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

Обратный эффект имеем в жирности начертаний и «просветах». Рассеивание света визуально делает просветы меньше, чем они рассчитывались для растеризации темных литер.  

Эти эффекты справедливы еще для двух параметров шрифта: кернинга и лигатур. 

На тесте у меня гарнитура Bodoni Moda / начертание Regular / пункт 16. Но в стандартах Material design и Human Design UI минимальный набор кегля для объекта — 10, body text — 12 / 14. В таком кегле контраст не спасет даже гротеск: Roboto и San Francisco. 

P.S.

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

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


  1. siberianlaika
    29.12.2022 17:38
    +4

    Отмечу, что в IDE нередко выбирают моноширинные шрифты адаптированные именно под отрисовку на мониторе, еще с тех времен когда каждый пиксель в символе был хорошо различим ) Для них в принципе проигнорированы принципы шрифтового дизайна, в угоду распознаваемости на мониторе и отрисовки букв одинаковых по ширине в своих знакоместах. Вот у меня сейчас в терминале и в Emacs по умолчанию шрифт Droid, видимо наследник этих принципов - моноширинный, толщина линий у букв выдержана примерно одинаковой, хорошо распознаётся как на белом, так и на чёрном, но он уже не выглядит так угловато, как ранние шрифты для мониторов или матричных принтеров (кто может помнит доисторические ПК, как начертание кирилицы запихивали в матрицу каких-нибудь 6x8 пикселей, больше всех страдали буквы Ы и Щ).

    По-моему тёмные темы пошли со времён ЭЛТ, когда наблюдать создаваемый электронным лучем белый фон было физически просто утомительно, даже на дорогих мониторах (помню для повышения контраста на мониторы нацепляли стеклянные фильтры). С развитием ЖК дисплеев, когда смогли достигнуть высокого контраста и внятной цветопередачи (вероятно с появлением IPS в 90x) это стало не так критично.


    1. AndrewYaremko Автор
      29.12.2022 17:46

      Да были времена когда шрифты были растровые. и каждый кегль был отдельным набором изображений. растеризация тогда была ручная. Так создавалась Verdana и Tahoma. И все же. Когда цифра стала поддерживать шрифтовые гарнитуры все они ориентировались по традиции на визуальное восприятие четных букв. О Из чего и выросли современные алгоритмы растеризации. Но при этом даже ретина не помогает избежать эффекта источника прямого света, а не отражения.


    1. ksbes
      30.12.2022 11:01
      +3

      По-моему тёмные темы пошли со времён ЭЛТ, когда наблюдать создаваемый электронным лучем белый фон было физически просто утомительно, даже на дорогих мониторах (помню для повышения контраста на мониторы нацепляли стеклянные фильтры).

      Нет. Совсем не так — как раз развите ЭЛТ и привело к появлению «белых тем» — т.к. изначально монохромная консоль была тёмная (чаще всего) — именно из-за физического, а не илюзорного расплывания светящегося пятна.
      Потом пошёл цвет и этот цвет надо было показывать. Так что эпоха ЭЛТ — это эпоха цветастых до вырвиглазия, ярких интерфейсов и, соответсвенно, «светлых тем». По принципу: «не монохром»!

      А те фильтры — они не для повышения контрастности (как вообще пассивный фильтр может контрастность повысить?), а для защиты от «рентгеновского излучения». Тормозящиеся маской и люминофором элетроны излучают (за счёт ускорения) всякие ЭМ волны (для справки — на похожем принципе работаботает СВЧ печка). Поэтому сидеть за 19ти дюймовым высококонтрастным (т.е. с мощной электронной пушкой) монитором по десятку часов в день — это существенно повышать риски всяких раков. По крайней мере — так считалось. (Ну и кактусы, конечно, чтобы своими иголочками это излучение на себя ловить :) )


      1. Stanislavvv
        30.12.2022 11:15

        Контраст повышался за счёт уменьшения бликов, которые на выпуклом мониторе видны почти из любого положения (простейший сетчатый фильтр их точно подавлял, чем мне когда-то на первой работе сильно облегчил жизнь), так что формально - фильтры таки работали.
        Что касается рентгена - очень сильно сомневаюсь, что продававшиеся тогда фильтры заметно фильтровали.


  1. RigidStyle
    29.12.2022 17:38

    Ну на счет контраста и т.д. это да. Ужас. И надо все менять (запихивать какой то постобработчик всего).

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


    1. AndrewYaremko Автор
      29.12.2022 17:49
      +2

      увеличив вес «просветы» уменьшатся и визуально вы получите совсем иную литеру, нежели ту что задумывал дизайнер шрифта. На счет все менять. Как раз с новым проектом буду думать, может с его запуском напишу какие решения в конечном счете использовал для ui. Но руки чешутся не в запой на праздники уйти, а в типографику. Старею.


  1. aamonster
    29.12.2022 18:29
    +3

    Для начала у вас гамма неправильная для отрисовки шрифта (ну или у меня, но, боюсь, тогда и у большинства неправильная). Всё прочее иметь смысл смотреть, только когда она настроена.


    1. AndrewYaremko Автор
      29.12.2022 18:51
      +1

      С изменением гаммы алгоритм растеризации не поменяется) А тот вакт что 99% дизайнеров делают инверсию в лоб моя гамма тоже не сильно поправит. Посмотрите как реализованы ужасно и сами андроиды, и приложения даже на иос с поддержкой dark mode. О том, чтобы изменить гамму у растра и иллюстраций на темной теме я вообще молчу. Я к тому, что народ не заморичивается — это ведь денег стоит — написать отдельный набор стилей под новую тему, а зачем, если народу и так — ок.

      А вот гаммы настраиваются в основном для темных интерфейсов — это да. Но они обычно не имеют иной цветовой раскраски.


      1. aamonster
        29.12.2022 21:46
        +2

        С изменением гаммы у вас даже инвертирование поменяется.

        Пусть гамма=2.0. Тогда пиксель с 50% светимостью будет иметь яркость 0.5**(1/2.0)=0.7 (берём шкалу, где белый – 1). Его негатив тоже будет иметь яркость 0.7, а вовсе не 0.3. Иначе весь anti-aliasing и sub-pixel accuracy сломаются (что и видно на ваших скриншотах).

        Грубо говоря, реальная формула для негативного изображения, не портящего сглаживание – negate(x) = (1-x**gamma)**(1/gamma).
        Ну, с растеризацией шрифта всё чуть проще, она изначально должна считаться с учётом гаммы, только и всего.


        1. AndrewYaremko Автор
          29.12.2022 22:54
          +1

          Здесь до субпикселей как до луны . Снимок же в статье с ретины. Поэтому о субпиксельной и цветовой растеризации в статье ни слова.

          Вы пердлагаете гамму поднять и тогда будут видны тонкие места, но при этом и толстые станут еще толще, а просветы и кернинг, соответственно, еще меньше. Пример с W.


      1. ArkadiyMak
        29.12.2022 22:54
        +7

        Алгоритм растеризации фритайпа выдает маску глифа в линейном пространстве. Но дисплеи обычно используют гамму 2.2, поэтому блендить текст с фоном нужно с гамма-коррекцией. Иначе получается нечитаемый белый текст на черном фоне, зато черный на белым выглядит вроде как прилично:

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

        Бледный черный никому не понравился, поэтому начали делать костыли типа утолщения контуров на мелких кеглях или меньших значений гаммы.
        https://freetype.org/freetype2/docs/hinting/text-rendering-general.html


        1. AndrewYaremko Автор
          29.12.2022 22:58
          +3

          Вот и посмотрите, на сколько визуально меньше «просветы» и больше капли стали в вашем примере. Читать такой текст много труднее.


          1. orekh
            30.12.2022 05:29

            В вашем каменте выше «белый на чёрном» после гамма-коррекции стало легче читать.


            1. AndrewYaremko Автор
              30.12.2022 05:51

              Ага, но шрифт от этого изменился в пропорциях.


  1. adeshere
    30.12.2022 03:09
    +2

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

    под спойлером

    дело в том, что я, в основном, работаю с графиками. Обычно в одном окне - кривые, в другом - Wоrd/Excell и набираемый текст, в третьем Notepad++, где открыт генерируемый программой протокол обработки данных, чтобы таскать оттуда всякие цифровые статистики; там тоже стандартный черный шрифт на белом фоне. Переключение между этими окнами не вызывает проблем - глазам комфортно, все смотрится и читается адекватно.

    Но как только мне нужно инвертировать картинку с графиками для публикации или для коллег, начинаются траблы. Как бы я ни варьировал цвет кривых на основном рабочем (черном!) экране, подкручивая там всякие биты, после инверсии палитра превращается в катастрофу. Вот

    пара примеров
    рисунок на черном фоне, с которым мне комфортно работать
    рисунок на черном фоне, с которым мне комфортно работать
    и он же на белом после инверсии
    и он же на белом после инверсии
    еще один рисунок на черном фоне
    еще один рисунок на черном фоне
    и он же на белом после инверсии
    и он же на белом после инверсии

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

    Причем "светящиеся" кривые на черном фоне совершенно не требовательны к нюансам. Там можно делать с цветом почти что угодно - графики равно будут выглядеть хорошо. Ограничения возникают, только когда надо нарисовать сразу много кривых, четко отличающихся друг от друга вне зависимости от настроек монитора (максимально я ограничился 12-ю отличающимися цветами; их маски ниже под спойлером). А вот на белом фоне подобрать комфортный набор цветов почти невозможно. Они либо ядовито-уродливые, либо блекло-невнятные.

    В итоге вместо простой инверсии цвета я в программе был вынужден отдельно задать

    набор цветов для черного и для белого фона.
    c
    c=======================================================================c
    c     3.1.1. Стандартные цвета графиков (частично повторяют текст-цвета)c
    c=======================================================================c
    c     В примечании отмечены цвета, которыми рисуются графики
    c     Массив plot_color= pc(i) задает цвет i-го графика на черном фоне, 
    c     а invert_plot_color= ipc(i) задает цвет i-го графика на белом фоне:
    c
    !     ВАРИАНТ 3
    !                          ! Blue    Green    Red        !   B   G   R
         +   $pc01  =2#00000000 00100000 11111111 00100000,  !  32 255  32  $LGreen       
         +   $pc02  =2#00000000 00010000 11111100 11111100,  !  16 252 252  $Yellow-
         +   $pc03  =2#00000000 11111000 11111000 01000000,  ! 248 248  64  $Light_Cyan   
         +   $pc04  =2#00000000 00000000 00000000 11111111,  !   0   0 255  $Light_Red    
         +   $pc05  =2#00000000 11111111 00000000 11111111,  ! 255   0 255  $Light_Magneta
         +   $pc06  =2#00000000 11111111 00001000 00001000,  ! 255   8   8  $Light_Blue+
         +   $pc07  =2#00000000 00000000 10100000 00000000,  !   0 160   0  $Green+
         +   $pc08  =2#00000000 00010000 10010000 10100000,  !  16 140 156  $Brown        
         +   $pc09  =2#00000000 10101000 10101000 00000000,  ! 168 168   0  $Cyan         
         +   $pc10  =2#00000000 00001000 01010000 11111000,  !   8  80 248  $Red+White
         +   $pc11  =2#00000000 10001000 01100000 10001000,  ! 136  96 136  $Magneta+White
         +   $pc12  =2#00000000 11101000 01000000 01000000,  ! 232  64  64  $Blue+White
                                                             !   B   G   R                 
         +   $ipc01 =2#00000000 00000000 01001111 00000000,  !   0  79   0  $BlackGreen   
         +   $ipc02 =2#00000000 00000000 00000000 10011100,  !   0   0 156  $Red          
         +   $ipc03 =2#00000000 10011100 00000000 00000000,  ! 156   0   0  $Blue         
         +   $ipc04 =2#00000000 00000000 10010000 11110000,  !   0 144 240  $Orange       
         +   $ipc05 =2#00000000 11000000 00001111 11000000,  ! 192   0 192  $Gray_Magneta 
         +   $ipc06 =2#00000000 10001111 10001111 00000000,  ! 143 143   0  $Cyan         
         +   $ipc07 =2#00000000 00100000 01101111 00100000,  !  32 111  32  $Gray_Green   
         +   $ipc08 =2#00000000 00000000 10010000 10010000,  !   0 144 144  $Brown        
         +   $ipc09 =2#00000000 11000111 11000111 00011111,  ! 199 199  31  $Gray_Cyan    
         +   $ipc10 =2#00000000 01000000 01000000 01111111,  !  64  64 127  $Gray_Red     
         +   $ipc11 =2#00000000 10001111 00000000 10001111,  ! 143   0 143  $Magneta      
         +   $ipc12 =2#00000000 01111111 01000000 01000000,  ! 127  64  64  $Gray_Blue    

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

    А теперь собственно вопрос: в чем дело? Почему так сложно подобрать цвет для графиков на белом экране? Почему при простой инверсии "черных" изображений "дружественность" палитры почти всегда резко падает? Что посоветуете? Как это исправить? Есть ли какие-то простые правила (мнемоника?), чтобы построить несколько вариантов палитры, которые должны хорошо инвертироваться, и потом выбрать один из них, а не пробовать все подряд, в надежде случайно угадать то, что понравится?

    Или это у меня какое-то извращенное зрение/восприятие, и вы на моих "белых" картинках никакой катастрофы не видите?

    P.S. Добавлю еще, что все картинки у меня векторные, чтобы было удобнее редактировать. И что инверсию цвета я обычно я делаю в Irfan View, хотя это вроде влиять не должно. (Еще я пробовал после инверсии подгонять цвета в Corel, но там тоже по умолчанию какой-то очень странный набор цветов для белого фона, который приемлемо смотрится при печати, но кошмарно - с экрана).

    P.P.S. И от монитора это вроде бы не особо зависит. У меня он стандартный, настройки по умолчанию... на других мониторах все примерно так же.

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


    1. AndrewYaremko Автор
      30.12.2022 06:08
      +1

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

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

      https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors


      1. adeshere
        30.12.2022 14:21
        +1

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


    1. nin-jin
      30.12.2022 11:05
      -1

      Вам нужно переводить цвета в LCH и инвертировать в ней L - тогда с воспринимаемым контрастом будет всё норм.


      1. AndrewYaremko Автор
        30.12.2022 12:19

        С контрастом уже расторизованных пикселей. А кернинг то кто будет править? Даже если они подряд залитые линии отрисованные в аккурат пиксель в пиксель будут казаться теснее.


  1. nebularia
    30.12.2022 07:22
    +1

    Условный Arial нормально смотрится в тёмной теме, а на псевдотипографские мне с не очень зрением и на белом фоне смотреть-то больно...


    1. AndrewYaremko Автор
      30.12.2022 08:02
      +1

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

      Но я вас, кажется понял, речь о предпочтении гротеску. Я всегда за. И в интерфейсах, где можно избежать стилизации использую Богоподобную Futur'у и Montserrat. Не гельветику тк на экспериментальных данных Футуроподобные считываются легче, как людьми с проблемным зрением, так и с нормальным.

      Вообще тема крайне спорная, научная база - ни о чем. За 6 лет я выбрал несколько исследований которым доверяю больше всего и остановился на этих шрифтах. Мой личный субъективный выбор)


  1. Mike-M
    30.12.2022 14:14

    нарушен базовый принцип типографики
    … сказал автор, у которого в статьях ошибка на ошибке сидит и ошибкой погоняет.
    Хуже того, автор не желает исправлять свои ошибки даже после многократных сообщений через Ctrl-Enter ????


    1. AndrewYaremko Автор
      30.12.2022 14:25

      Типографики, а не орфографии и пунктуации))) вот ошибка куда как серьезнее чем опечатки))


    1. AndrewYaremko Автор
      30.12.2022 14:31

      Но за указания ошибок спасибо, я все поправлю когда буду в ресурсе, чтобы опять не наделать их)


  1. redsh0927
    31.12.2022 08:32
    +1

    Только это проблема не тёмной темы, а современных систем, которые разучились в рендеринг шрифтов. Вместо чётких и ровных буковок рисуют какую-то мыльную хрень. К счастью, фаерфокс на винде пока справляется

    Заголовок спойлера
    image