Рейтинг со звездами на CSS

перейти к комментариям


Звездный рейтинг

Если вам понадобилось сделать механизм простановки оценок чему-либо (чаще всего при помощи «звездочек»), то для этого вовсе не обязательно применять JavaScript. Можно все сделать при помощи CSS и семантической разметки.

Первоисточник

На одном замечательном сайте есть целых две статьи про то, как такие рейтинги делать:

  1. Самое начало
  2. Вариант с выставленным рейтингом

Теперь я попытаюсь объяснить все это по-русски, добавив от себя некоторые улучшения (на мой взгляд).

Разметка

В исходном примере автор применяет простой ненумерованный список для создания рейтинга. Мне это показалось не совсем верным с точки зрения семантики: так как элементами списка являются цифры, то и список лучше применять нумерованный, вписав вместо цифр более понятные человеку термины типа «хорошо», «плохо» и т. д.

Почему вообще применяется список? Это очень удобно с точки зрения доступности (accessibility) — если агент не поддерживает CSS, то наш рейтинг предстанет простым списком ссылок без звездочек, но с возможностью голосования.

Кроме того, чтобы показать уже выбранное значение, применялся еще один элемент (неактивный), говорящий о том, какой рейтинг проставлен: <li class="current-rating">Currently 3.5/5 Stars.</li>. Мне кажется, что для подобных случаев уместнее использовать элемент DL — список определений.

W3C говорит нам:

Definition lists, created using the DL element, generally consist of a series of term/definition pairs (although definition lists may have other applications).

Это означает, что списки определений могут использоваться для пар термин/определение, а также иметь другие применения. То есть мы вполне можем использовать этот элемент, при этом «термином» будет текущий рейтинг, а его определением — список со звездами:

<dl class="star-rating">
  <dt>Рейтинг: 4 из 5 звезд</dt>
  <dd>
    <ol>
      <li><a href="#" class="star1">Ужасно</a></li>
      <li><a href="#" class="star2">Плохо</a></li>
      <li><a href="#" class="star3">Нормально</a></li>
      <li><a href="#" class="star4">Хорошо</a></li>
      <li><a href="#" class="star5">Отлично</a></li>
    </ol>
  </dd>
</dl>

Результат — ничего лишнего и необходимая функциональность.

Сами звезды

Звезды Теперь пришло время сделать сам рисунок звезд — открываете свой любимый Fireworks/Photoshop и рисуете примерно следующее:

Размер картинки в моем случае 20×60 пикселей, т. е. каждая звездочка имеет размер 20×20. Смысл в том, что необходимо изобразить картинку с тремя состояниями рейтинга (сверху-вниз):

  1. Пустое (рейтинг не проставлен)
  2. Звезда при выборе
  3. Состояние уже проставленного рейтинга

Изображение на все три состояния одно, что избавляет нас от необходимости догрузки отдельных картинок.

Оформление стилями

Стили буду объяснять по шагам:

Для начала уберем ненужные отступы у нашего списка, а также зададим его ширину и высоту (высота = 20, а ширина — 20×5 = 100). Важно указать правило position:relative, которое потом будет нужно для позиционирования элементов. Кроме того, на подложку мы положили нашу картинку со звездами (по умолчанию — пустая звезда, как если бы мы указали background-position:top):

dl.star-rating ol {
  margin: 0;
  padding: 0;
  list-style: none;
  width: 100px;
  height: 20px;
  position: relative;
  background: url(stars.png);
}

Теперь мы выстраиваем наши элементы списка в линию (float:left) и также убираем отступы:

dl.star-rating li {
  float: left;
  margin: 0;
  padding: 0;
}

Пришло время для ссылок: мы делаем их блочными элементами (чтобы задать ширину и высоту звездочек), прячем текст text-indent:-9999px, а также указываем абсолютное позиционирование и z-index (потом станет ясно зачем):

dl.star-rating li a {
  display: block;
  width: 20px;
  height: 20px;
  text-indent: -9999px;
  position: absolute;
  text-decoration: none;
  z-index: 10;
}

Теперь начинается самое важное — мы указываем правила для реакции на курсор. При его наведении, наша ссылка заполняется рисунком звездочки (второе состояние из-за указания center), а также отодвигается влево (к самому краю всего рейтинга). Делается это для того, чтобы активная ссылка (т. е. в состоянии hover) заполняла собой больше чем положенные ей по умолчанию 20 пикселей — сейчас увидим.

dl.star-rating li a:hover {
  background: url(stars.png) left center;
  left: 0;
  z-index: 2;
}

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

dl.star-rating a.star1 {
  left: 0;
}
  dl.star-rating a.star1:hover {
  width: 20px;
}
dl.star-rating a.star2 {
  left: 20px;
}
dl.star-rating a.star2:hover {
  width: 40px;
}
...

Остальные можно понять по аналогии: каждая следующая получает позиционирование, смещенное на 20 пикселей, а при наведении мышки — ширину, равную «значение»?20. Таким образом, каждая ссылка находится на «своем» месте в неактивном состоянии, а при hover’e — «отскакивает» влево, расширяясь при этом на заданную ширину.

Из-за указания z-index, наши звездочки позволяют «понижать» рейтинг, опускаясь ниже неактивных ссылок.

Результат можно увидеть здесь: Шаг 2.

Проставленный рейтинг

Чтобы показать уже проставленный рейтинг нам необходимо добавить некоторую разметку к списку (к четвертому пункту):

<dl class="star-rating">
  ...
      <li class="current" style="width:80px"><a href="#" class="star4">Хорошо</a></li>
  ...
</dl>

Избежать указания ширины похоже не удастся. Вычислить ее придется на серверной стороне, умножив количество баллов на ширину звезды — на 20 пикселей.

При этом совершенно не обязательно указывать круглое число. Вы можете проставить, скажем, 3.5 баллов — лишь укажите width:70px.

Кроме того, добавим немного стилей:

dl.star-rating li.current {
  background: url(stars.png) left bottom;
  height: 20px;
  z-index: 1;
}

Что даст нам «запомненное» состояние рейтинга. Результат.

Небольшой бонус

Чтобы сделать пользование рейтингом еще удобнее, мы можем отображать соответствующие надписи при смене рейтинга. Для этого нам понадобится добавить всего одно правило:

dl.star-rating ol>li a:hover {
  text-indent: 110px;
}

upd. последний код не работает в IE 5/6, поэтому мы его просто от него скрываем. Решить эту проблему можно при помощи обертки в дополнительные теги (а может и еще как-то), а мне этого не хочется... Поэтому пользователи IE просто не увидят поясняющих надписей (hint: вынесите их в аттрибут title у ссылок).

Самый финальный результат: Наш рейтинг.

upd2. в комментариях спросили про серверную сторону реализации рейтинга. Один из способов здесь.


Комментарии RSS для комментариев

  1. # Андрейка — 4421 дн. назад:

    Отлично! Как раз надо делать. Использую твое решение :) Спасибо.

  2. # SeLarin 4421 дн. назад:

    Спасибо. Очень интересно… При случае не премину воспользоваться ;)

  3. # dva — 4420 дн. назад:

    Спасибо.

    Последний пример ( http://eye.loveline.ru/example/stars/ ) сбоит в IE6 – под надписями множатся звездочки на всю длину текста.

  4. # Александр Шабуневич 4420 дн. назад:

    dva: точно не работает... последнее писал не проверяя в IE. Сейчас допишу про это

  5. # Sasha — 4409 дн. назад:

    Классно получилось!

  6. # Michael de`OZ 4407 дн. назад:

    А как это реализовать на серверной стороне?

  7. # Александр Шабуневич 4407 дн. назад:

    А как это реализовать на серверной стороне?

    Самой логичной была бы реализация на AJAX с возможностью просто кликнуть по ссылке при отключенном JS. А в ссылке указать путь на скрипт, например: vote.php?id=1&rate=3 с защитой от накруток внутри самого скрипта. Как-то так…

  8. # Vital — 4327 дн. назад:

    Прекольно, но в ИЕ дёргается...а с учётом того сколько пользователей под ИЕ...

  9. # Александр Шабуневич 4327 дн. назад:

    Прекольно, но в ИЕ дёргается...а с учётом того сколько пользователей под ИЕ...

    Как понять «дергается»? Проверял в IE 5/6 — не дергается. А оригинальный вариант тоже так себя ведет?

  10. # Vital — 4326 дн. назад:

    Так, очередной превед от ИЕ...
    Посмотрел в эмуляторе 98 и XP, действительно всё отлично работает, ничего не дёргается... а мой рабочий комп – w2k, IE6, при переводе курсора от одной звезды к другой на мгновение все звёзды становятся серыи, а потом зажигаются...дёргаются то бишь... частный случай в общем (наверное)...
    В любом случае для моей ситуации этот пример не подходит, т.к. по дизайну под звёздами цЫфры:

    * * * * * * *
    12 34 56 7

  11. # Александр Шабуневич 4326 дн. назад:

    В любом случае для моей ситуации этот пример не подходит, т.к. по дизайну под звёздами цЫфры:

    Цифры сделать не сложно — только придется ввести оборачивающий span. Или написать их вместо слов…

  12. # Vital — 4324 дн. назад:

    А вы попробуйте если «не сложно», при этом надо учесть что цифр 10 (от 1 до 10), каждая цифра должна адекватно стоять (ровно по центру под звездой) ну и конечно, всё это должно работать у всех (Opera, FF, IE)
    ;-)

  13. # Александр Шабуневич 4324 дн. назад:

    Попробовал =) Результат.

    Правда из-за странного глюка мозиллы, пришлось еще и слова с описаниями оценок обернуть в лишний div — в Опере и IE все работало и без него.

  14. # Vital — 4323 дн. назад:

    Красота :)

  15. # praca 4241 дн. назад:

    great article greets

  16. # Андрей 4141 дн. назад:

    Я полючил данную фитчу с php сктипту по типу vote все работает, только вот этот скипт отдельно статистику показывает... и приходиться рейтинг звезд менять в ручную...
    Можно ли как-то выципить цифры рейтинга из php и например при помощи java всунуть в рейтинг звезд, что бы автоматом менялись???

Что вы об этом думаете?


Клиент всегда прав? Нет CSS хакам?