Верстка рейтингов
Дата публикации: 01.12.2009
Уже наверное встречал в сети блоки с оценкой чего либо (фильма, мобильного телефона, статьи и т.п.), что-то вроде этого:

Рано или поздно каждый кодер сталкивается с такой задачей. И решить ее можно по разному.
Показ рейтинга
Способ 1 — дедовский метод
Вырезаем две картинки: одна для пустого значения (в нашем случае это звездочка), другая для заполненного. Выводим на сайт пять картинок, сколько из них нужно пустых, а сколько заполненных определяет алгоритм программиста:
<div class="productRate"> <img src="path-to/full-star.png" alt="" width="31" height="28" /> <img src="path-to/full-star.png" alt="" width="31" height="28" /> <img src="path-to/full-star.png" alt="" width="31" height="28" /> <img src="path-to/empty-star.png" alt="" width="31" height="28" /> <img src="path-to/empty-star.png" alt="" width="31" height="28" /> </div>
Какие же тут недостатки?
- для небольшого блока потребовалась куча строк — не лучшим образом скажется на читаемости кода, поисковой и сео оптимизациях;
- потребуется две отдельные картинки — снова же скорость загрузки страницы, нагрузка на сервер;
- использование картинок (тег <img>) для оформления, соответственно написать что-то вразумительное в alt нет возможности, а google предупреждал, что лучше так не делать;
- программисту, который имеет готовое число рейтинга, все равно придется дополнительно думать и писать код для корректного вывода этого самого рейтинга на сайте.
И на мой взгляд самый большой недостаток — практически нереальность вывода рейтинга со значением не кратным 1/N, где N — к-во возможных оценок в рейтинге (в нашем примере 5). Например, попробуй при такой верстке вывести значение равное 64%. На сайте должно получится что-то вроде такого:

Способ 2 — достойный
Этот вариант решает все вышеперечисленные проблемы. Алгоритм для нашего примера:
- делаем контейнер, задаем ему фон с одной пустой звездой, которая размножается по оси x (background-repeat: repeat-x);
- в него вкладываем блок, с фоном полной звезды (и тут фон множиться по оси x). По умолчанию этот блок имеет длину (width) равную 0;
- в HTML коде, с помощью атрибута style, устанавливаем длину вложенного блока равную значения рейтинга.
<div class="productRate">
<div style="width: 64%"></div>
</div>
CSS:
.productRate {
background: url(path-to/empty-star.png);
width: 150px;
height: 32px;
}
.productRate div {
background: url(path-to/full-star.png);
width: 0;
height: 100%;
}
Разницу трудно не заметить. И поверь, программист тебе будет благодарен за такой код.
Заметка
Для уменьшения числа отдельных картинок тут смело можно применять технику спрайтов.
Показ рейтинга с возможностью голосования
Часто можно встретить сайты, где рейтинг не просто показан, а можно, кликнув по нему, поставить свою оценку. Обычно при наведении курсора мыши на подобный блок, оценка, выбранная тобой, как-то выделяется от остальных позиций рейтинга. В нашем примере будут все те же звезды, добавится еще третья — ярко желтая, для подсветки выбранной оценки.
CSS метод
Для этого используем следующий HTML код
<ul> <li class="current" style="width: 60%"><span class="star1" title="Рейтинг 1 из 5">Ужасно</span></li> <li><span class="star2" title="Рейтинг 2 из 5">Плохо</span></li> <li><span class="star3" title="Рейтинг 3 из 5">Нормально</span></li> <li><span class="star4" title="Рейтинг 4 из 5">Хорошо</span></li> <li><span class="star5" title="Рейтинг 5 из 5">Отлично</span></li> </ul>
ul {
width: 150px;
height: 30px;
position: relative;
background: url(path-to/stars.png);
}
li {
float: left;
height: 30px;
}
li span {
display: block;
width: 30px;
height: 30px;
text-indent: -9999px;
position: absolute;
text-decoration: none;
z-index: 10;
cursor: pointer;
}
li span:hover {
background: url(path-to/stars.png) left center;
left: 0;
z-index: 2;
}
span.star1 {
left: 0;
}
span.star1:hover {
width: 30px;
}
span.star2 {
left: 30px;
}
span.star2:hover {
width: 60px;
}
span.star3 {
left: 60px;
}
span.star3:hover {
width: 90px;
}
span.star4 {
left: 90px;
}
span.star4:hover {
width: 120px;
}
span.star5 {
left: 120px;
}
span.star5:hover {
width: 150px;
}
li.current {
background: url(path-to/stars.png) left bottom;
z-index: 1;
}
ul>li span:hover{
text-indent: 160px;
}
stars.png в данном примере выглядит так:
Демонстрация. Прелести данного метода:
- подсветка указанной оценки происходит без применения скриптов (все работает за счет псевдокласса hover)
- для программиста тоже все прозрачно — чтобы вывести нужный рейтинг на сайт, нужно всего лишь задать нужную ширину первому элементу списка (с классом current)
- код в целом можно назвать семантичным
Недостатки:
- для IE6 придется добавить скрипт эмуляции hover, т.к. этот браузер hover понимает только для ссылок
- много кода
Хотя тут и сделан рейтинг без использования Javascript, очень высока вероятность, что все же скрипты тут будут применяться для отправки данных на сервер, например в паре с AJAX. Я бы так и делал. Поэтому в своей работе я бы такой рейтинг полностью построил на Javascript, тем самым по максимуму упростил HTML код.
Метод на Javascript
За основу берем компактный метод показа рейтингов, рассмотренный выше и «оживляем» его с помощью Javascript:
<div id="productRate">
<div style="width: 60%"></div>
</div>
#productRate {
background: url(path-to/stars.png);
width: 150px;
height: 32px;
position: relative;
}
#productRate div {
background: url(path-to/stars.png) left bottom;
width: 0;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
cursor: pointer;
}
#productRate span {
display: block;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 2;
background: url(path-to/stars.png) left center;
width: 0;
cursor: pointer;
}
Скрипт использует jQuery
<script type="text/javascript" src="path-to/jquery.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("#productRate").hover (
function(){ /* при наведении мыши на блок с рейтингом, динамически добавляем блок с подсветкой выбранной оценки */
jQuery(this).append("");
},
function()
{ /* при уходе с рейтинга, удаляем блок с подсветкой */
jQuery(this).find("span").remove();
});
var rating;
jQuery("#productRate").mousemove (
/*
устанавливаем ширину блока с подсветкой таким образом, чтобы была выделена оценка, находящаяся под курсором мыши
*/
function(e){
if (!e) e = window.event;
if (e.pageX){
x = e.pageX;
} else if (e.clientX){
x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
}
var posLeft = 0;
var obj = this;
while (obj.offsetParent)
{
posLeft += obj.offsetLeft;
obj = obj.offsetParent;
}
var offsetX = x-posLeft,
modOffsetX = 5*offsetX%this.offsetWidth; /* 5 - число возможных оценок */
rating = parseInt(5*offsetX/this.offsetWidth);
if(modOffsetX > 0) rating+=1;
jQuery(this).find("span").eq(0).css("width",rating*30+"px"); /* ширина одной оценки, в данном случае одной звезды */
});
jQuery("#productRate").click ( /* по клику на блоке можно определить какую оценку поставил пользователь */
function()
{
alert("Я ставлю "+rating);
return false;
});
Демо пример. Преимущества:
- компактный и семантический HTML код
- более компактный CSS
- код максимально подготовлен к «боевым» условиям
Проверено в:
Материалы
- Рейтинг со звездами на CSS (прислал Павел Сорокин)
