Ощущение динамики часто являлось тем, что отличало насыщенные Flash-ем сайты от сайтов, основанных на стандартах html. До недавнего времени флэш-интерфейсы всегда казались более живыми, они взаимодействовали с пользователем динамично, и это тот функционал, который остальные сайты не могли просто взять и скопировать.
Конечно, позже состояние дел изменилось — появились эффекты для динамических интерфейсов, поддерживаемые такими JS-библиотеками, как
Prototype,
Scriptaculous,
Moo,
YUI,
MochiKit (и этот список можно продолжить). Сейчас самое время (через 4 года) вспомнить технику
CSS Sprites и посмотреть, сможем ли мы добавить в неё «немного динамики».
Знакомство с jQuery
Тут мы сталкиваемся с первым условием: нам нужно использовать
jQuery, чтобы все получилось. jQuery – это хорошо продуманная JS-библиотека, которая предоставляет нам тот же нужный функционал, что и другие библиотеки, но обладает, помимо этого, дополнительным преимуществом, которое позволяет упростить расширение CSS Sprites: для выбора элементов страницы мы можем применять те же конструкции, что используются в CSS.
Нужно отметить, что эта библиотека требует загрузки несколько дополнительных килобайт скриптов. Конечно, внешние JS-библиотеки кэшируются и загружаются только один раз – когда посетитель сайта открывает страницу в первый раз. Самая компактная версия jQuery весит 15 кб. Это неизбежное увеличение размера страницы, и оно может стать проблемой. Если вы уже используете jQuery для других целей, тогда все нормально. Но если вы заинтересованы в добавлении только этой техники, то посчитайте размер загружаемой страницы и решите для себя, стоит ли эффект этого. (С тех пор, как
jQuery хостится у Google, вы можете сделать ссылку на версию используемой библиотеки, как и мы в приведенных примерах, и надеятся, что браузеры большинства посетителей вашего сайта уже закэшировали URL библиотеки) (Пер.:
На мой взгляд, автор тут немного преувеличивает проблему: jQuery одна из самых маленьких JS-библиотек и 15 лишних килобайт за динамику при первой загрузке — это нестрашно)
Как насчет других JS-библиотек? Вам абсолютно ничего не мешает использовать их. Рассматривайте эту статью как открытое приглашение портировать эту технику к той библиотеке, которой вы пользуетесь.
HTML и CSS
Первая вещь, которую мы хотим сделать – это создание основы навигационного меню для посетителей сайта с отключенным JavaScript.
У нас уже есть основанный только на CSS метод для rollover-эффекта (т.е. эффекта при наведении), поэтому начнем создавать нашу навигацию на сайте с использованием CSS Sprites. И, поскольку мы ленивы, в дальнейшем мы не будем создавать все во второй раз, а просто возьмем эти наработки, всего лишь добавив jQuery поверх.
Картинка для CSS Sprites
Если есть какие-то вопросы по технике CSS Sprites, вы можете взглянуть на
оригинальную статью, но есть несколько моментов, которые стоит разъяснить ниже. Начнем с HTML. Уделите особое внимание этой структуре, мы будем часто на неё ссылаться в дальнейшем:
<ul class='nav current-about'>
<li class='home'><a href='#'>Home</a></li>
<li class='about'><a href='#'>About</a></li>
<li class='services'><a href='#'>Services</a></li>
<li class='contact'><a href='#'>Contact</a></li>
</ul>
Каждый класс служит определенной цели: класс
nav тэга
ul позволяет указывать на этот элемент с помощью CSS (и позже Javascript), в то время, как второй класс
current-about используется для выделения просматриваемой страницы или раздела сайта. Каждый
li-элемент имеет свой уникальный класс, который также используется для указания на этот тэг в CSS или JS.
Итак, наша разметка для навигации – это простой и доступный HTML список, и у нас достаточно классов чтобы заработала техника Sprites:
.nav {
width: 401px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat;
position: absolute;
top: 100px;
left: 100px;
}
Мы установили свойство
position равным
absolute, чтобы изменить точку отсчета для позиционных сдвигов тэгов
li. Мы могли бы также использовать значение
relative, чтобы достичь того же эффекта и, в то же время, оставляя элемент
.nav в нормальном потоке. Есть некоторые причины использовать значение
relative, но в этой статье мы будем применять значение
absolute. Больше информации по этому вопросу вы можете получить в
статье Дугласа Боумана.
Основа самой техники Sprites в нашем случае – это использование background-изображений для каждого элемента навигации и их абсолютное позиционирование внутри родительского тэга
ul:
.nav li a:link, .nav li a:visited {
position: absolute;
top: 0;
height: 48px;
text-indent: -9000px;
overflow: hidden;
}
.nav .home a:link, .nav .home a:visited {
left: 23px;
width: 76px;
}
.nav .home a:hover, .nav .home a:focus {
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
.nav .home a:active {
background: url(../i/blue-nav.gif) no-repeat -23px -98px;
}
Мы собираемся продвинуться немножко дальше, чем в оригинальной статье, и определим состояния
focus и
active. Первое состояние – это небольшое добавление к переключателю изображений, когда ссылка является субъектом состояния
hover или
focus, состояние
active добавляет новое свойство – при клике на элемент. Они необязательны, но это хорошая идея — определить стили для обоих состояний. Правило “
overflow: hidden” также новое в наших стилях, оно служит для того, чтобы предотвратить появление визуального бага в некоторых браузерах.
Пример 1: Настройка CSS Sprites для меню.
Итак, мы подошли к стартовой точке – у нас теперь есть работающее навигационное меню, основанное на технике CSS Sprites, с возможностью выбора активного элемента. Разовьем нашу идею дальше.
Начальная настройка jQuery
Заметьте, что весь код, написанный ниже, будет расположен внутри этой jQuery функции, она гарантирует запуск кода только один раз и только после того, как полностью прогрузится вся страница. Все куски кода ниже предполагают, что они запускаются внутри этой функции, поэтому если вы столкнетесь с ошибками, не забудьте проверить месторасположение кода:
$(document).ready(function(){
// весь код здесь
});
Поскольку спрайтовое меню – это наше «меню по умолчанию» для отключенного Javascript (если мы все сделали правильно), то нам лучше избавиться от всех определенных в стилях фоновых изображений для элементов при наведении, поэтому мы создадим новые фоновые изображения с помощью скрипта:
$(".nav").children("li").each(function() {
$(this).children("a").css({backgroundImage:"none"});
});
В первой строчке запрашиваются элемент(-ы) класса
nav и после применяется функция к каждому дочернему элементу
li, который они содержат. Эта функция показана во второй строчке кода, она опрашивает объект
this (под
this подразумеваются найденные тэги
li) на наличие дочерних тэгов a внутри него. Если такие существуют, то для свойства CSS
background-image этих элементов устанавливается значение
none.
Пример 2: Отключение стилей при наведении с помощью jQuery.
Это работает… но мы также потеряли выделение выбранного пункта меню в процессе. Поэтому нам нужно проверять название нашего
current-(выбранный пункт меню) класса для родительского тэга
ul, чтобы сохранить фоновое изображение для выбранного элемента. Предыдущий код необходимо немного расширить:
$(".nav").children("li").each(function() {
var current = "nav current-" + ($(this).attr("class"));
var parentClass = $(".nav").attr("class");
if (parentClass != current) {
$(this).children("a").css({backgroundImage:"none"});
}
});
(Пер.:
В следующем абзаце подробно объясняется, что делает вышеприведенный код. Я посчитал это излишним – это очевидно даже тем, кто не знаком с jQuery. :))
Привязка событий
Теперь нам нужно привязать функцию к каждому из элементов
li для каждого события-взаимодействия, к которому применяются стили. Давайте создадим функцию для этого и назовем её
attachNavEvents:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
// какой-то код
}).mouseout(function() {
// какой-то код
}).mousedown(function() {
// какой-то код
}).mouseup(function() {
// какой-то код
});
}
Эта функция принимает 2 аргумента. Первый аргумент – строка, содержащая название класса родительского элемента. Второй аргумент – строка, содержащая название название класса тэга
li, к которому привязываются события. Мы скомбинировали оба аргумента в следующей строке функции, чтобы создать селектор, аналогичным применяемому в CSS, например такой
.nav .home.
Поскольку jQuery позволяет привязывать сразу несколько функций к одному объекту, мы смогли создать все функции для обработки событий сразу (в одной цепочке). Цепочка функций – это уникальная концепция jQuery. Не стоит заморачиваться насчет неё – не так важно, как она работает. Поэтому если вы находитесь в небольшом замешательстве, просто примите на веру то, что мы сейчас делаем.
Сейчас мы привяжем эти функции к каждому пункту нашего меню. Пока мы сделаем это не лучшим способом (но позже оптимизируем), и просто запустим созданную функцию для каждого тэга
li. В качестве аргументов мы передаем родительский элемент для каждого пункта меню, а также собственное название класса для тэга
li:
attachNavEvents(".nav", "home");
attachNavEvents(".nav", "about");
attachNavEvents(".nav", "services");
attachNavEvents(".nav", "contact");
Пока мы почти ничего не сделали, но у нас все впереди.
Пример 3: Начальная настройка скрипта для событий.
Теория
Я собираюсь объяснить, что мы будем делать дальше. Это важно понять, потому что вам нужно будет создать стили для элементов, с которыми мы будем работать.
Для каждой из ссылок мы создадим новый тэг
div внутри тэга
li. Этот новый тэг мы и будем использовать для эффектов jQuery. Фоновое изображение для тэга
div будет то же самое, что мы использовали ранее для тэга
a (и оно зависит также от родительского тэга
li). Мы абсолютно позиционируем тэг
div (он будет позиционироваться относительно элемента
.nav). Таким образом, мы почти полностью скопировали существующий тэг
a из нашей начальной конструкции CSS Sprites. Путем проб и ошибок я выяснил, что создание нового тэга
div позволяет с меньшими трудностями создать динамические эффекты на jQuery, чем если мы будем обходиться только существующими тэгами, так что это необходимый шаг.
Стили для тэга
div должны быть заранее прописаны в CSS. Мы создадим новый уникальный класс для
div (например,
.nav-home), зависящий от названия родительского класса
li, и добавим к нему стили:
.nav-home {
position: absolute;
top: 0;
left: 23px;
width: 76px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
Практика
Настало время добавления эффектов. Когда срабатывает событие mouseover, мы создаем элемент
div c соответствующим названием класса. Нам нужно, чтобы этот тэг был невидимым перед тем, как он появится, поэтому используем jQuery-функцию css для задания ему свойства
display: none. Наконец, мы используем jQuery-функцию
fadeIn для плавного появления
div и передаем ей в качестве аргумента значение 200, чтобы определить длительность анимации в миллисекундах:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
$(this).before('<div class="nav-' + myClass + '"></div>');
$("div.nav-" + myClass).css({display:"none"}).fadeIn(200);
});
}
Затем мы делаем то же самое, только наоборот, для события mouseout – наш
div должен плавно исчезнуть. После того, как он исчезнет, мы удаляем
div из DOM. Вот как наша функция
attachNavEvents должна работать:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
$(this).before('<div class="nav-' + myClass + '"></div>');
$("div.nav-" + myClass).css({display:"none"}).fadeIn(200);
}).mouseout(function() {
// псевдо-ссылка плавно исчезает и уничтожается
$("div.nav-" + myClass).fadeOut(200, function() {
$(this).remove();
});
});
}
И этого достаточно для эффектов при наведении.
Пример 4: Добавление эффектов при наведении.
Нам следует подумать об обработке событий mousedown и mouseup, поскольку у нас в стилях было прописано состояние
active для ссылок. Создадим другой класс, чтобы мы могли ссылаться только на него в CSS и менять название класса при возникновении события mousedown. При возникновении события mouseup, будет возвращаться прежнее название класса для тэга
div. Вот как будет выглядеть функция
attachNavEvents после этих изменений:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
$(this).before('<div class="nav-' + myClass + '"></div>');
$("div.nav-" + myClass).css({display:"none"}).fadeIn(200);
}).mouseout(function() {
$("div.nav-" + myClass).fadeOut(200, function() {
$(this).remove();
});
}).mousedown(function() {
$("div.nav-" + myClass).attr("class", "nav-" + myClass + "-click");
}).mouseup(function() {
$("div.nav-" + myClass + "-click").attr("class", "nav-" + myClass);
});
}
Мы можем повторно использовать стили при наведении на тэг
div, всего лишь немного изменив положение фонового спрайтового изображения для создания стилей при клике:
.nav-home, .nav-home-click {
position: absolute;
top: 0;
left: 23px;
width: 76px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
.nav-home-click {
background: url(../i/blue-nav.gif) no-repeat -23px -98px;
}
Теперь у нас есть эффекты при наведении, мы видим выбранный элемент навигации, и эффекты при клике также работают.
Пример 5: Собираем все вместе.
Другие размышления
Мы не ограничены только эффектом «fade». jQuery имеет встроенные функции «slideUp/slideDown», которые тоже можно использовать (
второй пример в статье). Или мы даже можем проявить фантазию и задействовать собственные анимационные эффекты, основанные на стилях и использующие jQuery-функцию animate (
третий пример). Сразу предупреждаем насчет функции animate — анимация может получиться не очень плавной, как вы могли заметить в нашем примере.
Кроссбраузерная совместимость – это как своеобразный небольшой подарок для вас, jQuery прекрасно работает во всех современных браузерах, и все, что вы видите здесь, работает в ИЕ6, ИЕ7, ФФ2, ФФ3, Сафари, Опере и т.д. Мы даже предусмотрели множество грациозных способов обхода ограничения функционала. Так, если у посетителя сайта отключен Javascript, он увидит динамику, реализованную с помощью CSS Sprites. (Пер.:
Это не работает в ИЕ6) Если же отключены CSS и JS, посетитель увидит простой
ul-список. Мы получаем и другие преимущества CSS Sprites помимо этого, так как можем использовать одну картинку для различных навигационных состояний и эффектов.
Хотя это и не обязательно, но все же рекомендуется принимать во внимание, что скорость анимации больше, чем несколько сотен миллисекунд может нравиться вначале, а потом начать действовать на нервы посетителям вашего сайта, после того, как эффект новизны сайта для них пропадет. Так что отдавайте предпочтение более быстрой анимации.
Еще одна небольшая проблема, с которой вы можете столкнуться – это когда текст на сайте начинает «моргать» во время анимации. Это сложное явление связано с
рендерингом суб-пикселей, присущим современным операционным системам. Лучшее решение этой проблемы – задать почти непрозрачное значение
opacity, чтобы рендеринг текста проводился особым образом. Если вы добавите эту строчку в свои стили, то «моргание текста» должно прекратиться, только текст будет сглаживаться обычным образом, а не с помощью суб-пикселей:
p {
opacity 0.9999;
}
Пакет функций для Sprites2
Нет необходимости запоминать какой-либо код в этой статье, поскольку мы подготовили
функцию, используемую в нашем окончательном примере. Используя код JavaScript в HTML-файле, как помощь, вам нужно поменять только одну строчку в коде, чтобы применить Sprites2 на вашем сайте:
$(document).ready(function(){
generateSprites(".nav", "current-", true, 150, "slide");
});
Функция
generateSprites принимает 5 аргументов:
1. Название класса родительского
ul, включая точку.
2. Префикс, используемый для выбранных элементов (например, для выбранного класса
selected-about, используйте "
selected-" в качестве значения префикса).
3. Переключатель, показывающий, используются ли стили для состояния
active. Если вы определяете состояние :active и его эквиваленты в jQuery в вашей таблице стилей, установите значение
true. В противном случае нужно установить
false.
4. Скорость анимации, в миллисекундах (300 = 0.3 секунды).
5. Тип анимации, строковая переменная. Установите «slide» или «fade», последнее стоит по умолчанию.
Пример 6: Всего одна простая строчка кода для изменения благодаря нашей функции.
Вам все ещё нужно будет позиционировать и применять стили к различным элементам в вашей CSS, поэтому не стесняйтесь использовать примеры наших стилевых файлов в этой статье, как подсказку.
Заметки
Во время написания этой статьи в интернете распространилась
схожая техника, хотя и без дополнительной поддержки CSS Sprites. Мы также обнаружили совсем другое
анимированное jQuery меню, которое вы можете найти полезным.
комментарии (48)