Для некоторых веб-сайтов и платформ в интернете важно отображать оценку материала пользователями в виде звёздного рейтинга. Недавно мне довелось реализовать для одного проекта компонент звёздного рейтинга со следующими требованиями:
- Производительность (без использования картинок)
- Адаптивность под разный размер
- Доступность
- Частичное заполнение звёзд (например, 3.5 или 3.2)
- Легкая поддержка с помощью CSS
Я решил использовать SVG и не пожалел об этом. В данной статье будет рассмотрен данный способ реализации.
Вступление
Прежде чем мы приступим, я бы хотел продемонстрировать примеры ситуаций, в которых данный компонент должен корректно работать.

Основное внимание будет сосредоточено на создании звезды, для которой можно задать заливку, контур, а также изменить размер и заполнить лишь частично.
Базовая разметка
Во-первых, нам понадобится SVG-код изображения звезды, который можно будет использовать в браузере.
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" /> </svg>
В браузере данный код отрисует чёрную звезду с шириной и высотой, равными 32px.
Доступность
Помните, что для пользователей скринридеров в атрибуте aria-label
нужно будет представить рейтинг не в виде изображения, а в виде текста.
<p aria-label="Rating is 4.5 out of 5"> <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" /> </svg> </p>
Как использовать SVG повторно
Мы можем либо просто пять раз скопировать приведённую выше разметку, либо сохранить SVG-код рисования фигуры «path» в виде шаблона и использовать повторно без дублирования разметки. Давайте сделаем это.
Сначала нужно создать SVG с нулевой шириной и высотой, чтобы он не занимал место
<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Content --> </svg>
В этом SVG в теге <symbol>
нужно задать SVG-код рисования фигуры «path», который нарисует звезду.
В элементе <symbol>
, кроме кода, который отрисует иконку звезды, важно добавить атрибут id
, чтобы на него можно было сослаться позже
<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg"> <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="star"> <path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" /> </symbol> </svg>
После всех этих действий мы сможем переиспользовать символ звезды с помощью элемента <use>
. Идея заключается в том, чтобы в атрибуте xlink:href
ссылаться на id
созданного символа.
<p class="c-rate"> <svg class="c-icon" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use xlink:href="#star"></use> </svg> </p>
Стилизация звезды
Теперь, когда мы получили список звёзд, давайте рассмотрим CSS-стилизацию. Я определил для звезды жёлтый и серый цвета.
<p class="c-rate"> <svg class="c-icon active" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon active" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon active" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon active" width="32" height="32"> <use xlink:href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use xlink:href="#star"></use> </svg> </p>
.c-icon { --star-active: #fece3c; --star-inactive: #6c6962; fill: var(--star-inactive); } .c-icon.active { fill: var(--star-active); }
Частичное заполнение
Использование SVG даёт нам две отличных возможности. Первая — использование SVG-масок, вторая — использование SVG-градиентов.
Половина звезды с помощью SVG-маски
Суть использования масок заключается в использовании тега <mask>
, задающего область, внутри которой фигура остаётся видимой, а за пределами — обрезается.

На рисунке выше продемонстрировано применение описанного эффекта, при котором видимой остаётся только часть звезды.
Чтобы реализовать это с помощью SVG, нужно сделать следующее:
- Создать SVG-шаблон, который можно повторно использовать
- Добавить элемент
<mask>
в виде прямоугольник, расположенного на осиx
, и спозиционированном на50%
- Применить маску к фигуре звезды
<!-- Переиспользуемый SVG-шаблон --> <svg width="0" height="0" viewBox="0 0 32 32"> <defs> <!-- Маска, которая будет закрывать часть звезды --> <mask id="half"> <rect x="50%" y="0" width="32" height="32" fill="white" /> </mask> <!-- Фигура звезды --> <symbol id="star" viewBox="0 0 32 32"> <path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" /> </symbol> </defs> </svg> <!-- Пример применения звезды с наложением маски --> <svg class="c-icon" width="32" height="32" viewBox="0 0 32 32"> <use xlink:href="#star" mask="url(#half)"/> </svg>
В результате получится половина звезды, как на предыдущем изображении.
Далее встаёт вопрос о том, как мы можем с помощью маски отобразить прозрачную звезду? Благодаря SVG, мы можем поместить в <mask>
несколько элементов.
После добавления ещё одного элемента, SVG-маска <mask>
будет выглядеть следующим образом:
<mask id="half"> <rect x="0" y="0" width="32" height="32" fill="white" /> <rect x="50%" y="0" width="32" height="32" fill="black" /> </mask>
В маске белый элемент представляет то, что мы хотим показать, а чёрный — то, что хотим скрыть. Объединив их, можно создать эффект вырезанной части фигуры.
При использовании более яркого цвета, чем просто чёрный, мы получим эффект прозрачности. Это значит, что правая часть звезды, которая на данный момент полностью скрыта, будет иметь светлый оттенок того же цвета, что и звезда.
<mask id="half"> <rect x="0" y="0" width="32" height="32" fill="white" /> <rect x="50%" y="0" width="32" height="32" fill="grey" /> </mask>
Давайте подведём итог с полной разметкой
<style> .c-star { width: var(--size, 1em); height: var(--size, 1em); fill: #e74f56; stroke: grey; } .c-star.active { fill: #e74f56; } .c-star.noactive { fill: #fff3f4; } </style> <div style="position: absolute;"> <svg style="width: 0; height: 0;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <defs> <linearGradient id="half" x1="0" x2="100%" y1="0" y2="0"> <stop offset="55%" stop-color="#e74f56"></stop> <stop offset="55%" stop-color="#fff3f4"></stop> </linearGradient> <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="star"> <path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" /> </symbol> </defs> </svg> </div> <p class="star-rating" aria-label="4.5 stars out of 5"> <svg class="c-star active" width="32" height="32" viewBox="0 0 32 32"> <use xlink:href="#star"></use> </svg> <svg class="c-star active" width="32" height="32" viewBox="0 0 32 32"> <use xlink:href="#star"></use> </svg> <svg class="c-star active" width="32" height="32" viewBox="0 0 32 32"> <use xlink:href="#star"></use> </svg> <svg class="c-star active" width="32" height="32" viewBox="0 0 32 32"> <use xlink:href="#star" fill="url(#half)"></use> </svg> <svg class="c-star noactive" width="32" height="32" viewBox="0 0 32 32"> <use xlink:href="#star"></use> </svg> </p>
Резельтат:

Статья взята с https://habr.com/