Кросс-браузерный вариант реализации механизма рейтинга без использования JavaScript
Прочитал сегодня статью "Пять звёздочек" на Pepelsbey.net. Автор описывает очень интересный подход для реализации механизма рейтингов; основное преимущество описываемого подхода — минимум JavaScript за счет грамотного использования CSS.
Решение Вадима основано на использовании CSS rollovers, плавающих элементах и z-index
и выглядит очень красиво. Особенно меня впечатлило то, что его решение будет работать с выключенной загрузкой изображений и отключенным CSS. Весьма приятно, ибо о usability отечественные разработчики задумываются далеко не всегда.
Среди недостатков отмечу следующие:
- При использовании IE6 с выключенным JavaScript вся красота перестаёт работать (оффтопик: не могу понять, по каким причинам народ до сих пор сидит на IE6?)
- Некоторое неудобство при изменении шкалы: например, если изменить код так, чтобы можно было учитывать полбалла, то помимо ширин придется менять и
z-index
каждого элементаa
. Хотя, в принципе, это мелочь.
Полгода назад я какое-то работал над проектом myfolio.com, там тоже применялось пятизвёздочное голосование (правда, принцип несколько другой). Считая, что тот подход тоже имеет право жить , привожу его здесь.
Разметка очень проста:
<ul class="vote">
<li class="ten"><a href="#rated=10" title="5 stars">5.0</a></li>
<li class="nine"><a href="#rated=9" title="4.5 stars">4.5</a></li>
<li class="eight"><a href="#rated=8" title="4 stars">4.0</a></li>
<li class="seven"><a href="#rated=7" title="3.5 stars">3.5</a></li>
<li class="six"><a href="#rated=6" title="3 star">3.0</a></li>
<li class="five"><a href="#rated=5" title="2.5 stars">2.5</a></li>
<li class="four"><a href="#rated=4" title="2 stars">2.0</a></li>
<li class="three rated"><a href="#rated=3" title="1.5 stars">1.5</a></li>
<li class="two"><a href="#rated=2" title="1 star">1.0</a></li>
<li class="one"><a href="#rated=1" title="0.5 stars">0.5</a></li>
</ul>
<!--[if lte IE 6]></a></td></tr></tbody></table><![endif]-->
Про условные комментарии вокруг элемента ul
можно прочитать в статье "Кросс-браузерное одноуровневое вертикальное меню без JavaScript".
Из особенностей — нумерация идёт в обратном порядке (это связано отказом от float
и z-index
, ибо код в myfolio был гораздо сложнее и с z-index
возникали некоторые проблемы в IE6).
Теперь самое интересное: стили:
background: url(stars.gif) no-repeat 0 0;
}
/* Небольшая особенность: если задавать цвет, то картинка не должна быть прозрачной.
Задание цвета используется для тех, кто выключил загрузку изображений в настройках браузера.
В этом случае пользователь увидит нечто наподобие progress bar (но это всё же лучше, чем ничего).
*/
.vote li.rated, .vote li a:hover {
background-color: red;
}
.vote {
background-position: 0 -14px;
}
.vote:hover li, .ievote:hover li {
background: none;
}
.vote {
width: 80px;
overflow: hidden;
position: relative;
}
.vote, .vote li, .vote li a {
height: 14px;
display: block;
}
.vote li {
position: absolute;
}
.vote, .vote li {
left: 0;
top: 0;
list-style: none;
margin: 0;
padding: 0;
}
.vote li a {
overflow: hidden;
text-indent: -100px;
outline: 0;
}
/* Задаем ширину каждого балла; каждый последующий балл включает в себя предыдущий*/
.vote li.one { width: 7px; }
.vote li.two { width: 16px; }
.vote li.three { width: 23px; }
.vote li.four { width: 32px; }
.vote li.five { width: 39px; }
.vote li.six { width: 48px; }
.vote li.seven { width: 55px; }
.vote li.eight { width: 64px; }
.vote li.nine { width: 71px; }
.vote li.ten { width: 80px; }
/* Для IE6 */
.ievote {
text-decoration: none !important;
}
Наконец, страница с рабочим примером.
Достоинства метода:
- Метод кросс-браузерный, работает даже при отключенной загрузке изображений и выключенном CSS;
- Превосходно работает даже при отключённом JavaScript (в том числе, и в IE6);
- Благодаря использованию CSS rollover достаточно всего лишь одного HTTP-запроса (в отличие от реализаций, где используются списки с элементами
img
).
Еще одно красивое решение от site-creator.info.
Любителям семантической вёрстки посвящается…
Отмечу сразу: я против
Во-первых, из-за того, что элементы формы поганить нехорошо (с точки зрения usability). То есть если пользователь привык, что радиокнопка выглядит именно так, то именно так она и должна выглядеть. Да и более того, браузеры не дают слишком уж извращать внешний вид элементов формы. То есть, если мы хотим нарисовать background поверх радиокнопки, то нам либо придется прятать радиокнопку (потому что она будет нарисована поверх фона, либо прятать ее под какой-нибудь элемент).
Во-вторых, из-за того, что появится много лишнего JavaScript: нам по сути нужно будет обработать три ситуации:
Ладно, теперь от слов переходим к делу.
Разметка:
<label class="ten" for="r10"><input type="radio" name="rate" value="10" id="r10"/>5.0</label>
<label class="nine" for="r9"><input type="radio" name="rate" value="9" id="r9"/>4.5</label>
<label class="eight" for="r8"><input type="radio" name="rate" value="8" id="r8"/>4.0</label>
<label class="seven" for="r7"><input type="radio" name="rate" value="7" id="r7"/>3.5</label>
<label class="six" for="r6"><input type="radio" name="rate" value="6" id="r6"/>3.0</label>
<label class="five" for="r5"><input type="radio" name="rate" value="5" id="r5"/>2.5</label>
<label class="four" for="r4"><input type="radio" name="rate" value="4" id="r4"/>2.0</label>
<label class="three rated" for="r3"><input type="radio" name="rate" value="3" id="r3" checked="checked"/>1.5</label>
<label class="two" for="r2"><input type="radio" name="rate" value="2" id="r2"/>1.0</label>
<label class="one" for="r1"><input type="radio" name="rate" value="1" id="r1"/>0.5</label>
<input type="submit" value="Vote"/>
</form>
Стили (примечание: если требуется поддержка IE6, используйте whatever:hover):
background: url(stars.gif) no-repeat 0 0;
}
html>body .vote label:hover, html>body .vote:hover label:hover {
background: url(stars.gif) no-repeat 0 0;
}
* html body .vote label:hover { /* For IE6 w/whatever:hover */
background: url(stars.gif) no-repeat 0 0 !important;
}
.vote {
background-position: 0 -14px;
position: relative;
}
.vote:hover label.rated {
background: none !important; /* !important is for IE6 w/whatever:hover */
}
.vote label {
height: 14px;
position: absolute;
text-indent: -1000px;
z-index: 2;
overflow: hidden;
}
.vote, .vote label {
left: 0;
top: 0;
margin: 0;
padding: 0;
}
.vote label.one { width: 7px; }
.vote label.two { width: 16px; }
.vote label.three { width: 23px; }
.vote label.four { width: 32px; }
.vote label.five { width: 39px; }
.vote label.six { width: 48px; }
.vote label.seven { width: 55px; }
.vote label.eight { width: 64px; }
.vote label.nine { width: 71px; }
.vote label.ten { width: 80px; }
.vote input {
visibility: hidden;
}
.vote label input {
visibility: visible;
width: 0;
}
И, наконец, JavaScript (я использую Prototype; кому что ближе):
img.onload = function()
{
$('vote').addClassName('vote').select('input[type="radio"]').invoke('observe', 'click', function(e) { e.element().form.submit(); } );
}
img.src = 'stars.gif';
Результат.
Внимание: я не тестировал пример во всех браузерах, поэтому кросс-браузерность гарантировать не могу.Проверено в IE6/7, FF, Opera, Konqueror.
Замечания:
label
) должны иметь атрибутfor
, связывающий их с соответствующей радиокнопкой.visibility: hidden
илиdisplay: none
. Их нужно либо сдвинуть заlabel
, либо, как в примере, поставить нулевую ширину. Если скрыватьlabel
, то обработчик должен вешаться не наinput[type="checkbox"]
, а наlabel
, и код в этом случае немного усложнится.img.onload()
. Для правильной работыimg.onload()
должен сработать первым.а для второго решения (с радиобутонами) есть пример, чтобы посмотреть его в деле? Лень копипастить
Капча злая, вроде правильно пишу… а говорит неверный код
Вот блин, извниняюсь… совсем ослеп. ссылку на пример нашёл