Меня зовут Владимир, я занимаюсь мобильным фронтендом в Яндекс.Почте. В нашем приложении уже была тёмная тема, но недожатая: мы умели перекрашивать интерфейс и простые письма. Но письма с форматированием оставались светлыми и контрастировали с тёмным интерфейсом, из-за чего глаза ночью могли уставать.


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


Простые способы


Прежде чем дойти до нашего волшебного «перекрашивателя», мы опробовали два простых, как пробка, варианта: навесить на элемент дополнительный тёмный стиль или CSS-фильтр. Нам они не подошли, но, возможно, для каких-то случаев будут даже лучше (потому что просто = круто).


Переопределение стилей


Самый простецкий способ, логично расширяющий тёмную тему самого приложения в CSS: повесим тёмные стили на контейнер для писем (в общем случае — для чужого контента, который нужно перекрасить):


.message--dark {
    background-color: black;
    color: white;
}

Но если у элементов внутри письма есть свои стили, они переопределят наш корневой стиль. Нет, !important не поможет. Идею можно дожать, отрубив наследование:


.message--dark * {
    background-color: black !important;
    color: white !important;
    border-color: #333 !important;
}

В данном случае без !important не обойтись, потому что сам по себе селектор не очень специфичный. Тем более это понадобится, чтобы переопределить инлайн-стили (а инлайн-стили с !important всё равно пролезут, ничего не поделать).


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



Если вы уважаете дизайнеров меньше, чем я, и всё же решите использовать такой метод, не забудьте допилить неочевидные мелочи:


  • box-shadow — только цвет переопределить не выйдет, придётся все тени убрать или жить со светлыми.
  • Цвета семантических элементов — ссылок, элементов ввода.
  • Инлайн-SVG — вместо background им нужно выставлять fill, а вместо colorstroke, но это не точно, смотря какой SVG — может быть и наоборот.

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


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


CSS-фильтр


Очень остроумный и элегантный вариант. Перекрасить страницу можно CSS-фильтром:


.message--dark {
    filter: invert(100) hue-rotate(180deg); /* hue-rotate возвращает тона обратно */
}

После этого фотографии станут криповыми, но это не беда — их перекрасим обратно:


.message-dark img {
    filter: invert(100) hue-rotate(180deg);
}


Остаются проблемы с контентными картинками, привязанными через background (знаем, так удобнее подстраивать соотношение сторон, но как же семантика?). Допустим, что мы сможем найти все такие элементы, явно их пометить и перекрасить обратно.


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



  1. Тёмные страницы осветляются.
  2. Итоговыми цветами невозможно управлять — какой фильтр наложить, чтобы подстроить фон к вашему фирменному #bbbbb8? Загадка.
  3. После двух перекрасов картинки выцветают.
  4. Всё тормозит (особенно на телефонах) — логично, теперь вместо простой отрисовки браузеру нужно на каждом экране гонять обработку изображений.

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


Адаптивная тема


Настало время волшебства! Из недостатков первых двух подходов собираем чеклист:


  1. Делать фон тёмным, текст — светлым, границы — средними.
  2. Определять уже тёмные страницы и не перекрашивать их.
  3. Сохранять оригинальное соотношение яркостей и контрастов.
  4. Давать возможность настройки цветов.
  5. Оставлять тона такими, какими они были вначале.

Нам нужно изменить цвета стилей так, чтобы фон был тёмным. И почему бы не сделать это буквально? Просто берём все стили, ищем правила, связанные с цветами (color, background, border, box-shadow, их подсвойства), и заменяем его на «затемнённое» — затемняем фон, осветляем текст, границы затемняем меньше фона и т. д.


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


Недостатки — стандартные для «everything-in-js». Да, мы гоняем скрипты, ломаем инкапсуляцию стилей и парсим CSS регэкспами. Ну, в отличие от HTML, последнее не так уж позорно, потому что грамматика (нужного нам уровня) CSS всё-таки регулярная.


План перекраски такой:


  1. Нормализуем легаси-свойства стиля (bgcolor и друзей), перекладываем их в style="...".
  2. Находим все инлайн-стили.
  3. В каждом стиле находим все цветные правила (background-color, color, box-shadow и т. д.).
  4. Из всех цветных правил достаём цвета, находим нужный преобразователь (затемнитель для фона, осветлитель для текста).
  5. Вызываем преобразователь.
  6. Собираем преобразованные правила обратно в CSS.

Обвязка (нормализация, поиск стилей, парсинг) довольно простая. Разберёмся с тем, как именно работает наш волшебный преобразователь.


HSL-преобразования


«Затемнить цвет» — не такое простое действие, как может показаться, особенно если мы хотим сохранить тон (голубой становится тёмно-синим, а не оранжевым). Сделать это в нормальном RGB можно, но проблематично. Любители алгоритмического дизайна знают, что там даже градиенты получаются кривоватые. Зато работать с цветами в HSL — чистое наслаждение: вместо Red, Green и Blue, с которыми непонятно, что делать, у нас появляются другие три канала:


  • Hue — как раз тон, который мы хотим сохранить.
  • Saturaion — насыщенность, которая нам сейчас не очень важна.
  • Lightness — яркость, которую мы будем менять.

Такое пространство удобно представлять в виде цилиндра. А наша задача — перевернуть этот цилиндр с ног на голову. Функции цветокоррекции делают что-то вроде (h, s, l) => [h, s, 1 - l].


Цвета, с которыми и так всё хорошо


Иногда ситуация складывается удачно: эксклюзивный дизайн письма (или его части) уже тёмный. В таком случае не нужно ничего менять, лучше просто тихонько порадоваться — вероятно, дизайнер подобрал цвета не хуже нашего алгоритма. В HSL достаточно смотреть на L — яркость. Если она выше (для текста) или ниже (для фона) порога (который, конечно, настраивается) — ничего не делаем.


Динамический цирк


Хотя нам это и не понадобилось (ещё раз спасибо, санитайзер, ты спас меня от безумия!), но я всё же расскажу, какие допилы нужны адаптивной теме, чтобы затемнять полные страницы, а не только дурацкие статические письма из девяностых. Аккуратнее, это задача для тех, кто любит запах селекторов по утрам.


Динамические инлайн-стили


Самый простой кейс, который ломает нашу затемнённую страницу — изменение инлайн-стилей. Операция частая, но и фикс простой: добавляем MutationObserver и оперативно чиним инлайн-стили при изменениях.


Внешние стили


Работать со стилями из <link> изнутри страницы довольно мучительно из-за асинхронности и @import, да и от CORS не веселее. Кажется, эту проблему можно было бы довольно элегантно решить через веб-воркер (прокси для *.css).


Динамические стили


Наконец, собирая в кучу все наши проблемы, вспоминаем, что скрипт вообще может добавлять, удалять и переставлять (специфичность! каскад!) <style> и <link>, да ещё и менять правила в <style>. Решается всё тем же MutationObserver на элементы стилей, но на каждое изменение — больше обработки.


CSS-переменные


Совершенно новый виток безумия наступает, когда в игру входят CSS-переменные. Затемнять сами переменные мы не можем: даже если допустить, что мы по формату угадаем, что в переменной находится цвет (хотя я бы не советовал этим заниматься), неизвестно, в какой роли он нам встретится — фон, текст, граница, всё сразу? Более того, значения переменных наследуются, так что нам уже нужно учитывать не только стили, но и элементы, к которым они применяются, и всё это быстро эскалируется и взрывается.


Если CSS-переменные доедут до мейнстрима, у нас проблемы. С другой стороны, к тому времени уже начнут подвозить color(), с которым можно будет не менять цвета в JS, а просто заменять цвета на color(var(--bg) lightness(-50%)).


Резюме



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


На практике адаптивный режим нужно использовать вместе с переопределением стилей: к стандартным элементам вроде <input> или <a> стили обычно явно не применяют, а по умолчанию они светлые.


Как затемнять картинки


Перекраска картинок — отдельная проблема, которая очень беспокоит меня лично. Это интересно, и у меня наконец-то есть шанс использовать словосочетание «спектральный анализ». С картинками в тёмной теме есть несколько типичных проблем.


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



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



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



Интересно, что иногда картинки вообще не несут никакой смысловой нагрузки — это трекинг-пиксели и «держатели формата» в особо извращённой вёрстке. Такие можно смело сделать невидимыми (скажем, opacity: 0).



Эвристики с интроспекцией


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


Считаем тёмные, светлые и прозрачные пиксели на картинке, причём не все, а выборочно — очевидная оптимизация. Определяем общую яркость картинки (светлая, тёмная, средняя) и наличие прозрачности. Тёмные картинки с прозрачностью инвертируем, светлые без прозрачности — приглушаем, остальные не трогаем.


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


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



Итог


Для полноценной тёмной темы в почте нам не хватало перекраски писем со стилями, и мы выяснили, как это устроить. Два простых варианта на чистом CSS — переопределение стилей и CSS-фильтр — не подошли: первый слишком сурово обходится с исходным дизайном, второй просто плохо работает. В итоге мы используем адаптивное затемнение — разбираем стили, заменяем цвета более подходящими и собираем обратно. Сейчас работаем над расширением темы на картинки — для этого нужно анализировать их содержимое и перекрашивать только некоторые.


Если вам когда-нибудь потребуется перекрашивать произвольный пользовательский HTML под тёмную тему, держите в голове три метода:


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

Даже если вы никогда не будете этим заниматься, надеюсь, вы интересно провели время!


Полезные ссылки:


  1. Если вам интересно обсудить эту тему вживую и в контексте разработки под Android, то приглашаем в гости 18 апреля в петербургский офис Яндекса.


  2. Недавно мы рассказывали о решении другой проблемы пользователей почты — проблемы рассылок.


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


  1. AndreyYu
    09.04.2019 11:11

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


    1. Paramid
      09.04.2019 11:25
      -1

      и к чему этот комментарий?


    1. hMartin
      09.04.2019 11:26

      У меня раздражение, когда я 100% времени работаю с темной темой IDE и приходится переключаться с в браузер, чтобы что-то подглядеть в гугле. Глаза аж выжигать начинает. Пробовал работать с светлой темой IDE и подвыкрученной подсветкой — не, глаза дико устают


      1. AndreyYu
        09.04.2019 11:27

        Я себе ставлю таймер на 25 минут, затем закрываю глаза секунд на 30 и затем смотрю дальше — получше ощущения.


        1. hMartin
          09.04.2019 11:54

          У меня стоит safeeyes (linux), настроил там каждые 15 мин разминку для глаз, каждые полчаса — 5 минут отдыха :)


      1. Paramid
        09.04.2019 11:35

        для браузера есть расширение, в win и macos давно есть такие вещи, как night shift.


        1. hMartin
          09.04.2019 11:56

          Для linux есть redshift, там можно цветовую гамму менять, да. Этим и живу :)
          Про расширения в курсе, пробовал, не всегда удобно.


    1. inoyakaigor
      09.04.2019 14:58

      Позволю себе с вами не согласится. Тёмные темы построенные на базе тёмно-серого фона не раздражают от слова «никак». Хотя, допускаю, тут играют роль индивидуальные особенности.

      Например:


  1. AngReload
    09.04.2019 11:40

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


    1. thoughtspile Автор
      09.04.2019 11:50

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


    1. Lynn
      09.04.2019 18:45
      +3

      На современных телефонах его кажется и нет.

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


  1. Stalkash
    09.04.2019 11:44

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


    1. thoughtspile Автор
      09.04.2019 12:04

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

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


      1. Stalkash
        09.04.2019 12:15

        Может быть, добавить какой-нибудь чекбокс «Перекрашивать картинки в соответствии с цветовой темой» рядом с кнопкой включения темной темы либо как-то явно уведомлять о перекрашивании картинок в теле письма при включении? Все же, тот же логотип хабра или майкрософта даже немного перекрашенные будут восприниматься пользователем по-новому, имхо.


        1. thoughtspile Автор
          09.04.2019 14:02

          Мы еще подумаем, как это лучше сделать, и будем держать это предложение в уме — спасибо!


  1. nezdhanov
    09.04.2019 16:15

    Хорошо, вы берете письмо от известной фирмы с их контрастным логотипом и уникальным дизайном письма и начинаете его перекрашивать? По моему немного некорректный подход если брать в расчет такое понятие как гайдлан и бренд? Как быть если контора захочет все таки сохранить свой к примеру логотип в девственном виде?


    1. VADemon
      10.04.2019 04:45

      Темная тема — отдельная опция в настройках. Я её нажал и да, я буду ожидать, что вещи будут по-другому выглядеть — мой выбор.


      Сравнивая с ранними браузерами, как концептом, главное было — передать информацию. Как текст отображался, какой шрифт и размер, какой размер экрана — вот это всё было за пользователем, и страницы (ожидаемо) могли выглядеть по-разному. Хотели иметь Comic Sans 24пт? Пожалуйста, в настройках браузера.


      Сейчас всё наоборот. Шрифт обязательно жёстко прописан в HTML/CSS и, как и весь остальной дизайн предписывается пользователю. Сместилась парадигма от "как-нибудь отобразить контент" до "чтобы обязательно у всех одинаково выглядело, как в макете". (Потому что технологии позволяют)


      Пример: использую я DarkReader расширение (ссылка в комм. выше) — сайты у меня теперь темные. Вот вы будете мне мешать изменять цвет на темный? Да, не "девственный" вид, да, не по style guide, от этого что-то хуже стало? Если тот же логотип не гнусно искаверкан, то он узнается.


      Лучше пример: встроенная читалка в Firefox. Некоторые нынешние вебсайты такого надизайнили, что читать в Reader банально удобнее (а был пример — ultra light font, тот вовсе был не распозноваем для комфортного чтения).


      Тут либо удобство пользователя (и контроль на его стороне), либо "видение" дизайнера. Мне, как вы видите, второе начало надоедать.


    1. suholet
      10.04.2019 12:52

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


  1. vt4a2h
    09.04.2019 17:04

    Жаль, что современные браузеры не умеют сообщить о том, что пользователь предпочитает тёмную тему. В этом случае, сайты могли бы использовать предопределённую тёмную тему. Вот это было бы действительно полезно, потому что, если ты, например, работаешь в IDE с тёмной темой, и потом например переключаешься доки почитать, а там тема светлая, то это не очень удобно.


    1. Lynn
      09.04.2019 18:47
      +2

      1. vt4a2h
        09.04.2019 22:55

        Довольно интересно, благодарю.

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

        Пока я вижу, что вопрос ещё открыт.


        1. AngReload
          10.04.2019 08:38

          Кроме MacOS, в Windows 10 также есть Dark Mode, и Firefox 67 это поддерживает. Но:


          Safari 12.1, Chrome 73 and Firefox 67 support Dark Mode!

          Тут излишний оптимизм. Ни в Chrome 73, ни даже в Chrome 76 prefers-color-scheme ещё не работает. Последний стабильный Firefox 66-й, а Safari 12.1 выпущен лишь неделю назад. В общем, рано пока.


  1. D3D9EX
    09.04.2019 17:37

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


  1. recompileme
    09.04.2019 18:02
    +1

    Делаю сейчас темную тему, в разрабатываемом мною приложении.
    Я применил для картинок в ленте — метод дизеринга Аткинсона. Они выглядят довольно спорно, но вполне читаемо. Не уверен что такой радикальный формат вам подойдет — но всё же

    Темная



    Светлая



    Для тела статьи — генерируются две картинки. Сжатая дизерингом — как плейсхолдер, на время загрузки. В случае оффлайн доступа — показывается только дизеринг версия (оригиналы не скачиваются на устройство для экономии места)



    Основной экран — обычный blue gray в терминах material. Оттенки серого вобщем:


    1. thoughtspile Автор
      09.04.2019 21:26
      +1

      Глитч-арт! В целом мне не кажется, что для нашего кейса писать свою обработку изображений на клиенте на JS — хорошее решение: потом все будут удивляться, отчего так быстро садится телефон. На сервере тоже по понятным причинам не хотелось бы.


      1. recompileme
        10.04.2019 09:38

        А на чем вы собираетесь делать спектральный анализ картинок если не секрет?


        1. thoughtspile Автор
          10.04.2019 10:37

          Конечно, на том же JS. Но есть одно важное отличие: если я взялся фильтровать картинку, то придётся фильтровать её всю: скромный 800x600 уже может всё подвесить. А вот для анализа достаточно взять 1000 пикселей — учитывая, что картинки обычно довольно гладкие, будет репрезентативно.


  1. recompileme
    09.04.2019 18:25

    А вообще лично меня в почтовых клиентах раздражают две вещи:
    — перевернутый скролл
    — отсутствие группировки по отправителю
    Идеальный почтовый клиент в моем понимании — это каналы в телеграм. Каждый отправитель это канал, раз. Напротив каждого отправителя — количество непрочитанных сообщений — два. При клике на отправителя — читаю его письма в хронологичеком порядке, начиная с последнего прочитанного — три. Собственно мое приложение придерживается тех же принципов и изначально я писал почтовый клиент. Это уже на ходу переобулся в читалку. Но надеюсь когдать вернусь к этому вопросу.


    1. rombell
      10.04.2019 08:35

      Пришло письмо на группу товарищей, один из товарищей ответил, другой- искать теперь по трём каналам, или как разруливать?


      1. recompileme
        10.04.2019 09:27

        Как групповой чат, например


  1. Torvald3d
    09.04.2019 18:45
    +1

    Я уже писал вам в саппорт, напишу ещё раз здесь: вы меняете тему, но не меняете цвет нижнего бара с кнопками, в итоге чёрный телефон, темная тема и белая полоска внизу.
    Samsung Galaxy Note 8
    image


    1. suholet
      10.04.2019 13:07

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


  1. wilerat
    09.04.2019 21:13

    Очень интересная статья.
    Мне приходилось тоже заниматься перекрашиванием стилей, хотя делал это на более простых стилях, и для моей цели это подошло.
    Делал это конвертацией цвета в lab, и инвертированием L канала.
    Однако чисто инвертация не очень хороша. На AMOLED экранах да, чисто чёрный цвет можно использовать, но всё же пока большинство использует IPS.
    И ещё, тёмная Holo тема не использует чёрный в качестве фона.
    Так что я конвертировал цвета с небольшим смещением относительно будущего чисто чёрного цвета.
    outLab[0] = 100 — outLab[0] * 0.85
    Отлично подошло под Holo тему.
    Вообще в приложениях с несколькими темами наверно неплохо делать две тёмных темы: тёмную и чёрную для amoled экранов.


    1. thoughtspile Автор
      09.04.2019 21:24

      Да, с подстройкой к окружающей теме, которая обычно не черная, пришлось повозиться. Если не секрет, почему LAB, а не HSL / HSV, которые концептуально попроще?


      1. wilerat
        09.04.2019 21:54
        +1

        В основном из за опыта использования lab в фотошопе. Приходилось много где с его каналами колдовать. Он очень хорош для операций я яркостью и насыщенностью.
        Плюс lab специально создавался c подстройкой под человеческое зрение.

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

        То есть изменение l канала в lab мне кажется будет лучше восприниматься визуально, чем то же самое в hsl
        И скорость обработки ну очень мало различается, особенно если делать hashmap из уже использованных цветов, и определять инверсию для цвета только 1 раз.


  1. ilya-ivanov
    10.04.2019 07:48

    Когда вы механически понижаете brightness в HSB/HSV, возникают оптические искажения, т.к. цветовосприятие не полностью соответствует «математике». Например, для глаз не существует тёмно-жёлтого цвета — он воспринимается как грязно-коричневый (хорошо заметно на третьем скриншоте). Чистый синий #0000ff изначально выглядит фиолетовым, но при понижении яркости синеет. И т.д. Плюс при естественном затенении тон обычно слегка смещается в холодную сторону.

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

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

    Об очевидных проблемах с тенями элементов вы уже упомянули — объемы теряются.

    Этот путь, скорее всего, приведёт к возникновению дополнительной мета-разметки или ограничений CSS-свойств для отправителей. Понадобится возможность защищать брендовые цвета, переопределять вручную какие-то нюансы и т.п.

    Пользовательский контент по мере развития CSS тоже усложняется: в самом письме могут задействоваться альфа-каналы и цветовые трансформации. Как такой каскад будет выглядеть после дополнительных преобразований — фиг знает. Предположим, фон плашки задан через rgba(255,255,255,0.7) поверх синего контейнера. Совокупно каждый пиксель светлый. И что с этим делать? :)

    В общем, дизайн нельзя адекватно затемнить простым смещением всего вдоль оси Brightness/Value. Результат всегда будет отличаться от оригинала, причем разницу трудно предсказать. Вы можете отправить человеку фото своей черной кошки на фоне серой шторы, а прислать в итоге картину Малевича «Черный квадрат» :)

    Мне кажется, принципиально более правильный подход — дать возможность отправителям самостоятельно предусматривать ночную версию своих писем. Понятно, что это вводит толику хаоса и не все будут заморачиваться. Но это логичнее. Если уж дневной дизайн создаётся на внешней стороне и находится вне вашего контроля, то на той же стороне должен создаваться и ночной. Нет смысла надстраивать структуру, которая от вас не зависит — результат будет очень шатким.

    P.S. Для инверсии логотипа взяли слишком простой пример. В большинстве случаев лого, рассчитанный исключительно на светлый фон, при инверсии будет выглядеть очень плохо:



    При всём при этом тема крайне интересная. Спасибо за пост и вообще за то, что делитесь с опытом — здесь есть о чём подумать)


    1. wilerat
      10.04.2019 11:39
      +1

      Хотелось бы указать вам, что вы перепутали понятия «инвертирование изображения» и «инвертирование яркости изображения»
      Здесь та же самая картинка c инверсией яркости (плюс 15% белого)

      Скрытый текст


      1. ilya-ivanov
        10.04.2019 12:15

        Принимается, спасибо) Зарапортовался. К сожалению, это не спасает итоговый результат — он всё равно далёк от приемлемого. Нельзя так с айдентикой обращаться, на мой взгляд.

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

        Утрированно говоря, если у одной фирмы логотип — черный круг, а у другой — белый круг, то при инверсии происходит подмена торговой марки)


        1. thoughtspile Автор
          10.04.2019 12:25

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

          Насчет логотипов хотел добавить, что всё таки большая часть темных логотипов — монохромные (да, у меня очень большая подборка). В случае с цветным акцентом становится сложнее, но самый адский кейс — черно-белый логотип, у которого, как ни крути, половина теряется.

          Юридический аспект нас тоже беспокоил, перекрашивать просто письма нам разрешили. Кажется, что дизайнеры совершенно спокойно рисуют однотонные версии логотипов для использования без учета яркости — шелкографией, выжиганием по дереву, термопечатью, что там еще бывает. Разъяснения ФАС я не получал, но кажется, подмена торговой марки — как раз регистрация белого круга при зарегистрированном черном)


    1. thoughtspile Автор
      10.04.2019 12:43

      Приятно получать развернутые ответы, спасибо.


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


      Дальше у нас целый спектр вариантов посередине:


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

      Каждый способ может сработать, а может и нет: не попробуем — не узнаем.


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


    1. suholet
      10.04.2019 13:10

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


  1. sergey-b
    10.04.2019 23:47

    Всегда удивлялся тому, что стандартом де-факто является черный текст на белом фоне. Нам ведь реально приходится часами смотреть на горящую лампочку. Это вредно и неудобно. Думаю, это все началось с Microsoft Word, который воплощал концепцию what you see is what you get. Чтобы сымитировать видимость белой бумаги стали всюду клепать белый фон. К сожалению, никому не пришло в голову, что на листе бумаги мы видим отраженный рассеянный свет, а на мониторе — прямое излучение. И только сейчас до разработчиков интерфейсов начало доходить, что до сих пор мы двигались не туда.


    1. vintage
      12.04.2019 10:40

      на листе бумаги мы видим отраженный рассеянный свет, а на мониторе — прямое излучение

      Монитор — не лазер, глаза не выжигает.


  1. sergey-b
    12.04.2019 10:41
    +1

    Выжигает, еще как.


    1. vintage
      12.04.2019 12:42

      Вы сейчас с физикой или физиологией спорите? При одинаковой яркости монитора и окружающего освещения нет никакой разницы.


      1. sergey-b
        12.04.2019 12:51

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


        1. vintage
          12.04.2019 13:38

          А вручную регулировать яркость освещения/монитора религия не позволяет?