Вот линейный градиент на CSS, идущий от чисто жёлтого до чисто синего цвета:


Заметили, что в центре он становится бледным и грязным?

Это явление Эрик Кеннеди назвал «мёртвой зоной серого». Если вы тщательно не выбираете цвета для своих градиентов, то в ваших градиентах на CSS часто возникает такая обесцвеченная часть посередине.

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

Как вычисляются градиенты


Задавались ли вы когда-нибудь вопросом, как работает алгоритм linear-gradient в CSS? Как он вычисляет конкретное значение цвета для каждого пикселя вдоль спектра?

Он вычисляет его, беря математическое среднее для каждого из трёх цветовых каналов: Red, Green и Blue.






[Прим. пер.: в оригинале статьи все изображения интерактивны.]

В цветовом пространстве RGB мы создаём цвета смешением трёх каналов: красного, зелёного и синего. Каждый канал имеет диапазон значений от 0 до 255.

Если мы увеличим до максимума значения всех трёх каналов — 255 / 255 / 255, то получим чисто белый цвет. А если установим каждый канал на 0, то получим чёрный, отсутствие всех цветов.

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


В показанном выше виджете градиента мы начали с чисто жёлтого цвета (255/255/0). При перемещении по градиенту мы начинаем примешивать синий (0/0/255). К тому моменту, как мы достигнем самой середины, мы уберём половину жёлтого и добавим половину синего.

Иными словами, все три канала сходятся к их среднему значению, 127,5. И в результате получается серый цвет.

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

Альтернативные цветовые модели


Существует множество разных способов задания цвета. Пока мы использовали только модель R/G/B. И, честно говоря, эта цветовая модель довольно отстойная.

Давайте поговорим о другой цветовой модели: HSL.

HSL расшифровывается как Hue / Saturation / Lightness (тон, насыщенность и светлота). Если вы пользовались селектором цветов, то, вероятно работали с этой цветовой моделью.

Пример:


Вот что означает каждое значение:

  • Hue (тон) управляет тем, каким будет пигмент, где находится цвет на шкале цветов.
  • Saturation (насыщенность) управляет тем, насколько ярок будет цвет.
  • Lightness (светлость) управляет тем, насколько светлым или тёмным будет цвет.

Лично мне такой способ кажется гораздо более интуитивным способом восприятя цветов.

Но вот что по-настоящему волшебно: что если вместо усреднения значений RGB в наших градиентах мы будем усреднять значения HSL?






Мёртвой зоны серого больше нет, потому что теперь мы смешиваем не значения R/G/B, а значения H/S/L.

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

Вот ещё один пример, на этот раз смешение цветов с разной насыщенностью и светлостью. Ниже для сравнения показаны цвета со стандартным RGB-смешением:







Достаточно наглядная разница, правда?

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

Согласно цветовой модели HSL, оба этих цвета имеют одинаковую «светлость»:


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

К счастью, существуют другие цветовые модели, учитывающие восприятие человека. Например, HCL, похожая на HSL, однако смоделированная с учётом зрения человека:






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

Используем знания на практике


У меня есть хорошие и плохие новости. Давайте начнём с плохих.

CSS не позволяет нам выбирать цветовую модель. используемую в вычислении градиентов. Мы не можем выбрать интерполяцию HSL для конкретного градиента, по крайней мере, пока. Насколько я знаю, CSS Images Level 4 даёт возможность указания «способа интерполирования цветов», но он поддерживается не всеми браузерами.

Однако есть и хорошие новости: исхитрившись, мы можем обойти эти ограничения.

Градиенты в CSS не привязаны только к двум крайним цветам. Можно передавать 3 цвета, или 10 цветов, или даже 100 цветов.

Сначала нам нужно вручную вычислить набор промежуточных цветов. Мы можем сделать это с помощью JavaScript, чтобы можно было использовать любую нужную цветовую модель (благодаря полезной библиотеке наподобие chroma.js):





Далее мы берём этот набор цветов и передаём каждое значение функции градиента CSS:

.box {
  background-image: linear-gradient(
    to right,
    #ffff00,
    #f8ea47,
    #f0d465,
    #f0d465,
    #e7bf7c,
    #ddaa8f,
    #d095a1,
    #c280b2,
    #b26cc2,
    #9d56d2,
    #8440e1,
    #6028f0,
    #0000ff
  )
}

(Здесь мы используем линейные градиенты, но тот же трюк работает с радиальными и коническими градиентами!)

Но постойте, разве движок CSS не использует RGB-интерполяцию для вычисления пространств между каждым из указанных цветов? Если мы не передаём сотни цветов, достаточные для каждого отдельного пикселя, то всё равно используем RGB-интерполяцию!

Да, это правда, но, к счастью, это не особо важно.

Когда два цвета очень схожи друг с другом, на самом деле не важно, какую цветовую модель мы используем. Градиент получится приблизительно одинаковым. Мы не получим сильно отличающееся «среднее» значение, как бы мы ни вычисляли это «среднее».

Например, вот градиент, в котором используются два очень схожих цвета:



Цвета настолько близки, что RGB-интерполяция никак не может их испортить.

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

Ну а теперь самое интересное. Давайте поговорим о том, как генерировать эти градиенты.

Знакомство с генератором градиентов


Я создал инструмент, позволяющий генерировать роскошные, красивые градиенты, которые можно использовать в CSS:


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

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

Генератор находится здесь: https://www.joshwcomeau.com/gradient-generator/

Предыдущие работы


На создание собственного генератора меня вдохновили эти два чудесных генератора градиентов:

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


  1. hungry_forester
    12.01.2022 13:56
    +8

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


  1. uburame
    12.01.2022 14:10
    +18

    Но ведь получились совершенно разные градиенты: в первом случае переход от цвета к цвету через серый, во втором - переход через промежуточные цвета, диктуемые моделью HSL.


    1. Zibx
      12.01.2022 15:35
      +2

      Дальше в статье есть переход через LAB, который кажется глазу очень естественным.


      1. uburame
        12.01.2022 17:34
        +4

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


      1. assembled
        12.01.2022 18:06
        +2

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


      1. aamonster
        12.01.2022 18:16
        +1

        Погодите. В Lab же тоже посередине между жёлтым и синим лежит серый, нет?
        И автор статьи принял по итогу совершенно правильное решение – воткнуть посередине такой цвет, чтобы градиент был не "точным", а "красивым". Единственное – мне казалось, что дизайнеры его для таких (достаточно редких) случаев обычно руками подбирают.


        1. Zibx
          15.01.2022 02:03

          Если хочется сделать хороший градиент, то переходить нужно через CIELAB. А если величайший, то отреверсить формулу перцептивной разницы цветов CIEDE2000 и гулять по полученному.

          Сейчас дополнительно погуглил и есть ещё такие пространства как CIECAM02 и IPT.



  1. alexboev
    12.01.2022 15:05
    +5

    Не могу не упомянуть, что у автора оригинальной статьи осенью вышел просто невероятный интерактивный курс по современному CSS. Вряд ли вы видели что-то подобное раньше. Крайне рекомендую!


    1. censor2005
      13.01.2022 08:14

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


      1. alexboev
        13.01.2022 09:38
        +3

        https://courses.joshwcomeau.com/css-for-js


        1. alexboev
          13.01.2022 10:52
          +1

          Для россиян у автора есть очень приличная региональная скидка, почти в половину стоимости. При покупке есть галка.


          1. sasha1024
            13.01.2022 15:37

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


            1. alexboev
              13.01.2022 15:56
              +1

              Вот.


              1. alexboev
                13.01.2022 16:02

                Курс недешевый. Но есть резон. Автор вложид в него просто нереальное количество труда, это не просто груда видео в ютубе или плюралсайте каком-нибудь. Во-первых, автор просто невероятно четко и ясно излагает мысли свои. Посмотрите ЛЮБУЮ его статью. Я купил курс, когда прочитал его статью про pixel perfect design. Чувствуется талант и опыт, и умение донести это до слушателя. Во-вторых, он всегда не просто красиво оформляет статьи, а еще и делает кучу отполированного интерактива для экспериментов прямо по ходу чтения! И тут целый курс такого контента! К примеру, в курсе есть интерактивные задачки в каждом топике для закрепления материала. Дается с десяток все усложняющихся задач, вы сразу на месте в интерактивном конструкторе их решаете, и вам поясняют точно, где и ПОЧЕМУ вы ошиблись. Например, так было очень легко понять border collapse. В-общем, я нигде ни в каком курсе не видел подобного. Я даже не поленился все эти комментарии тут написать, хотя никогда ничего особо не комментирую :)


                1. alexboev
                  13.01.2022 22:22

                  Вот так, например, выглядит игра про border collapse. Серый блок надо двигать внутри белого. Красный - внутри серого. Расставить надо их так, как, по-вашему, они должны отрисоваться по правилу. Если делаешь неправильно, автор показывает решение с объяснением:


              1. sasha1024
                13.01.2022 16:26

                Это на какой странице?


                1. alexboev
                  13.01.2022 16:35
                  +1

                  Прямо на домашней https://css-for-js.dev/, внизу. Прокручивается до этого места по кропке розовой Enrol now


                  1. sasha1024
                    13.01.2022 19:58

                    Всегда не любил такие скроллящиеся интерфейсы, но сейчас похоже моя нелюбовь достигла апеофоза. Реально — несколько раз был на этой странице, из любопытства искал именно эту штуку — и не находил (высота страницы 26.5 экранов, но очевидной структуры или оглавления у неё нету); всё, что находил, — пункт «Do you support Purchasing Power Parity (PPP) / regional licenses?» в FAQ внизу. Ну, Вам в любом случае спасибо.


                    1. alexboev
                      13.01.2022 21:39

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


  1. volaand
    12.01.2022 15:05

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


    1. vesper-bot
      12.01.2022 16:00

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


    1. aamonster
      12.01.2022 18:46

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


    1. Dzenbuddist
      13.01.2022 09:56

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

      Неделька работы и готово :)))


  1. BulldozerBSG
    12.01.2022 16:22
    +4

    Что не так с цветами на экране


    1. sasha1024
      13.01.2022 15:34

      Насколько я понимаю, на самом деле transfer characteristic — не совсем квадратный корень (или даже совсем не квадратный корень). Но как упрощение — сойдёт.


  1. iShrimp
    12.01.2022 17:03

    Берём и исправляем гамму, и получается линейный градиент здорового человека :)


  1. Kyushu
    13.01.2022 11:22

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


  1. Rukis
    13.01.2022 12:32
    +1

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