Стояла задача добавить стар-рейтинг к форме комментариев для шаблона.

Это должны быть обычные 5 звездочек, при наведении на которые выделяются все звездочки от начала до той, на которую навели и при выборе (клике) такое состояние сохраняется. Также, конечно, нужно обеспечить передачу значения указанного рейтинга при отправке формы.

Решение делал не для конечного проекта, а для шаблона. Поэтому нужно было сделать звездочки максимально гибким для дальнейшей кастомизации. То есть изменения цвета, размера звездочек должно быть максимально легким. Под такую конфигурацию использование спрайта изображений не подходило, поэтому решил использовать шрифтовые иконки. Выбор пал на сервис Font Awesome. Там есть звездочки с названием fa-star-o — звездочка по умолчанию и fa-star — звездочка активная (при наведении и выборе).

Дальше решил подумать, как можно реализовать такую задача минимальными ресурсами, в идеале без использования javascript. В итоге все получилось и, как по мне, такое решение оптимальное для подобной задачи.

Кому лень читать дальше, можете сразу посмотреть результат тут — codepen.

HTML-разметка


Общая идея состоит в том, что мы выводим рейтинг обычными радиокнопками, что бы сохранить передачу данные через форму. Дальше прячем радиокнопки с помощью CSS, а выделять их будем с помощью клика по соседних лейблах, которые ссылаются на радиокнопку атрибутом for. Сами же лейблы мы выводим в виде иконок с сервиса Font Awesome.

В итоге HTML-разметка следующая:

<div class="star-rating">
      <div class="star-rating__wrap">
        <input class="star-rating__input" id="star-rating-5" type="radio" name="rating" value="5">
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-5" title="5 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-4" type="radio" name="rating" value="4">
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-4" title="4 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-3" type="radio" name="rating" value="3">
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-3" title="3 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-2" type="radio" name="rating" value="2">
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-2" title="2 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-1" type="radio" name="rating" value="1">
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-1" title="1 out of 5 stars"></label>
      </div>
</div>

Конечно, не забываем подключить шрифт Font Awesome в начале.

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

Очень важно сохранять порядок следования элементов input и label, при чем не помещать никаких вложенных элементов внутрь.Такая зависимость от html-разметки негативная, но это та жертва которую я посчитал уместной.

Также очень важно выводить радиокнопки в обратном порядке от 5 до 1.

CSS-стили


Первое, что нужно сделать — это спрятать радиокнопки. В результате у нас остаются только звездочки при нажатия на которые выделяется нужный радиобокс.

.star-rating__input{
display: none;
}

Второе — при наведении иконка должна изменятся на активную, при чем измениться должна не только текущая иконка, а и все иконки перед ней!

.star-rating__ico:hover:before,
.star-rating__ico:hover ~ .b-star-rating__ico:before,
{
	content: "\f005";
}

content: "\f005"; — это код активной иконки стар-рейтинга в шрифте Font Awesome. Иконки в этом шрифте вставляются через псевдоэлемент ::before

Третье — при клике на иконку состояние наведения должно сохраниться, то-есть активными должны быть текущая и соседние звездочки.

Добавляем к этому же правилу еще один селектор:

.star-rating__input:checked ~ .star-rating__ico:before


В результате главные стили, которые делают основную работу следующие:

.star-rating__input{
	display: none;
}
.star-rating__ico:hover:before,
.star-rating__ico:hover ~ .star-rating__ico:before,
.star-rating__input:checked ~ .star-rating__ico:before
{
	content: "\f005";
}

Дальше нужно перевернуть звездочки в другую сторону, так как сестринский селектор выбирает соседей по направлению текста. По умолчанию слева-направо, а нам нужно наоборот.

Для решения этой задачи есть два способа: изменить направления текста для элемента star-rating указав direction: rtl или сделать элемент плавающим по правой стороне. Мне больше по душе второй вариант. Кроме этого сделав элементы внутри .star-rating плавающими мы уберем отступы между звездочками из-за которых пропадает наведение

В общем, дальше уже все обычно. Еще раз ссылка на результат codepen.

В результате у нас полноценный стар-рейтинг со шрифтовыми иконками, написанный только на HTML+СSS в котором легко изменять размеры и цвет звездочек.

Комментарии (20)


  1. jemali_m
    16.07.2015 20:42
    +2

    Неплохо конечно же, но вы просто слегка изменили решение от Криса Койера на который ссылается сам автор Font Awesome на этой странице.

    А вот что касается отдельного подключения целой таблицы стилей со шрифтом Font Awesome, то это реально громоздко. можно было просто обойтись одной или двумя иконками звездочек.

    Что-то вроде этого:

    .css
    .star-rating__ico:hover:before,
    .star-rating__ico:hover ~ .b-star-rating__ico:before, {
      content: "";
      background-image: url(data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%20id%3D%22imgView%22%20x%3D%220px%22%20y%3D%220px%22%20width%3D%22256px%22%20height%3D%22255px%22%20viewBox%3D%220%200%20126.729%20126.73%22%20style%3D%22display%3A%20block%3B%22%20xml%3Aspace%3D%22preserve%22%20class%3D%22detail%20convertSvgInline%20replaced-svg%22%20data-id%3D%2256786%22%20data-kw%3D%22favourites7%22%20fill%3D%22%23FF9800%22%3E%3Cg%3E%3Cpath%20d%3D%22M121.215%2C44.212l-34.899-3.3c-2.2-0.2-4.101-1.6-5-3.7l-12.5-30.3c-2-5-9.101-5-11.101%2C0l-12.4%2C30.3%20%20%20c-0.8%2C2.1-2.8%2C3.5-5%2C3.7l-34.9%2C3.3c-5.2%2C0.5-7.3%2C7-3.4%2C10.5l26.3%2C23.1c1.7%2C1.5%2C2.4%2C3.7%2C1.9%2C5.9l-7.9%2C32.399%20%20%20c-1.2%2C5.101%2C4.3%2C9.3%2C8.9%2C6.601l29.1-17.101c1.9-1.1%2C4.2-1.1%2C6.1%2C0l29.101%2C17.101c4.6%2C2.699%2C10.1-1.4%2C8.899-6.601l-7.8-32.399%20%20%20c-0.5-2.2%2C0.2-4.4%2C1.9-5.9l26.3-23.1C128.615%2C51.212%2C126.415%2C44.712%2C121.215%2C44.212z%22%20style%3D%22%22%20fill%3D%22%22%3E%3C%2Fpath%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E);
      width: 20px;
      height: 20px;
      display: block;
      background-size: cover;
    }
    


    1. KaLGaN
      16.07.2015 20:56
      +2

      Проще использовать свой шрифт, сделанный на сервисах типа fontello.com

      А вообще, автор поста не открыл Америки. Решение известное и довольно прикольное.


    1. Kepler-22b Автор
      16.07.2015 23:02
      -1

      Спасибо за ссылки, решение на Font Awesom не видел. В отрыве от контекста для такой задачи грузить весь Font Awesom, конечно, накладно. Но как я замечаю эта библиотека шрифтов очень часто итак подключена на многих проектах. В Криса Койера не нравиться использование direction rtl, мне кажется с float лучше. Кроме того я максимально изолировал блок рейтинга, что-бы просто скопипастить код и вставить в любое место на сайте.


      1. jemali_m
        16.07.2015 23:26

        Вообще, само решение Койера уже давно морально устарело, и реализация через direction rtl является для многих спорным вариантом.


      1. Ohar
        17.07.2015 09:53

        Нет никакого «всего Font Awesome».
        Вы выбираете из него нужные глифы и скачиваете их. Я обычно ставлю 3–10 глоифов на проект, больше не пригождается.


  1. Aiki
    16.07.2015 21:34
    +1

    А зачем label-ы? И hover-ы можно обыграть интереснее: codepen.


    1. Serator
      16.07.2015 23:04
      +1

      Псевдо-элементы на элементах с заменяемым содержимым противоречат спецификации и то, что это поддерживает Webkit / Blink вовсе не означает, что так всегда и будет.

      code.google.com/p/chromium/issues/detail?id=480891
      bugzilla.mozilla.org/show_bug.cgi?id=1157575


      1. Kepler-22b Автор
        16.07.2015 23:22
        +1

        Да, согласен. Странно, как такое решение работает. Псевдоэлементы before и after нельзя добавлять к одиночным тегам, так как в них нельзя ничего вложить. Хром как-то осилил, Firefox и IE10 в ауте.


        1. Serator
          16.07.2015 23:35
          +1

          Если интересно, то вот тест возможности использования псевдо-элементов в различных элементах: red-team-design.com/wp-content/uploads/2012/06/generated-content-on-replaced-elements-test.html.


          1. Kepler-22b Автор
            16.07.2015 23:40

            Спасибо! Посмотрел исходник в хроме, офигел. В DOM браузер открыл input, вставил туда псевдоэлемент и закрыл — prntscr.com/7tis4r Это жесть какая-то. Не знаю, что именно меня тревожит, но это уже слишком.


          1. Ohar
            17.07.2015 10:01
            +1

            Спасибо, очень интересно.
            Не знал, что Blink настолько сошёл с ума.

            <input type="button"> — нет псевдоэлемента.
            <input type="checkbox"> — есть псевдоэлемент.
            

            «Где логика? Где разум?» © известный анекдот.


        1. TNK
          20.07.2015 14:23

          К одиночным можно, нельзя к заменяемым (replaced). Факт 11 отсюда: www.sitepoint.com/12-little-known-css-facts-the-sequel


      1. Aiki
        16.07.2015 23:26
        -1

        Видимо создателям спецификации ничего не говорят такие вещи, как AJAX, DHTML, contenteditable в конце концов. В современном вебе у любого элемента может замениться содержимое, у некоторых это происходит чаше, чем у иного input-а. По этой логике следует отказаться от псевдоэлементов вообще.


        1. Kepler-22b Автор
          16.07.2015 23:32

          Тут дело даже не в спецификации, а в логике. Суть псевдоэлементов в том, что они добавляют виртуальный элемент первым или последним ребенком. В одиночного элемента нету понятий закрывающий и открывающий тег и контент внутри, как, в принципе, там может оказаться другой элемент?


  1. max_rip
    17.07.2015 03:01

    Ну не правильно это как-то считать с конца)
    Лучше как положено с 1 до 5 codepen.io/anon/pen/mJjEMj
    Конечно звездочки немного прыгают, но это скорее всего из-за самого шрифта. Если их подогнать под целые значения и сделать свой шрифт, то все должно стать супер)


  1. savostin
    17.07.2015 08:03
    +2

    А зачем FontAwesome, когда есть ? и ??


    1. Ohar
      17.07.2015 10:08

      К сожалению, они довольно криво рендерятся разными браузерными движками.


      1. Ohar
        20.07.2015 18:53

        Ну или не подходят по дизайну.


  1. cmdr
    17.07.2015 09:41

    Как-то странно, что если одна из звезд чекнута, то ховер срабатывает только на тех, что после нее, а предыдущие как будто дизейблятся. Не думаю, что это ожидаемое поведение.


    1. Kudja
      17.07.2015 12:34

      В этом случае иммхо лучше иметь состояния с разными цветами на чекнутый и на ховер