Создаем подсказки в стиле WP-Coda

Владимир | | CSS, HTML, JavaScript, Web дизайн, Web разработка.

wp coda effect

Думаю, все кто интересуется web дизайном видели тему для WordPress WP-Coda.

Меня прежде всего заинтересовал эффект со всплывающим блоком (появляется над первым пунктом в горизонтальном меню).

Эффект очень красивый и мне захотелось сделать всплывающие подсказки в таком же стиле.

Как оказалось – ничего сверх сложного 😉 .

Прежде всего, рассмотрим принцип работы эффекта.

При наведении указателя мышки на какой-то элемент страницы плавно появляется блок с текстом. При этом одновременно применяются два эффекта: перемещение и изменение прозрачности.

Если переместить мышку на другой элемент страницы – блок плавно исчезает.

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

Кроме того, подсказок может быть несколько, поэтому необходима возможность работы с ними одновременно. Причем одновременно две подсказки не должны быть видимы никогда.

В результате получилось два JavaScript класса. Плюс для их работы нужна библиотека jQuery.

Посмотреть демоверсию можно здесь. Я использовал такие подсказки для всех элементов горизонтального меню.

Первый класс (Popup) – создает подсказки и содержит методы для управления ими.

Второй (PopupContainer) – представляет собой контейнер для хранения экземпляров первого класса, и содержит только один метод addPopup. В качестве параметров он получает id элемента, которому принадлежит подсказка и id блока с самой подсказкой.

Теперь разберем порядок работы эффекта.

Как вы понимаете, переход подсказки из одного состояния в другое (видима/невидима) происходит при возникновении определенного события. В данном случае это mouseenter и mouseleave.

На следующей диаграмме я показал порядок работы эффекта при возникновении события mouseenter.

muoseenter diagram

Прежде всего, обратите внимание на переменные visible и showBegin. В них мы сохраняем текущее состояние подсказки.

Если visible == true, то подсказка в данный момент показана.

showBegin == true означает, что в данный момент идет анимация.

Используя эти переменные, мы можем определить, когда нужно игнорировать событие mouseenter.

Представьте ситуацию. Посетитель навел мышку на элемент, начался показ анимации (изменяется прозрачность, и подсказка плавно смещается). В этот момент посетитель перемещает мышь. Что произойдет? Должна ли прерваться анимация?

Я решил сделать следующим образом. Анимация продолжается в любом случае, но если посетитель убирает мышку с элемента, то сразу же после ее завершения запускается обратный эффект. Т.е. в результате блок с подсказкой будет скрыт.

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

Таким образом, если посетитель уберет мышку с элемента после того как анимация завершилась, то метод hide спрячет подсказку. Если же анимация не завершилась, то метод hide просто установит значение переменной nextAction = 'hide'.

Перед завершением работы метод show проверит состояние nextAction и вызовет метод hide. Т.е. подсказка исчезнет.

Диаграмму работы при возникновении события mouseleave я не приводил, т.к. принцип работы такой же.

Теперь взгляните на исходный код класса Popup

function Popup(target, popup) {
	var showBegin = false;
	var visible = false;
	var nextAction = 'none';
	
	var target = target;
	var popup = popup;
	
	var curObj = this;
	
	this.show = function() {
		if (!visible && !showBegin) {
			//сбрасываем предыдущее значение nextAction
			nextAction = 'show';
			showBegin = true;
			//рассчитываем координаты всплывающей подсказки
			var pWidth = popup.innerWidth();
			var tHieght = target.innerHeight();
			var tWidth = target.innerWidth();
			var tOffset = target.offset();
			var popupLeft = tWidth/2 + tOffset.left - pWidth/2;
			var popupTop = tHieght/2 + tOffset.top;
			
			//показываем подсказку
			popup.removeClass("hide");
			popup.css("top", popupTop);
			popup.css("left", popupLeft);
			popup.css("opacity", 0);
			//запускаем анимацию (изменение прозрачности и положения)
			popup.animate({
				opacity: 1,
				top: '+=' + 10 + 'px'
			}, 1000, 'swing', function() {
				//выполняется после завершения анимации
				visible = true;
				showBegin = false;
				if (nextAction == 'hide') {
					curObj.hide();
				}
			});
		}
		else {
			//если подсказка уже показана или начата анимация
			//сохраняем следующую операцию
			nextAction = 'show';
			return;
		}
	}
	
	this.hide = function() {
		if (!showBegin && visible) {
			//сбрасываем предыдущее значение nextAction
			nextAction = 'hide';
			showBegin = true;
			//убираем подсказку (изменяем прозрачность и смещаем)
			popup.animate({
				opacity: 0,
				top: '-=' + 10 + 'px'
			}, 1000, 'swing', function() {
				//выполняется после завершения анимации
				visible = false;
				showBegin = false;
				popup.addClass("hide");
				if (nextAction == 'show') {
					curObj.show();
				}
			});
		}
		else {
			//если подсказка невидимая или идет анимация
			//сохраняем следующую операцию и выходим
			nextAction = 'hide';
			return;
		}
	}
	
	this.setEventHandlers = function() {
		target.bind('mouseenter', this.show)
			.bind('mouseleave', this.hide);
	}
}

С помощью метода setEventHandlers мы устанавливаем обработчики событий. При возникновении mouseenter будет вызван метод show, а при возникновении mouseleavehide.

Принцип работы метода show мы уже рассмотрели. Единственное, на что я хочу обратить ваше внимание – это способ размещения подсказки.

Нам нужно, поместить подсказку точно под элементом, к которому она относится.

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

Затем делаем подсказку видимой (убираем класс hide) и запускаем анимацию (функция animate). В данном случае мы плавно изменяем прозрачность, и смещаем подсказку вниз на 10 пикселов.

Примечание. Для определения положения и размеров блоков используется плагин jQuery Dimensions.

Теперь рассмотрим класс контейнера

function PopupContainer() {
	var popups = [];
	
	this.addPopup = function(target, popup) {
		var newPopup = new Popup(target, popup);
		newPopup.setEventHandlers();
		popups.push(newPopup);
	}
}

Как видите, он предельно прост. Единственный метод addPopup создает новый объект класса Popup и сразу же вызывает его метод setEventHandlers. Т.е. подсказка сразу же готова к работе.

Использование подсказки

1) Подключаем необходимые библиотеки и стили. Например:

<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jquery.dimensions.js" type="text/javascript"></script>
<script src="js/popups.js" type="text/javascript"></script>
<script src="js/common.js" type="text/javascript"></script>
<link href="css/styles.css" charset="UTF-8" rel="stylesheet" type="text/css" />

2) Создаем элемент, для которого будет вызвана подсказка.

<p><a id="targetblock" href="#">Наведите указатель мыши на этот текст чтобы увидеть подсказку</a></p>

3) Создаем подсказку

<div id="mypopup" class="hide popuptip">
	<div class="tiptext">
	Это всплывающая подсказка в стиле <strong>Coda</strong><br />Она появляется при наведении указателя мыши на ссылку.
	</div>
	<div id="tipfooter"></div>
</div>

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

Во-первых, она должна быть абсолютно позиционирована.

Во-вторых, нужно иметь возможность ее спрятать. Обычно для этого используется правило display: none.

4) Оформление подсказки. Тут у вас полная свобода 😉 . Я использовал следующие правила.

.popuptip {
	position: absolute;
	z-index: 3000;
	width: 160px;
}

.hide {
	display: none;
}

.popuptip .tiptext {
	background-image: url('../images/tooltip_back_transp.png');
	padding: 20px 20px 5px 20px;
	font-size: 0.8em;
}

#tipfooter {
	background-image: url('../images/tooltip_back_transp.png');
	height: 20px;
	background-position: bottom left;
}

Обязательными являются только первые два (popuptip и hide).

Примечание. В качестве фона я использовал рисунок tooltip_back_transp.png и технику CSS спрайтов. Здесь на ней я останавливаться не буду, вы легко сможете найти подробные статьи на эту тему.

5) Создаем подсказку и «привязываем» ее к какому-нибудь элементу на странице.

$(document).ready(function() {
	var pContainer = new PopupContainer();
	pContainer.addPopup($("#targetblock"), $("#mypopup"));
});

Скачать

Если эффект вас заинтересовал – качайте архив с примером. В нем находятся все необходимые библиотеки и скрипты.

Все вопросы и замечания буду рад почитать в комментариях 😉

  • Исчерпывающая статья по коду, спасибо

  • Исчерпывающая статья по коду, спасибо

  • Еще можно использовать паттерн конечных автоматов 🙂

    • У меня на них аллергия 🙂
      Шутка 🙂 .
      А в принципе эта подсказка и ведет себя как конечный автомат.

  • Еще можно использовать паттерн конечных автоматов 🙂

    • У меня на них аллергия 🙂
      Шутка 🙂 .
      А в принципе эта подсказка и ведет себя как конечный автомат.

  • Ух, спасибо за код! жаль что вы раньше это не написали, когда в инсте требывалось )))

  • Ух, спасибо за код! жаль что вы раньше это не написали, когда в инсте требывалось )))

  • Прикольно, но что-то в хроме как-то странно работает; при наведениии на кнопку не фиксируется, а сразу убирается…

    • Спасибо! Как раз в хроме я и не тестировал…

  • Прикольно, но что-то в хроме как-то странно работает; при наведениии на кнопку не фиксируется, а сразу убирается…

    • Спасибо! Как раз в хроме я и не тестировал…

  • Татьяна

    Всё прекрасно,но только не понятно как вставлять на сайте,как закрепить к блогу,допутим мне нужно,чтобы на определённом тексте, при навидение появлялась вот такая подсказка,скажите как зделать , только подробней пожалуйста..Уважаемый

    • Подключение этого скрипта к блогу или сайту обычное.

      1) Подключить файлы в заголовке (для блога на WP (дефолтная тема) заголовок находится в файле wp-contentthemesdefaultheader.php)

      2) Создать блоки с подсказками. Наверно, логичнее всего будет разместить их в футере (wp-contentthemesdefaultfooter.php).

      3) Назначить подсказки элементам на странице. Для этого в заголовок добавляете код из последнего листинга (названия элементов страницы и блоков меняете на ваши). Функцию addPopup нужно вызвать для каждого элемента, которому вы назначаете подсказку.

  • Татьяна

    Всё прекрасно,но только не понятно как вставлять на сайте,как закрепить к блогу,допутим мне нужно,чтобы на определённом тексте, при навидение появлялась вот такая подсказка,скажите как зделать , только подробней пожалуйста..Уважаемый

    • Подключение этого скрипта к блогу или сайту обычное.

      1) Подключить файлы в заголовке (для блога на WP (дефолтная тема) заголовок находится в файле wp-content\themes\default\header.php)

      2) Создать блоки с подсказками. Наверно, логичнее всего будет разместить их в футере (wp-content\themes\default\footer.php).

      3) Назначить подсказки элементам на странице. Для этого в заголовок добавляете код из последнего листинга (названия элементов страницы и блоков меняете на ваши). Функцию addPopup нужно вызвать для каждого элемента, которому вы назначаете подсказку.

  • Alex

    Не могли бы объснить подробней, пункт 3 из последнего комментария

    • Допустим, на странице есть 3 элемента, которым вы хотите назначить подсказки. Предположим, они имеют id: elem1, elem2, elem3.
      Вы создали блоки с подсказками для каждого из них: popup1, popup2, popup3.
      Теперь подключаем подсказки:
      var pContainer = new PopupContainer();
      pContainer.addPopup($("#elem1"), $("#popup1"));
      pContainer.addPopup($("#elem2"), $("#popup2"));
      pContainer.addPopup($("#elem3"), $("#popup3"));

      • Mr Pioneer

        а текст подсказки прямо тут во втором парметре нельзя забивать?

        • Нет, этот скрипт такой вариант не поддерживает. Придется его переписывать.

  • Alex

    Не могли бы объснить подробней, пункт 3 из последнего комментария

    • Допустим, на странице есть 3 элемента, которым вы хотите назначить подсказки. Предположим, они имеют id: elem1, elem2, elem3.
      Вы создали блоки с подсказками для каждого из них: popup1, popup2, popup3.
      Теперь подключаем подсказки:
      var pContainer = new PopupContainer();
      pContainer.addPopup($("#elem1"), $("#popup1"));
      pContainer.addPopup($("#elem2"), $("#popup2"));
      pContainer.addPopup($("#elem3"), $("#popup3"));

  • Спасибо, полезный код

  • Спасибо, полезный код

  • Alex

    За статью большое спасибо,долго искал подобное, но всё не то, а вот у Вас то что нужно,вообще сайт классный.
    Вопросик.
    Не могу понять как пользоваться плагином для определения месторосположения подсказки.
    Текст в подсказке какой может иметь объём в написание?
    Спасибо за ответ!

    • С помощью плагина (Dimensions) определяем положение других элементов, а не подсказки. Ее размещение мы задаем (относительно других элементов или как-то по другому). В данном случае я определял центр элементов которым назначена подсказка (строки 17-22 листинг 1) и размещал подсказку относительно него. Единственно нужно помнить, что мы задаем координаты левого верхнего угла подсказки, а не ее центра.

      >> объем текста

      Теоретически — любой 🙂 Но на практике он ограничен размером экрана, html разметкой подсказки и здравым смыслом.
      В этом примере подсказка фиксированной ширины 160px и для создания фона с закругленными углами используется картинка высотой 1000px. Т.е. глюки могут быть если вы напишите очень длинное слово (>160px) или длина текста будет больше 1000px (если точнее нужно учесть еще отступы от края блока).
      В общем, пара небольших абзацев текста поместиться спокойно, если нужно больше придется менять разметку (например, можно увеличить ширину).

  • Alex

    За статью большое спасибо,долго искал подобное, но всё не то, а вот у Вас то что нужно,вообще сайт классный.
    Вопросик.
    Не могу понять как пользоваться плагином для определения месторосположения подсказки.
    Текст в подсказке какой может иметь объём в написание?
    Спасибо за ответ!

    • С помощью плагина (Dimensions) определяем положение других элементов, а не подсказки. Ее размещение мы задаем (относительно других элементов или как-то по другому). В данном случае я определял центр элементов которым назначена подсказка (строки 17-22 листинг 1) и размещал подсказку относительно него. Единственно нужно помнить, что мы задаем координаты левого верхнего угла подсказки, а не ее центра.

      >> объем текста

      Теоретически — любой 🙂 Но на практике он ограничен размером экрана, html разметкой подсказки и здравым смыслом.
      В этом примере подсказка фиксированной ширины 160px и для создания фона с закругленными углами используется картинка высотой 1000px. Т.е. глюки могут быть если вы напишите очень длинное слово (>160px) или длина текста будет больше 1000px (если точнее нужно учесть еще отступы от края блока).
      В общем, пара небольших абзацев текста поместиться спокойно, если нужно больше придется менять разметку (например, можно увеличить ширину).

  • Alex

    Короче объясню по сути,большой текст и в определённом месте, наводя на слово должна вылазить подсказка, мне как бы и не надо определять расположение этого слова,просто нужно ,чтобы подсказка была рядом с этим словом.
    А у меня получается не так,подсказка вылазит в конце страницы, и то не полностью, получается, что страница перекрывает её-((.
    Может , что подскажите.

    • У вас должна быть возможность выбрать нужно слово как элемент страницы.
      Проще всего это сделать если вставить его внутрь тегов span
      Например,
      <span id="mykey">текст с подсказкой</span>
      И подключаем подсказку
      var pContainer = new PopupContainer();
      pContainer.addPopup($(«#mykey»), $(«#mypopup»));

  • Alex

    Короче объясню по сути,большой текст и в определённом месте, наводя на слово должна вылазить подсказка, мне как бы и не надо определять расположение этого слова,просто нужно ,чтобы подсказка была рядом с этим словом.
    А у меня получается не так,подсказка вылазит в конце страницы, и то не полностью, получается, что страница перекрывает её-((.
    Может , что подскажите.

    • У вас должна быть возможность выбрать нужно слово как элемент страницы.
      Проще всего это сделать если вставить его внутрь тегов span
      Например,
      <span id="mykey">текст с подсказкой</span>
      И подключаем подсказку
      var pContainer = new PopupContainer();
      pContainer.addPopup($(«#mykey»), $(«#mypopup»));

  • Alex

    А кстати,подскажите где менять ширину разметки?

    • 1) перерисовываем картинку с фоном под новую ширину
      2) во втором снизу листинге (CSS стили) в строке 4 указываем новую ширину

  • Alex

    А кстати,подскажите где менять ширину разметки?

    • 1) перерисовываем картинку с фоном под новую ширину
      2) во втором снизу листинге (CSS стили) в строке 4 указываем новую ширину

  • Alex

    Большое спасибо за ответ.

  • Alex

    Большое спасибо за ответ.

  • Красиво сделано. Можно прикрутить к какому-нибудь модному сайту, чтобы посетителей удивлять.

    Правда не некоторых компах будет тормозить. Вот у меня например на работе Атлон 1800 — тормозит эта анимация.

    • К сожалению тут вряд ли получится что-то сделать. Все упирается в скорость выполнения JavaScript. И чем сложнее эффект тем больше нагрузка.
      Вообще, мне кажется, если подсказок на странице должно быть много, то не стоит злоупотреблять эффектами, лучше использовать обычную подсказку.

      Кстати, в оригинале (WP-Coda) эта подсказка применяется только к одному пункту верхнего меню.

  • Красиво сделано. Можно прикрутить к какому-нибудь модному сайту, чтобы посетителей удивлять.

    Правда не некоторых компах будет тормозить. Вот у меня например на работе Атлон 1800 — тормозит эта анимация.

    • К сожалению тут вряд ли получится что-то сделать. Все упирается в скорость выполнения JavaScript. И чем сложнее эффект тем больше нагрузка.
      Вообще, мне кажется, если подсказок на странице должно быть много, то не стоит злоупотреблять эффектами, лучше использовать обычную подсказку.

      Кстати, в оригинале (WP-Coda) эта подсказка применяется только к одному пункту верхнего меню.

  • Дмитрий

    Народ, хелп!
    Не работает эта фишка в IE когда я привязываю ID к тэгу <area….что делать?!ну вот не хочет вылезать подсказка и все…

    • Сложно сказать, присылайте ваш скрипт, попробую потестировать 😉

      • Дмитрий

        Владимир, спасибо уже не нужно…нашел другое решение.Спасибо что откликнулись…:)

  • Дмитрий

    Народ, хелп!
    Не работает эта фишка в IE когда я привязываю ID к тэгу <area….что делать?!ну вот не хочет вылезать подсказка и все…

    • Сложно сказать, присылайте ваш скрипт, попробую потестировать 😉

      • Дмитрий

        Владимир, спасибо уже не нужно…нашел другое решение.Спасибо что откликнулись…:)

  • А как сделать так, чтобы подсказка появлялась не сразу, а при сохранении фокуса на объекте (ссылке) 3 секунды? А если фокус был потерян — ничего не появлялось.

    • Попробуйте так:
      1) при появлении фокуса (событие mouseenter) устанавливаете какой-нибудь флаг (вроде showTip = true)
      2) используя setTimeout(fcn, timeout) создаете задержку. Функция fcn должна показывать подсказку, и в ней непосредственно перед отображением подсказки нужно проверить флаг. Если он сброшен (showTip == true) подсказку не показываем.
      3) при возникновении событие mouseleave нужно сбросить флаг.

  • А как сделать так, чтобы подсказка появлялась не сразу, а при сохранении фокуса на объекте (ссылке) 3 секунды? А если фокус был потерян — ничего не появлялось.

    • Попробуйте так:
      1) при появлении фокуса (событие mouseenter) устанавливаете какой-нибудь флаг (вроде showTip = true)
      2) используя setTimeout(fcn, timeout) создаете задержку. Функция fcn должна показывать подсказку, и в ней непосредственно перед отображением подсказки нужно проверить флаг. Если он сброшен (showTip == true) подсказку не показываем.
      3) при возникновении событие mouseleave нужно сбросить флаг.

  • Где можно посмотреть подсказки в деле?
    Кто делал дайте ссылку пожалуйста.

    • В конце статьи — архив с примером. А польза от него, зависит от дизайна вашего сайта. Желательно, чтобы подсказка не перекрывала текст, кнопки и т.п.

  • Где можно посмотреть подсказки в деле?
    Кто делал дайте ссылку пожалуйста.

    • В конце статьи — архив с примером. А польза от него, зависит от дизайна вашего сайта. Желательно, чтобы подсказка не перекрывала текст, кнопки и т.п.

  • Владимир, спасибо!

  • Владимир, спасибо!