Верстка рейтингов
Дата публикации: 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 предупреждал (https://developers.google.com/search/docs/appearance/google-images?hl=ru), что лучше так не делать;
- программисту, который имеет готовое число рейтинга, все равно придется дополнительно думать и писать код для корректного вывода этого самого рейтинга на сайте.
И на мой взгляд самый большой недостаток — практически нереальность вывода рейтинга со значением не кратным 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
- код максимально подготовлен к «боевым» условиям
Проверено в:
Материалы
- www.aether.ru/blog/2006/05/15/css-star-rating — Рейтинг со звездами на CSS