Javascript.RU

Отказ от js как оптимизация js, часть 2

Предположим, у нас есть графическое меню на сайте. Нужно при наведении сменить изображение пункта на другое.

Эта задача для эпохи вебдваноля уже не так актуальна, мода на украшательства в навигации постепенно сходит на нет, но все-таки, если дизайнер решил, что в главном меню кровь-из-носа нужны выпукло-вогнутые плашки с Matisse ITC, что же делать в таком случае?

Ставшее почти классическим решение (вошедшее, среди прочего, в редактор Dreamweaver): по событию mouseover src у картинки меняется на нужный, по mouseout — обратно. Но вот беда, картинка еще не подгружена, а ее уже надо показать. Создаем объект Image и проталкиваем при его помощи в кеш изображение.
…полностью забывая про css и добавляя каши в код.

Избавиться от этого безобразия нам помогут так называемые спрайты. Чтобы понять, что это и чем именно помочь, опять начнем с основ css.

display — одно из важнейших свойств css, меняющее поведение элемента. Не вдаваясь (на этот раз) в дебри, лишь скажу, что задав ссылке display: block, мы можем заставить ее вести себя не как строчный элемент, а как блочный:

<style type="text/css">
	a {
		font-size: 24px;
		background: aliceblue;
		text-align: center;
	}
	a:hover {
		background: navy
	}
</style>
<a href="javascript://"> Я ссылка </a>
<a href="javascript://" style="display: block"> А я плашка </a>

Размеры активной области ссылки с display: block можно задавать явным образом через width и height, как и обычному диву. И как обычный див по умолчанию ссылка занимает всю доступную ширину. И то и другое нам на руку.

Рассмотрим другой пример и попутно избавимся от болезни некоторых навигационных меню (ну, например, в phpmyadmin), когда задник уже поменялся, но при щелчке не проиходит ничего, просто потому что на ссылку еще не навели.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<style type="text/css">
			#menu {
				border-collapse: collapse;
				table-layout: fixed;
				width: 100%;
			}
			#menu .menu-item {
				padding: 0px;
				border: solid black 1px;
			}
			#menu .menu-item a {
				display: block; /* ! */
				padding: 4px;
				text-align: center;
				background: aliceblue;  /* ! */
				text-decoration: none;
			}
			#menu .menu-item a:hover {
				background: floralwhite; /* ! */
			}
		</style>
	</head>
	<body>
		<table id="menu">
			<tr>
				<td class="menu-item"><a href="javascript://1">Lorem</a></td>
				<td class="menu-item"><a href="javascript://2">Ipsum</a></td>
				<td class="menu-item"><a href="javascript://3">Dolor</a></td>
				<td class="menu-item"><a href="javascript://4">Sit</a></td>
				<td class="menu-item"><a href="javascript://5">Amet</a></td>
			</tr>
		</table>
	</body>
</html>

Ну а теперь, собственно, перейдем к озвученной проблеме. При наведении на ссылку можно менять положение ее фона при помощи background-position: x y;.

Сделаем что-то наподобие вот такого изображения:

Все, что нам нужно, это сделать это изображение фоном у всех нужных ссылок и у каждой из них показать лишь нужный фрагмент. И получится что-то вроде этого:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<style type="text/css">
			#tpl-menu { 
				display: block;
				padding: 0px; margin: 0px;
				width: 440px; height: 50px;
			}
			#tpl-menu .tpl-menu-item {
				float: left;  /* display становится block автоматически */
				display: inline; list-style: none outside; /* оба свойства — фиксы для IE6 */
				padding: 0px; margin: 0px 5px;
				width: 100px; height: 50px;
			}
			#tpl-menu .tpl-menu-item a {
				display: block;  /* ! */
				height: 0px; padding: 50px 0px 0px 0px; overflow: hidden;
				background: #f0f0f0 url(/files/u4363/sample-sprite.gif) 0px 0px no-repeat;  /* ! */
			}
			#tpl-menu .tpl-menu-item-1 a       {background-position:    0px   0px}
			#tpl-menu .tpl-menu-item-1 a:hover {background-position:    0px -50px}
			#tpl-menu .tpl-menu-item-2 a       {background-position: -100px   0px}
			#tpl-menu .tpl-menu-item-2 a:hover {background-position: -100px -50px}
			#tpl-menu .tpl-menu-item-3 a       {background-position: -200px   0px}
			#tpl-menu .tpl-menu-item-3 a:hover {background-position: -200px -50px}
			#tpl-menu .tpl-menu-item-4 a       {background-position: -300px   0px}
			#tpl-menu .tpl-menu-item-4 a:hover {background-position: -300px -50px}
		</style>
	</head>
	<body>
		<ul id="tpl-menu">
			<li class="tpl-menu-item tpl-menu-item-1"><a href="javascript://1">Рыба</a></li>
			<li class="tpl-menu-item tpl-menu-item-2"><a href="javascript://2">Мясо</a></li>
			<li class="tpl-menu-item tpl-menu-item-3"><a href="javascript://3">Молоко</a></li>
			<li class="tpl-menu-item tpl-menu-item-4"><a href="javascript://4">Масло</a></li>
		</ul>
	</body>
</html>

Как видите, ни грамма яваскрипта и использование одного графического файла вместо восьми (и отпавшая сама собой необходимость к принудительном кешировании), и при всем при этом еще и совместимость с текстовыми браузерами.

Ну, а если Вам нужно менять именно картинки, тоже нет ничего невозможного. Просто засовываем обе в одну ссылку, но показываем только одну. А при наведении — скрываем и показываем другую.

Но тут есть одно «но». В Опере, причем с незапамятных времен, изображения не подгружаются с сервера, если у них установлено display: none. Логично, или нет, но придется придумать другой способ скрывать изображения.

Для этого вспомним, что если у элемента position установлено в absolute, он не занимает места на странице. А еще то, что если элемент уходит за левую или верхнюю границу окна, полоса прокрутки не появляется (кроме некоторых версий Firefox 1.x, который, к счастью, уже отмер).

Итого имеем:

<style type="text/css">
	a:hover .tpl-alternate-visible,
	.tpl-alternate-hidden {
		position: absolute;
		left: -100000px; /* хватит? */
		visibility: hidden; /* если не хватит */
	}
	a:hover .tpl-alternate-hidden,
	.tpl-alternate-visible {
		position: static;
		visibility: visible;
	}
</style>
<a href="javascript://">
	<img class="tpl-alternate-visible" src="http://javascript.ru/forum/images/ca_serenity/misc/logo.gif" />
	<img class="tpl-alternate-hidden" src="http://www.google.ru/logos/holiday09_3.gif" />
</a>

Правда, при просмотре без css мы увидим сразу два изображения. Обладатели медленного интернета и счастивые пользователи elinks, конечно, видели еще и не такое, но что же, нам их совсем не жалко?

Ну, вот, кажется, и все.

+2

Автор: Гость (не зарегистрирован), дата: 24 декабря, 2009 - 12:30
#permalink
#tpl-menu .tpl-menu-item {
    float: left; display: inline; list-style: none outside;
    padding: 0px; margin: 0px;
    width: 100px; height: 50px;
    margin: 0px 5px;
}

Элемент будет блочным несмотря на display:inline.


Автор: subzey, дата: 24 декабря, 2009 - 14:49
#permalink

Хорошо, что Вы это заметили. Это неспроста.

Да, элемент будет блочным, и, казалось бы, свойство бесполезное, но IE6 благодаря этому считает флоаты правильно, т.е., без трехпиксельного отступа и удвоения ближнего поля.


Автор: Гость (не зарегистрирован), дата: 24 декабря, 2009 - 12:33
#permalink
#tpl-menu .tpl-menu-item {
    float: left; display: inline; list-style: none outside;
    padding: 0px; margin: 0px;
    width: 100px; height: 50px;
    margin: 0px 5px;
}

margin назначается 2 раза.


Автор: subzey, дата: 24 декабря, 2009 - 14:50
#permalink

Спасибо за внимательность!

Дописывал уже около трех часов ночи, и протупил. Сейчас удалю.


Автор: Гость (не зарегистрирован), дата: 24 декабря, 2009 - 15:16
#permalink

Во втором примере если курсор медленно проводить через границу рисунка, то изображения начинают ужасно прыгать (Firefox 3.5).


Автор: subzey, дата: 24 декабря, 2009 - 18:04
#permalink

Изображения разного размера.
Соответственно, получается так: курсор наведен → картинка сменилась → курсор за картинкой, а, значит, уведен → картинка сменилась.

Уж извините за «грязный» пример. Но я думаю, я его оставлю как экспонат «как делать не стоит».

Кстати, Опера ведет себя по-другому в таких случаях — для нее смена :hover и курсора происходят только в случае, если курсор сдвинулся. Обычно это не нужно (хорошим тоном считается когда у пользователя ничего не убегает из-под курсора), но в маргинальных случаях следует это учесть.


Автор: ixth, дата: 2 марта, 2010 - 11:37
#permalink

Subzey, я тебе наверное уже показывал эту фиговину. Что скажешь про такую "оптимизацию js без js"? Есть две формочки и их надо, таксзть, тогглить по клику на ссылке. Я решил сделать так, чтобы тогглинг работал и без js, получилось как-то так:

http://ainop.ixth.net/examples/form/index2.html

Есть, правда, несколько больших "но":

  1. добавляет в конец URI fragment-id (хотя, с натяжкой это можно считать и фичей).
  2. чтобы при переходе между формами не было вот такого: http://ainop.ixth.net/examples/form/shot-01.png, на сами формы повешен tabindex, что не одобряет w3c и их валидатор.
  3. насколько я помню, предыдущий пункт не оказывает должного действия в ie, будь он трижды проклят.

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 01:37
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 12:41
#permalink

Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
10 + 10 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Другие записи этого автора
subzey
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Популярные таги
Последние комментарии
Последние темы на форуме
Forum