Начнём сразу с результата — флаг из двух полос, нарисованный одним правилом:

.flag--ukraine {
  aspect-ratio: 3 / 2;
  background: linear-gradient(#0057b7 50%, #ffd700 50%);
}

Никаких картинок и вложенных блоков: синяя половина и жёлтая половина — это один градиент. Разберёмся, почему он не плавный, а с чёткой границей.

Градиент — это картинка

Первое, что стоит запомнить: linear-gradient() возвращает не цвет, а изображение. Браузер рисует его на лету, но для CSS это то же самое, что url(photo.jpg).

Отсюда частая ошибка новичков:

/* не сработает: background-color принимает только цвет */
.card {
  background-color: linear-gradient(#0057b7, #ffd700);
}

/* сработает: градиент — это фоновое изображение */
.card {
  background-image: linear-gradient(#0057b7, #ffd700);
}

/* или шорткат background, как во всех примерах мануала */
.card {
  background: linear-gradient(#0057b7, #ffd700);
}

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

Заготовка для флагов

Все флаги в мануале строятся на одном базовом классе. Флаг ведёт себя почти как картинка: стоит в строке текста и растёт вместе со шрифтом.

.flag {
  display: inline-grid;  /* стоит в строке, как <img> */
  height: 1em;           /* высота = размер шрифта */
  vertical-align: top;   /* ровнее встаёт рядом с текстом */
  position: relative;    /* опора для ::before/::after в главе 7 */
  overflow: hidden;      /* всё, что вылезло, обрезаем */
}

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

Внутри строки текста используем <span>, а не <div>: блочный элемент внутри абзаца — невалидная разметка.

<p>Финал разыграют
  <span class="flag flag--ukraine"></span> Украина и
  <span class="flag flag--lithuania"></span> Литва.
</p>

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

Цветовые стопы

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

  • Позиций нет совсем — цвета распределяются равномерно, а переход занимает всю высоту.
  • Позиции есть — цвет «чистый» до своей позиции, а между двумя стопами идёт плавное смешивание.
  • Две позиции совпали — на смешивание не осталось места, получается жёсткая граница.
/* переход на всю высоту */
.box--smooth { background: linear-gradient(#0057b7, #ffd700); }

/* до 40% синий, с 60% жёлтый, между ними — переход */
.box--zone { background: linear-gradient(#0057b7 40%, #ffd700 60%); }

/* стопы в одной точке — переход нулевой ширины */
.box--hard { background: linear-gradient(#0057b7 50%, #ffd700 50%); }

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

Полосы: два значения у одного цвета

У цвета может быть сразу две позиции — где он начинается и где заканчивается. Так удобно описывать полосы:

.flag--lithuania {
  aspect-ratio: 5 / 3;
  background: linear-gradient(
    #fdb913  0%     33.33%,
    #006a44 33.33%  66.67%,
    #c1272d 66.67% 100%
  );
}

Запись длинная, но читается как таблица: жёлтый от 0 до трети, зелёный от трети до двух третей, красный до конца.

Теперь сократим её по двум правилам:

  1. Первый цвет и так начинается с 0, а последний и так заканчивается на 100%, поэтому эти позиции можно не писать.
  2. Если позиция стопа меньше предыдущей, браузер подтягивает её до предыдущей. Значит, вместо точного начала полосы можно поставить 0 — граница всё равно окажется там, где кончился прошлый цвет.
.flag--lithuania {
  aspect-ratio: 5 / 3;
  background: linear-gradient(#fdb913 33.33%, #006a44 0 66.67%, #c1272d 0);
}

Этот приём с 0 встретится во всех следующих главах. Читать его стоит так: «новый цвет начинается сразу там, где кончился предыдущий».

Поддержка браузерами: две позиции у одного цвета
chrome
Chrome
71
firefox
Firefox
64
edge
Edge
79
safari
Safari
12.1
opera
Opera
58

Подсказка перехода

Между двумя цветами можно поставить одинокое значение без цвета — подсказку перехода (transition hint). Она говорит, в какой точке смесь должна быть ровно пополам:

/* середина смеси — на 50%, как обычно */
.box--plain { background: linear-gradient(#7048e8, #ffd43b); }

/* середина смеси сдвинута к 20%: жёлтый «захватывает» больше места */
.box--hint { background: linear-gradient(#7048e8, 20%, #ffd43b); }

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

Ещё одна настройка плавных градиентов — цветовое пространство, в котором браузер смешивает цвета (linear-gradient(in oklch, …)). Она убирает серую «грязь» посередине между яркими цветами; подробный разбор с примерами — в статье про OKLCH.

Что запомнить

  • Градиент — это изображение: его кладут в background или background-image, но не в background-color.
  • Стопы в одной точке дают жёсткую границу.
  • 0 в начале полосы означает «сразу после предыдущего цвета».
  • Пустому элементу нужны размеры — у нас это высота плюс aspect-ratio.