Простая всплывающая подсказка на CSS и jQuery

Знак вопроса на оранжевом фонеКак-то я написал статью о том как можно сделать простую клик-подсказку только на CSS и в общем все хорошо, но покоя мне эта тема не давала. И решил я, как и положено, сделать простую всплывающую подсказку на jQuery - небольшой скриптик, ничего лишнего. Получился у меня скрипт общим "весом" чуть больше 1-го килоБайта.
  Суть его простая - найти подходящие элементы, обернуть и добавить необходимые блоки, организовать тип вывода подсказки - по клику или при наведении курсора и самое главное - всегда отображать подсказку в видимой области экрана, даже при наличии вертикальной или горизонтальной прокрутки страницы.
Информация изложенная здесь устарела!
Обновленный, доработанный и улучшенный вариант простой всплывающей подсказки выложен в новой статье - Универсальная всплывающая подсказка.
  Текст подсказки берется из тега TITLE или из блока, расположенного рядом, в котором прописывается подсказка. Оформление и варианты положений задаются в стилях, кстати, для любителей "только на CSS" возможно использовать подсказку и без скрипта. Данный вариант в любом случаи, как мне кажется, лучше предыдущего.
 Итак, для начала смотрим демо:
DEMO
 Кто в курсе дела и сам разберется - архив с исходником и необходимыми дополнениями в конце статьи :)
 Цвет, фона и текста подсказки определяется в CSS. На демонстрационной странице он черный просто для контраста.
 Теперь разберемся что к чему.

CSS для всплывающей подсказки

Стиль не большой и простой, но при желании можно расширить.
.tip {
  display: inline-block;
  position: relative;
}
/*Стиль для кнопки, если она есть*/
.tip em,
.linktip em {
  background:#FD6E00;
  text-align:center;
  border-radius: 20px;
  border: 1px solid #ccc;
  color: #fff;
  font: normal bold 12px Arial;
  text-decoration: none;
  cursor:pointer;
  padding: 0 4px;
}
/*Стиль для изображения в подсказке*/
.tip>span>img {
  max-width: 50%;
  max-height: auto;
  margin: 3px;
  float: left;
}
/*Стиль для кнопки закрытия подсказки(кристик)*/
.answer>b,
.answer-left>b {
  position:absolute;
  font: normal bold 14px Comic Sans MS;
  color:#999;
  cursor:pointer;
  padding: 4px;
}
.answer>b {
  top:0;
  right:0;
}
.answer-left>b {
  top:0;
  left:0;
}
.answer>b:hover,
.answer-left>b:hover {color:#000;} /*при наведении*/

/*Стиль для блока подсказки*/
.answer,
.answer-left {
  display:none; /*скрываем*/
  position:absolute; /*позиционируем абсолютно*/
  z-index:9999; /*отображаем поверх всех элементов на странице*/
  background: #EDEDED; /*цвет фона*/
  border-radius: 3px;
  border: 1px solid #ccc;
  color: #000; /*цвет текста*/
  font: normal 500 14px Trebuchet MS;
  text-align:left;
  text-shadow: 0 1px 2px #fff, 0 0 10px #E0F1FF; /*тень текста*/
  text-decoration: none;
  opacity: 1; /*прозрачность*/
  cursor:default;
  margin-top:-30px; /*смещение вверх*/
  width: 200px; /*ширина !значение*/
  min-height: 50px; /*минимальная высота (если текста мало)*/
  max-height: auto; /*высота в зависимости от количества текста*/
  white-space: normal; /*переносы слов*/
}
.answer {
  box-shadow: 5px 5px 0.5em -0.1em rgba(0,0,6,0.5); /*тень справа*/
  right: -240px; /*!смещение = ширина + отступы*/
  padding: 5px 20px 7px 7px; /*отступы внутри*/
}
.answer-left {
  box-shadow: -5px 5px 0.5em -0.1em rgba(0,0,6,0.5); /*тень слева*/
  left: -240px; /*!смещение*/
  padding: 5px 7px 7px 20px;
}
.a-top {
  bottom: -10px; /*!смещение, положение подсказки вверх */
}
/*Стили для уголка*/
.a-top:before,
.answer:before,
.answer-left:before {
  content:"";
  position:absolute;
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAQAAACR313BAAAAaElEQVR4XoWQMQ6AMAwDna6wMXTjB/x/7E4i9SV9AwgxuJKDcKfqrlVizInrObwLHLng9sKhgm8nIQV4eWAFJig/EIogUATCTPh7zZUUuqHXOL4m7waglViyvVthNXvaGhNr2jnTLQTenE8VKUp0n4sAAAAASUVORK5CYII=) no-repeat;
  width: 9px;
  height: 15px;
}
.answer:before {
  left: -9px;
  margin-top: 10px;
  background-position: 0 0;
}
.answer-left:before {
  right: -9px;
  margin-top: 10px;
  background-position: -9px 0;
}
.a-top:before {
  bottom: 10px;
}
/*Для отображения клик-подсказки без скрипта, только на CSS*/
.tip>a:focus~span.answer,
.tip>a:focus~span.answer-left {
  display:block;
}
.tip>a[tabindex="1"]:focus {
  outline: none;
}
.tip>a[tabindex="1"]:focus>em {
  background:#FF4F19;
}

HTML разметка

Тут доступно 2 варианта.
 1.Простой - добавляем к ссылке класс, по которому скрипт определит что это будет ссылка с подсказкой. Текст добавляется в атрибут TITLE.
<a class="linktip" href="#" title="Текст подсказки">SomeLink</a>
Класс .linktip говорит о том что для этой ссылки будет "построен" блок с подсказкой.
 2. Всплывающая подсказка с ссылками и картинками - весь блок пишется вручную. Плюс в том что такая всплывающая подсказка будет работать без скрипта, только на CSS.
<span class='tip'><a tabindex="1"><em>?</em></a><span class='answer'>Текст подсказки</span></span>
 При использовании без скрипта, чтобы подсказка отображалась при наведении курсора в стилях меняем :focus на :hover
 Тег <em> выполняет роль кнопки, если его нет, ссылка отображается обычно. Для скрипта, он также является фильтром отображения подсказки - при наведении курсора или по клику.

jQuery скрипт для всплывающей подсказки

 Скрипт самый простой. Именно он добавляет нужные классы, для правильного позиционирования(отображения) подсказки на экране и определяет способ ее появления.
$(function() {
 $('a.linktip').wrap('<span class="tip" />'); //оборачиваем соответствующие элементы в контейнер
  $('span.tip').each(function(){
       myTip = $(this),
       tipLink = myTip.children('a'),
       tBlock = myTip.children('span').length, //подсчитываем дочерние SPAN элементы внутри контейнера
       tTitle = tipLink.attr('title') != 0, //определяем наличие тега TITLE
       tipText = tipLink.attr('title'); //берем текст из тега TITLE

     tipLink.removeAttr("title"); //скрываем обычный TITLE
   //условие - если внутри нет доч. SPAN и есть TITLE,
   //добавляем соответствующий SPAN с текстом взятым из TITLE
     if(tBlock === 0 && tTitle === true){myTip.append('<span class="answer">' + tipText + '</span>')};

     var tip = myTip.find('span.answer , span.answer-left').hide(); //найдем и скроем блоки с подсказками

//при наличии у ссылки тега EM подсказка будет появляется по клику
//также сразу добавим и "крестик" закрытия
     tipLink.has('em').click(showTip).siblings('span').append('<b class="close">X</b>');

//если тага EM нет, подсказка будет появляться при наведении курсора
    tipLink.not($('em').parent()).hoverIntent(
       showTip,
     function(){
       tip.fadeOut(200);}
    );
//закрытие подсказки при клике на "крестик"
    tip.on('click', '.close', function(){
       tip.fadeOut(200);}
    );

//функция вывода и появления подсказки на экран
//вне зависимости от размеров окна,
//наличия горизонтальной или вертикальной прокрутки
//подсказка всегда будет в видимой области
    function showTip(e){
       xM = e.pageX,
       yM = e.pageY,
       tipW = tip.width(),
       tipH = tip.height(),
       winW = $(window).width(),
       winH = $(window).height(),
       scrollwinH = $(window).scrollTop(),
       scrollwinW = $(window).scrollLeft(),
       curwinH = $(window).scrollTop() + $(window).height();
    if ( xM > scrollwinW + tipW * 2 ) {tip.removeClass('answer').addClass('answer-left');}
       else {tip.removeClass('answer-left').addClass('answer');}
    if ( yM > scrollwinH + tipH && yM > curwinH / 2 ) {tip.addClass('a-top');}
       else {tip.removeClass('a-top');}
    tip.fadeIn(100).css('display','block');
   e.preventDefault();
   };
 });
});/*конец*/

 Не забываем что для работы данного скрипта у вас на сайте должна быть подключена библиотека jQuery
 Однако, дабы избавится от, так называемой, "свистопляски" при быстром и многократном наведении курсора на ссылку со всплывающей подсказкой, и не мучать мозг с setTimout и setInterval, добавим один очень чудесный плагин, который я не так давно нашел в сети. Называется он hoverInternet, он уже используется в демо и добавлен в архив с исходником.
  Официальная страница плагина
 Вот и все, мнения, пожелания, критика - в комментах.

  Скачать исходник со всеми необходимыми дополнениями, как всегда, можно из сферы, нажав на кнопку ниже. Файл - SimpleTip
СКАЧАТЬ ZIP
P.S. Отдельное спасибо классным пацанам с CyberForum.ru, которые помогли разобраться с важным моментом :).
©http://magentawave.com

30 комментариев:

  1. Анонимный12.03.13, 21:03

    А, как сделать свою картинку для этой кнопки?? Второй день уже туплю...

    ОтветитьУдалить
    Ответы
    1. Какой кнопки? Со знаком вопроса? Это не картинка, это все через стили сделано, но впрочем можно и через картинку. Стиля для неё записаны в коде CSS после комментария
      /*Стиль для кнопки, если она есть*/

      Удалить
    2. Анонимный13.03.13, 8:04

      Ну, она не отображается... я прописываю картинку , убираю радиус, и т.д. нО ЗНАЧЕК ВОПРОСА ОСТАЕТСЯ НЕИЗМЕННЫМ. Просто за ним меняется фон, на фон картинки. Я так понимаю у вас меня выполненно имено при помощи "hoverInternet" ?

      Удалить
    3. hoverInternet - это jQuery плагин, чтобы при наведении убрать зацикливание и автоматом выставить короткий таймаут на появление подсказки. Но его можно убрать и вместо функции в скрипте .hoverIntent использовать обычную функцию - .hover при этом в строке:
      tip.fadeIn(100).css('display','block');
      нужно добавить функцию .stop() и будет так:
      tip.stop().fadeIn(100).css('display','block');
      Это я просто так изначально написал скрипт, так сказать пробовал, пожалуй обновлю пост и уберу этот плагин, можно обойтись и без него.

      Что касается вашей картинки. во-первых, к скрипту это дело не имеет никакого отношения, это CSS. Во-вторых, понятное дело что знак вопроса никуда не денется ибо картинку вы подкладываете как фон, а "?" это текст, не пишите его в HTML коде для подсказки и его не будет или сделайте текст прозрачным, а размер шрифта нулевым. И не забывайте указывать в стилях для EM высоту и ширину соответствующую вашей картинке. А именно:
      /*Стиль для кнопки, если она есть*/
      .tip em,
      .linktip em {
      background:url(.../your-img-16x16.png) no-repeat;
      color: transparent; /*цвет текста прозрачный*/
      font: normal normal 0 Arial; /*размер шрифта - 0*/
      text-decoration: none;
      cursor:pointer;
      height: 16px;
      width: 16px;
      }

      Удалить
    4. Анонимный13.03.13, 11:46

      Понятно что это css, но моя картинка с размерами 200/100px , с казанной даже таким образом -"min-height: 100px;" она не отображается этим размером. Чем еще может быть это ограничено?

      Удалить
    5. Я уж теперь вообще смутно понимаю что вы творите... Код всего что вы уже сделали сюда - http://jsfiddle.net, ссылку в комент. (КОД В КОММЕНТАРИЙ НЕ ПОСТИТЬ)

      Удалить
  2. Анонимный13.03.13, 12:18

    http://jsfiddle.net/cCZVG/

    ОтветитьУдалить
    Ответы
    1. http://jsfiddle.net/cCZVG/1/

      Удалить
    2. Анонимный13.03.13, 13:13

      Большое спасибо) Остался последний вопрос, чем регулируется ее позиционирование относительно моей картинки? Если ем же css? то сам просто позже проэкспериментирую. Еще раз спасибо!

      Удалить
  3. Анонимный09.07.13, 12:41

    Подскажите по какой причине вместо подсказок может вылетать "Undefined" ? подключил вроде все правильно, окошко с подсказкой вылетает, а вместо подсказки Undefined ((

    ОтветитьУдалить
    Ответы
    1. Вы где-то допустили ошибку в коде, такой ответ означает что содержимое не найдено, т.е. скрипт не находит блок текста подсказки. Я еще раз проверил код из статьи, все работает. Ищите ошибку у себя в коде, возможно где-то название класса спутали.

      Удалить
  4. сильно хитрый цсс
    .tip>span>img оно может работать и так .tip span img?
    .tip>a:focus~span.answer - что делает тильда?
    .tip>a:focus~span.answer-left
    .tip>a[tabindex="1"]:focus - а это вообще как - что это за индекс и для чего нужен?

    ОтветитьУдалить
    Ответы
    1. Так сделано чтобы подсказка работала без скрипта. Чтобы было понятнее по коду и селекторам, изучаем:
      http://www.w3.org/TR/selectors/#selectors
      http://htmlbook.ru/samcss/selektory-atributov

      tabindex - указывает на приоритет подсветки ссылки при переключении клавиатурой. В данном случаи это трюк, используется чтобы убрать подсветку по умолчанию и иметь возможность дополнительно выделить значок с "?" когда подсказка активна.

      Удалить
  5. Анонимный25.10.13, 11:01

    tipLink.not($('em').parent()).hoverIntent( лишняя закрывающая скобка.
    Не работает в ие7, ни с jq ни css

    ОтветитьУдалить
    Ответы
    1. Не уверен что она(скобка) лишняя, в IE7 тестил - все работает

      Удалить
  6. Классный скрипт, спасибо. Для будущих поколений: чтобы прикрутить его к CMS Drupal, нужно исправить первую и последнюю строки.

    jQuery(document).ready(function($) {
    ...
    })(jQuery);

    ОтветитьУдалить
    Ответы
    1. Однако, почему-то не закрывается подсказка при клике на крестик... Помогите, пожалуйста.

      Удалить
    2. Показывайте пример.У меня все работает.

      Удалить
  7. Анонимный03.02.14, 13:38

    Спасибо за всплывающие окошечки. :)
    Правда не использую их по полной, просто срочно нужно было какое-то готовое решение. Пришлось убрать стрелочку блока (она классная, но не было времени делать новую картинку другого цвета). К тому же не разобрался, как увеличить ширину всплывающей подсказки.
    У себя также добавил скрытие окошка по клику мимо него (кроме крестика):
    $(document).click(function(event) {
    if ($(event.target).closest(".tip").length) return;
    $(".answer").hide();
    event.stopPropagation();
    });

    ОтветитьУдалить
    Ответы
    1. Можно делать проще:
      $('html,body').click(function(){
      $(".answer").hide();
      });

      Удалить
  8. Как сделать закрытие подсказки не по кресту , а по клику в любое место. В демо такого нет.

    ОтветитьУдалить
    Ответы
    1. Зато есть в комментариях. И кстати, сказать это устаревший вариант и в скором времени будет обновлен, на более удобный и простой.

      Удалить
  9. Анонимный18.03.14, 14:13

    Спасибо! То что искал

    ОтветитьУдалить
  10. Анонимный12.05.14, 12:07

    Здравствуйте, у меня подсказка установлена в ячейке таблицы и обрезается границами этой самой ячейки. Как вынести ее поверх всего?

    ОтветитьУдалить
  11. Анонимный30.05.14, 12:00

    Решение казалось изящным, пока не выяснилось, что без плагина "hoverInternet" всё это "изящество" просто не работает. Жаль...

    ОтветитьУдалить
    Ответы
    1. И без этого плагина все работает - http://cssdeck.com/labs/full/kh87bq0r
      Статья написана довольно давно и данная версия подсказки уже устарела в ближайшее время будет выложен более функциональный и универсальный вариант подсказки.

      Удалить
  12. Анонимный11.03.15, 11:21

    Уважаемый автор, скажите как сделать что бы в вашем примере можно было выделить текст заключенный в подсказке? В данном примере при наведении курсором на подсказку она исчезает, что нужно отредактировать что бы она не исчезала и можно было выделить заключенный в нее текст?

    ОтветитьУдалить
  13. Здравствуйте, уважаемый автор! Мне статья очень понравилась, но на нее наткнулся в поиске на вашем сайте статьи о том, как можно сделать, чтобы описание к фото, которое делается обычно при создании статьи в блоге, не было видно сразу, а появлялось при наведении мышью на фото. То есть, с hover effectом. Как это можно реализовать?

    ОтветитьУдалить

Следующее Предыдущее

BestProject