Я посмотрел существующие 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

