UXPUB 🇺🇦 Дизайн-спільнота

Cover image for Создание темной темы для Stack Overflow
Редакція
Редакція

Опубліковано

Создание темной темы для Stack Overflow

30 марта 2020 года мы разрешили людям использовать бета-версию темной темы Stack Overflow. Давайте поговорим о проделанной работе.

Баннер, рекламирующий функцию темной темы

Я Аарон Шеки, главный дизайнер Stack Overflow по дизайн-системам. Я помогаю проектировать все компоненты интерфейса, которые собираются в новые функции.

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

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

Но именно я – тот парень, который наконец-то добавил тёмную тему в Stack Overflow.

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

Приступим!

Исследование цвета

При создании оригинальных цветовых шкал нашего продукта мы – возможно, наивно – взяли одно цветовое значение и изменили его, используя цветовое преобразование Less. Например, мы бы определили переменную Less @red и несколько раз затемнили бы ее на 10%, используя darken(@red, 10%). Затем мы бы несколько раз осветлили его tint(@red, 10%) на другом конце спектра. В результате мы бы получили цветовую шкалу от @red-050 до @red-900 с шагом в 10% между ними.

В моих первых исследованиях темной темы для Stack Overflow, я просто хотел протестировать изменение цветовой шкалы и замену белого фона на черный. При таком подходе цвет @red-050 стал @red-900, а значения в середине шкалы остались практически неизменными.

При таком подходе все стало непригодным с точки зрения контраста и это именно то, что мне не нравится в темных темах в целом. Обратите особое внимание на самое темное значение красного цвета на черном фоне. Оно почти неразличимо. Подробнее об этом позже.

Нам нужна темная тема получше этой

Начнем с макета

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

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

Выбор лучшего алгоритма

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

Первоначально самый светлый желтый оттенок был неотличим от белого, а самый темный оттенок желтого неотличим от черного

У нас были проблемы на темном конце спектра с каждым цветом. При использовании @red-900 и @blue-900 в качестве фона эти цвета были неотличимы от черного и друг друга. Нам был нужен алгоритм, способный дать цвета, которые по-прежнему считывались бы в качестве основного оттенка при самых светлых и самых темных значениях. Это позволяло бы нам создавать компоненты с этими значениями цвета.

Самые темные значения наших цветов были неотличимы друг от друга и от черного цвета

При создании компонента уведомлений мы не могли использовать цвета из нашей дизайн-системы. Вместо этого нам пришлось искать кастомные цвета.

Эти цвета прекрасны, но не основаны на значениях нашей цветовой шкалы

Я использовал удивительный сайт Colorbox от Lyft, чтобы нормализовать наши цвета. Вместо наивной линейной шкалы с шагом 10% я использовал кривые Безье – значительно улучшившие результат в разных концах шкалы.

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

Темные версии

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

Нормализованная цветовая гамма

Добавление цветов в Stacks

Перед тем как добавлять темную тему в Stack Overflow, мне сначала нужно было протестировать ее, используя в качестве песочницы нашу дизайн-систему Stacks.

Переменные

Мне нужно было преобразовать статические, Less-скомпилированные шестнадцатеричные значения в CSS-свойства времени выполнения. Это означало сохранение цветовых значений цвета var(--red-500) вместо статичного @red-500. Это была интересная задача. Мы обычно выбираем одно значение цвета, например, @red-500 и оттенки светлее или темнее для состояний фокуса и наведения курсора, и таких вещей, как фон и цвета границ.

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

Проблема с нативными CSS-переменными заключается в том, что вы не можете применить к ним любой тип преобразования Less. darken(var(--red-500), 5%)ломает компилятор, поскольку CSS-переменные оцениваются только во время выполнения.

Это означало, что мне нужно было реорганизовать способ создания кнопок. Мне следовало отойти от:

.s-btn {
    color: @white;
    background-color: @blue-600;
    border: 1px solid darken(@blue-600, 5%);

    &:hover {
        background-color: darken(@blue-600, 5%);
        border-color: darken(@blue-600, 10%);
    }
}
Увійти у повноекранний режим Вихід із повноекранного режиму

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

.s-btn {
    color: var(--white);
    background-color: var(--blue-600);
    border: 1px solid var(--blue-700);

    &:hover {
        background-color: var(--blue-700);
        border-color: var(--blue-800);
    }
}
Увійти у повноекранний режим Вихід із повноекранного режиму

Мне нужно было сделать это для всех компонентов Stacks, а не только для кнопок. Подобный подход применяется к уведомлениям, модальным окнам, кнопкам, ссылкам и т.д.

Совместимость браузера

Погодите секунду. Переменные CSS не поддерживаются Internet Explorer 11, браузером, который мы много использовали во время этого исследования. В конечном итоге мы приняли решение отказаться от поддержки IE11, убрав все CSS-хаки, добавленные нами за эти годы, чтобы заставить его работать. Затем мы отправили пользователям, использующим IE11, уведомление об устаревании, призывающее их установить новый браузер. Это решение не далось нам легко, и на его реализацию потребовались недели рефакторинга.

Условные классы (Conditional classes)

Благодаря тому, что IE11 больше не сдерживал нас, я смог работать с цветами в Stacks. Я решил добавить класс .theme-system к элементу body. При этом мы меняли светлые цвета на их темные эквиваленты по медиа-запросу темной темы. Кроме того, мы можем полностью пропустить этот медиа-запрос и просто вызвать темные цвета, добавив.theme-dark вместо body. Это позволит пользователям видеть темную тему независимо от настроек их системы. Мой подход в итоге выглядел так:

body {
    --red-600: #c02d2e;
}

body.theme-system {
    @media (prefers-color-scheme: dark) {
        --red-600: #d25d5d;
    }
}

body.theme-dark {
    --red-600: #d25d5d;
}
Увійти у повноекранний режим Вихід із повноекранного режиму

Для обеспечения полной гибкости, Stacks предоставляет атомные классы цвета, которые применяются только при включенной темной теме. Вы можете подробнее прочитать о CSS решениях Stacks в моем личном портфолио. Добавляя.d:bg-green-100 к элементу, наши разработчики и дизайнеры могут сказать: «В темной теме примени зеленый фон 100». Дополнительные условные классы позволяют нам добавлять границы, менять фон или цвет текста в темной теме. Стив Шогер написал отличный твит, демонстрирующий настройки, которые иногда требуются для темной темы. Я черпал вдохновение у Tailwind.

Документирование

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

Добавление цветов в Stack Overflow

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

Поскольку большинство наших интерфейсов, созданных после 2018 года, используют Stacks, они получают темную тему и адаптивные макеты бесплатно.

Site chrome

Во-первых, мне нужно было сделать изменения, не нарушая стандартный режим работы Stack Overflow. Эти задачи в основном сводились к замене статических переменных Less на их эквиваленты CSS-переменных по всему сайту. Сначала я применил background-color: var(--white) к фону сайта, заменив background-color: @white. Затем я сделал тоже самое для цветов шрифта. Это означало удаление большого количества CSS-переменных, поскольку мы часто переопределяли цвета шрифта на дочерних элементах, когда могли просто наследовать их от родительского элемента.

Мотивация сотрудников

После этого, я опирался на разработчиков Адама Лира и Ника Крейвера, чтобы предоставить метод передачи превью темной темы сотрудникам Stack Overflow. Это позволило бы нашим сотрудникам переключиться на недоделанную темную тему, и увидеть, сколько работы осталось. Я надеялся таким образом мотивировать их помочь исправить оставшуюся часть нашего сайта. Это позволило бы мне исправить самую большую проблему сайта – существующую кодовую базу.

Кнопки

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

Это стало наиболее очевидно, когда дело дошло до кнопок. За эти годы мы создали различные виды кнопок. Это обстоятельство было неприятным, поскольку мы стремились использовать для стилизации сам элемент кнопки. Это означает, что любая button или input type="button" на сайте по умолчанию получит специфическое стилевое оформление из устаревшего набора стилей.

Это привело к значительному рефакторингу, который все еще продолжается. Мы продолжаем на уровне элемента удалять в CSS ссылки button, заменяя их эквивалентами из Stacks. Например, сотни input type="submit" нужно заменить на . Мы часто связывали интерактивность JavaScript с этими визуальными селекторами. Если мы меняли визуальные классы, это часто нарушало действие кнопки. Для тысячи кнопок мне нужно было сначала добавить специфичные для js классы, соединить их, а затем убрать старые визуальные элементы.

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

Заголовок сайта

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

Светлая строка заголовка

Темная строка заголовка

Тематическая строка заголовка

Для светлой строки заголовка, которую мы добавили в Stack Overflow, нужно было найти решение, чтобы измерить, был ли наш цвет CSS-переменной или статическим шестнадцатеричным значением. Если бы это была CSS-переменная, мы бы полностью пропустили преобразования Less, создав заголовок, который бы менял цвета в зависимости от того, включена ли темная тема. Если вместо этого вы используете статическую переменную Less, он будет измерять этот цвет для светлой или темной темы и создавать соответствующий заголовок.

Наш подход в итоге выглядел так:

& when ( iscolor(@theme-topbar-background-color) ) {
     @theme-topbar-style: if(luma(@theme-topbar-background-color) >= 50%, light, dark);
 }
 & when not ( iscolor(@theme-topbar-background-color) ) {
     @theme-topbar-style: automatic;
 }
Увійти у повноекранний режим Вихід із повноекранного режиму

Затем я построю заголовок соответствующим образом на основе automatic, light, или dark.

Теги

Не добавляйте макет в свой компонент при его проектировании. Другими словами, ваш контекст должен определять, сколько места между ними. Не фиксируйте его в своем компоненте. Во время ранних итераций Stack Overflow было решено, что к нашему компоненту post-tag будут применены внешние поля. Как и наши кнопки, теги сталкивались с той же проблемой JS-таргетинга. Ситуацию усложняло то, что большинство тегов были сгенерированы с использованием одного вспомогательного метода в нашем приложении.

Рефакторинг тегов означал бы замену post-tag для нашего нового компонента s-tag, учитывающего тему. Мне также нужно было бы реорганизовать наш JS, чтобы при необходимости добавить js-tag. Мне также нужно изменить метод генерации тегов, чтобы он принимал произвольные классы макетов, поскольку в определенных контекстах мы можем захотеть обернуть наши теги в гибкий макет, а не полагаться на предварительно добавленные поля.

Стиль поста

Большая часть Stack Overflow создается постами пользователей. Эти посты отображают markdown в качестве исходного тела вопроса, а также ответов и комментариев. Во время запуска Stack Overflow Markdown был относительно новым.

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

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

Стиль кода

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

Результаты

Бета-версия темной темы впервые появилась 30 марта 2020 года

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

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

Всерьез работа над темной темой началась в июле 2019 года с предварительного pull request. До этого в апреле 2019 года вы могли видеть публичное обсуждение того, что может потребоваться для создания темной темы. После, по крайней мере, 60 последующих pull requests, бета-версия темной темы была представлена 30 марта 2020 года.

Большое спасибо Adam Lear, Des Darilek, Nick Craver, Kevin Montrose, Brian Nickel, Catija, Ben Popper, Joy Liuzzo, Sara Chipps, Kristina Lustig, Jon Chan и Ben Kelly.


Перевод статьи stackoverflow.blog

Топ коментарі (0)