Хватит использовать библиотеки для рейтингов. Я сделал компонент звездочного рейтинга
только на CSS с поддержкой половинок звезд всего в 60 строк. Без JavaScript. Полностью доступный. С плавным hover.
Я посмотрел существующие pure-CSS решения и почти везде одни и те же проблемы.
Либо нет поддержки половинок, либо завязка на FontAwesome, либо дерганый и нестабильный hover.
В итоге я сделал свое решение, используя только radio input’ы, label’ы и SVG-маски.
Ключевая идея упирается в ограничение CSS:
он умеет выбирать только элементы, идущие
после текущего (через ~).
А в рейтинге звезд нужно подсвечивать звезды
до той, на которую навели курсор.
Решение простое: переворачиваем DOM и визуально отражаем его через
flex-direction: row-reverse.
.star-rating {
display: inline-flex;
flex-direction: row-reverse;
justify-content: flex-end;
}Порядок в DOM: 5★ → 0.5★
Визуальный порядок: 0.5★ → 5★
Теперь
~ выбирает визуально предыдущие звезды.
Для половинок я разделил каждую звезду на два
<label> — левую и правую половину.
Каждый label использует SVG-маску половинки звезды.
nth-of-type(odd) — правая половина
nth-of-type(even) — левая половина
Почему маска, а не
background-image?
У background-image нельзя динамически менять цвет заливки SVG.
А mask работает как трафарет — сквозь него просто просвечивает
background-color.
В итоге hover — это просто смена цвета.
/* Подсветка при наведении */
label:hover,
label:hover ~ label {
background-color: goldenrod;
}
/* Подсветка выбранного */
input:checked ~ label {
background-color: gold;
}
Простые селекторы. Никаких JS-обработчиков.
Отступы между звездами ломают UX hover’а — появляются «мертвые зоны», где ничего не подсвечивается.
Фикс такой: расширяем
ширину label, но оставляем
mask-size прежним.
Зазор виден визуально, но зона hover остается непрерывной.
Radio-кнопки визуально скрыты, но остаются в DOM.
Скринридеры видят:
* нормальные radio input’ы
* label’ы с aria-label вроде
3 1/2 stars* полноценную навигацию с клавиатуры
CSS-only — это не компромисс по доступности.
@WebDev_Plus