Xiper

Верстка рейтингов

Автор: Евгений Рыжков Дата публикации:

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

пример рейтинга товара

Рано или поздно каждый кодер сталкивается с такой задачей. И решить ее можно по разному.

Показ рейтинга

Способ 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>

Какие же тут недостатки?

  1. для небольшого блока потребовалась куча строк — не лучшим образом скажется на читаемости кода, поисковой и сео оптимизациях;
  2. потребуется две отдельные картинки — снова же скорость загрузки страницы, нагрузка на сервер;
  3. использование картинок (тег <img>) для оформления, соответственно написать что-то вразумительное в alt нет возможности, а google предупреждал, что лучше так не делать;
  4. программисту, который имеет готовое число рейтинга, все равно придется дополнительно думать и писать код для корректного вывода этого самого рейтинга на сайте.

И на мой взгляд самый большой недостаток — практически нереальность вывода рейтинга со значением не кратным 1/N, где N — к-во возможных оценок в рейтинге (в нашем примере 5). Например, попробуй при такой верстке вывести значение равное 64%. На сайте должно получится что-то вроде такого:

пример рейтинга с неудобным значением

Способ 2 — достойный

Этот вариант решает все вышеперечисленные проблемы. Алгоритм для нашего примера:

  1. делаем контейнер, задаем ему фон с одной пустой звездой, которая размножается по оси x (background-repeat: repeat-x);
  2. в него вкладываем блок, с фоном полной звезды (и тут фон множиться по оси x). По умолчанию этот блок имеет длину (width) равную 0;
  3. в 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%;
}

Разницу трудно не заметить. И поверь, программист тебе будет благодарен за такой код.

Заметка

Для уменьшения числа отдельных картинок тут смело можно применять технику спрайтов.

Показ рейтинга с возможностью голосования

update

Часто можно встретить сайты, где рейтинг не просто показан, а можно, кликнув по нему, поставить свою оценку. Обычно при наведении курсора мыши на подобный блок, оценка, выбранная тобой, как-то выделяется от остальных позиций рейтинга. В нашем примере будут все те же звезды, добавится еще третья — ярко желтая, для подсветки выбранной оценки.

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 (прислал Павел Сорокин)