Наклонная жёсткая граница в градиенте на многих экранах выглядит рвано, «лесенкой». Слева — как получается по умолчанию, справа — с маленькой поправкой:
/* граница-«лесенка» */
.box--hard {
background: linear-gradient(30deg, #e03131 50%, #1971c2 50%);
}
/* граница сглажена: переход шириной 1px */
.box--soft {
background: linear-gradient(30deg, #e03131 calc(50% - 0.5px), #1971c2 calc(50% + 0.5px));
}
Откуда берётся лесенка
У векторной фигуры (SVG или clip-path) браузер сглаживает край: пиксели на границе получают промежуточный цвет. Жёсткую границу в градиенте он так не обрабатывает — каждый пиксель окрашивается либо в один цвет, либо в другой, и на наклонной линии видны ступеньки.
Лечение — дать границе крошечный плавный переход вручную: развести два стопа на 1px (по полпикселя в каждую сторону). Глазу это незаметно, а ступеньки пропадают. Хватит и сдвига одного стопа: #e03131 calc(50% - 1px), #1971c2 50%.
Горизонтальным и вертикальным границам поправка не нужна: там пиксели совпадают с линией.
Три элемента вместо одного
«Флаг из одного элемента» — немного лукавая формулировка. У каждого элемента, кроме пустых вроде <img> и <input>, есть два псевдоэлемента — ::before и ::after. Их можно стилизовать отдельно, и они дают то, чего нет у фона:
- поворот — фоновый слой нельзя повернуть, а псевдоэлемент можно через rotate;
- сложную форму — border-radius, clip-path, маски;
- гладкий край — обрезанная фигура сглаживается браузером, в отличие от границы в градиенте.
Два обязательных условия: свойство content (хотя бы пустая строка, иначе псевдоэлемент не появится) и position: absolute относительно флага. Для этого в заготовке из первой главы и стоит position: relative.
Зубцы через clip-path
У флага Бахрейна такой же зубчатый край, как у Катара из главы 5, но зубцов пять. Вместо плитки из конических градиентов возьмём белый ::before на весь флаг и обрежем его многоугольником:
.flag--bahrain {
aspect-ratio: 5 / 3;
background: #ce1126;
}
.flag--bahrain::before {
content: "";
position: absolute;
inset: 0;
background: #fff;
clip-path: polygon(
0 0, 25% 0,
40% 10%, 25% 20%, 40% 30%, 25% 40%, 40% 50%,
25% 60%, 40% 70%, 25% 80%, 40% 90%, 25% 100%,
0 100%
);
}
Точки многоугольника идут по контуру белой области: верхний левый угол, затем зигзаг между 25% и 40% ширины, затем нижний левый угол. Края зубцов получаются гладкими без всяких поправок. Тот же приём подходит для треугольников у Чехии и Багам: треугольник из clip-path всегда ровнее конического. Подробно о функциях polygon(), circle() и других — в статье про clip-path.
Звёзды через ::before и ::after
Флаг Панамы — четыре четверти (конический градиент) и две звезды разного цвета. Звёзды — по одной на каждый псевдоэлемент:
.flag--panama {
--red: #da121a;
--blue: #072357;
aspect-ratio: 3 / 2;
background: conic-gradient(var(--red) 25%, #fff 0 50%, var(--blue) 0 75%, #fff 0);
}
.flag--panama::before,
.flag--panama::after {
content: "";
position: absolute;
top: 25%;
left: 25%;
width: 18%;
aspect-ratio: 1;
translate: -50% -50%;
background: var(--blue);
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
.flag--panama::after {
top: 75%;
left: 75%;
background: var(--red);
}
Общие свойства звёзд описаны один раз для обоих псевдоэлементов, а ::after переопределяет только позицию и цвет. translate: -50% -50% ставит центр звезды точно в центр своей четверти.
Кто-то считает clip-path в CSS-рисунках «читерством» — звезду можно собрать и из конических градиентов. Но в рабочем коде важнее читаемость, а clip-path и маски пригодятся далеко за пределами флагов. Другие фигуры на чистом CSS — в статье о CSS-фигурах.
Где граница разумного
Гербы, эмблемы, надписи и мелкие детали на CSS рисовать можно, но не нужно: код раздувается, а результат хуже, чем у SVG-файла. Разумная граница — полосы, кресты, круги, треугольники и простые фигуры. Всё сложнее — в SVG.
Флаг должен быть виден не только глазам
Пустой <span> с фоном скринридер просто пропустит: для него там ничего нет. Если флаг несёт смысл (страна команды, язык интерфейса), ему нужна текстовая альтернатива:
<span class="flag flag--finland" role="img" aria-label="Флаг Финляндии"></span>
role="img" говорит, что элемент — изображение, а aria-label — это его alt-текст. Если же рядом и так написано название страны, флаг декоративный: лучше скрыть его от скринридера через aria-hidden="true", чтобы название не прозвучало дважды.
Практика
Лучший способ закрепить градиенты — нарисовать несколько флагов самостоятельно. Список примерно по возрастанию сложности:
- Монако — две полосы.
- Эстония — три полосы.
- Объединённые Арабские Эмираты — полосы плюс вертикальная полоса у древка.
- Лаос — полосы разной ширины и круг.
- Исландия — крест с окантовкой.
- Доминиканская Республика (без герба) — крест и четыре цветных прямоугольника.
- Сент-Люсия — треугольники друг на друге.
Не бывает единственно верного кода для флага. Подойдёт любой набор градиентов, который даёт правильную картинку и читается без мучений.