CODYSHOP
темы и плагины для WordpressВ этой статье хочу поговорить о всплывающих подсказках. Хотя эта задача стара как мир, быстро найти готовое решение оказалось довольно проблематично. Я перебрал пару десятков вариантов, но ни один не устроил. Коротко о том, что искал:
- Адаптивность, – пожалуй, главное требование. К 2019 году – это уже давно стандарт, и это правильно.
- Использование библиотеки jQuery, ничего дополнительно тянуть не нужно.
- Оформительная часть должна базироваться на CSS с минимальным набором стилей. Всё остальное: шрифты, цвета, отступы и другое мы адаптируем сами под текущие задачи. Вместо того, чтобы выпиливать лишнее, лучше просто добавим самое необходимое “по ходу”.
Многие готовые решения основаны исключительно на каскадных таблицах CSS. Что ж, это хорошо, если адаптивность не требуется. Но нас это не устраивает. Подсказки на “чистом CSS” не могут рассчитать положение элемента на экране, и работают на основе предустановленных стилей. Именно поэтому, такие подсказки обрезаются в мобильной версии. В некоторых решениях расположение “всплывашки” задаётся явно, вручную: через атрибуты “data-” или даже непосредственно в javascript, что очень неудобно.
Особенности liteTooltip.js
Однако, если вы ищете решение по параметрам, что перечислены выше, представляю вашему вниманию liteTooltip. Это лёгкая библиотека для создания адаптивных всплывающих подсказок. Данное решение не претендует на самое идеальное, однако может закрыть множество задач.
Пару моментов чисто субъективных:
- По умолчанию подсказки должны отображаться над элементом. Пользователи читают сверху вниз, и обычно зрительно захватывают блок текста. Так мы не закрываем непрочитанную часть. Если она не влезает в область экрана, смещаем её так, чтобы она помещалась полностью.
- Поддержка html в блоке подсказки – само собой.
- Реализация оформительной части через JS – избыточно. Цвета, отступы и тому подобное делаем через CSS.
- Хорошо задавать момент появления подсказки для каждого элемента в отдельности: при наведении или клике.
- Подсказка должна рассчитывать ширину области просмотра и адаптироваться к узким экранам, выбирая наилучшее положение относительно элемента (сверху, снизу, слева, в центре, справа).
Всё это учтено в liteTooltip.
Подключение
- Поместите код стилей в любом месте существующего файла CSS или создайте новый. Вы также можете вставить его в HTML-файл в head, обернув код тегами
<style>
и</style>
. - Поместите код JavaScript в существующий JS-файл или создайте новый. Вы также можете вставить его в HTML-файл в head или, лучше перед закрывающим тегом
body
, обернув его тегами<script>
и</script>
. - Присвойте класс
class="liteTooltip"
и один из атрибутов:data-tooltip-mouseover="Ваша подсказка"
илиdata-tooltip-focus="Ваша подсказка"
любому из тегов HTML-файле, где вы хотите, чтобы всплывающая подсказка появлялась при вызове. Вы можете использовать html теги для оформления, но избегайте блочных элементов.
Обратите внимание, что атрибут содержит текст подсказки и событие его вызова:
data-tooltip-mouseover
– появление подсказки при наведении курсором на элемент.data-tooltip-focus
– появление при фокусировки курсора в элементе, обычно используется для полей ввода input.
Код CSS
Для начала давайте построим внешний вид нашей подсказки. Никаких причудливых стилей, только основные свойства и несложная анимация, чтобы вы могли четко видеть, как это работает.
.tooltip { background: rgba(0,0,0,.9); color: #fff; z-index: 999999; position: absolute; padding: 15px; max-width: 250px; border-radius: 2px; } .tooltip.animation-slide { -webkit-animation-name: slideTooltip; -webkit-animation-duration: .25s; -webkit-animation-timing-function: ease; animation-name: slideTooltip; animation-duration: .25s; animation-timing-function: ease; } .tooltip .tooltip-arrow { position: absolute; border: 8px solid rgba(0,0,0,.9); } .tooltip-arrow.bottomtotop { border-top-color: transparent; border-left-color: transparent; border-right-color: transparent; top: -16px; } .tooltip-arrow.toptobottom { border-bottom-color: transparent; border-left-color: transparent; border-right-color: transparent; bottom: -16px; } .tooltip-arrow.righttoleft { border-left-color: transparent; border-bottom-color: transparent; border-top-color: transparent; left: -16px; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); } .tooltip-arrow.lefttoright { border-right-color: transparent; border-bottom-color: transparent; border-top-color: transparent; right: -16px; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); } .tooltip-arrow.center { left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); } @-webkit-keyframes slideTooltip { from { -webkit-transform: translateY(-20%); transform: translateY(-20%); opacity: 0; } to { -webkit-transform: translateY(0); transform: translateY(0); opacity: 1; } } @keyframes slideTooltip { from { -webkit-transform: translateY(-20%); transform: translateY(-20%); opacity: 0; } to { -webkit-transform: translateY(0); transform: translateY(0); opacity: 1; } }
Код JS
!function($, b, c, d) { 'use strict'; $.fn.liteTooltip = function(c) { var g, e = $(this), f = $.extend({}, $.fn.liteTooltip.default, c); e.each(function() { var evnt = ( typeof $(this).attr('data-tooltip-mouseover') !== 'undefined' ) ? 'mouseover' : ( typeof $(this).attr('data-tooltip-focus') !== 'undefined' ) ? 'focus' : 'mouseover'; 'mouseover' === evnt ? g = 'mouseout' : 'focus' === evnt && (g = 'blur') $(this).on(evnt, function() { $.fn.liteTooltip.removeElem(f) function m($) { 'top' === $.position ? r($) : 'left' === $.position ? p($) : 'right' === $.position ? o($) : 'bottom' === $.position ? q($) : n($), t($, i) } function n(c) { function t($, b) { 'top' === $ ? (b.position = 'top', r(b)) : 'bottom' === $ ? (b.position = 'bottom', q(b)) : 'left' === $ ? (b.position = 'left', p(b)) : 'right' === $ && (b.position = 'right', o(b)) } var d = { left: 0, right: 0, top: 0, bottom: 0 }, e = null, g = 0, h = c.triggerLeft - c.tlWidth + f.space; h > g && (d.left = h); var i = $(b).width(), j = i - (c.triggerLeft + c.triggerW); j > c.tlWidth && (d.right = j); var k = c.triggerTop, l = k; l > c.tlHeight + f.space && (d.top = l); var m = $(b).height(), n = m - (c.triggerTop + c.triggerH); n > c.tlHeight + f.space && (d.bottom = n); var s = Math.max(d.left, d.right, d.top, d.bottom); $.each(d, function($, b) { b === s && (e = $) }), t(e, c) } function o(c) { var d = $(b).width(), e = d - (c.triggerLeft + c.triggerW); if (e < c.tlWidth + f.space) n(c); else { var g = u(c, 'sideRight'), h = v(c); s(h, g) } } function p($) { if ($.triggerLeft < $.tlWidth + f.space) n($); else { var b = u($, 'sideLeft'), c = v($); s(c, b) } } function q(c) { var d = $(b).height(), e = d - (c.triggerTop + c.triggerH); if (e < c.tlHeight + f.space) n(c); else { var g = u(c), h = c.triggerTop + c.triggerH + f.space; s(h, g) } } function r($) { if ($.triggerTop < $.tlHeight + f.space) n($); else { var b = u($), c = $.triggerTop - $.tlHeight - f.space; s(c, b) } } function s(b, c) { $('#tooltip').css({ top: b, left: c }) } function t(b, c) { c.bool ? 'top' === b.position ? 'left' === c.side ? (x('left', b), $('#tooltip').find('.tooltip-arrow').css({ left: b.triggerW / 2 - 8 })) : 'right' === c.side && (x('right', b), $('#tooltip').find('.tooltip-arrow').css({ left: b.tlWidth - (b.triggerW - 8) })) : 'bottom' === b.position && ('left' === c.side ? (x('left', b), $('#tooltip').find('.tooltip-arrow').css({ left: b.triggerW / 2 - 8 })) : 'right' === c.side && (x('right', b), $('#tooltip').find('.tooltip-arrow').css({ left: b.triggerW + 8 }))) : x('center', b) } function u(c, d) { if (d && 'sideLeft' === d) var e = c.triggerLeft - (c.tlWidth + f.space); else if (d && 'sideRight' === d) var e = c.triggerLeft + (c.triggerW + f.space); else var g = .5 * c.tlWidth - .5 * c.triggerW, e = c.triggerLeft - g; return e < 0 ? (e = c.triggerLeft, i.bool = !0, i.side = 'left') : e > $(b).width() && (e = $(b).width() - (c.triggerLeft + c.triggerW) - c.tlWidth, i.bool = !0, i.side = 'right'), e } function v($) { var b = .5 * $.tlHeight - .5 * $.triggerH, c = $.triggerTop - b; return c < 0 && (c = $.triggerTop), c } function w() { var b = $('<div class="tooltip animation-' + f.animation + '" id="tooltip"></div>'); $('body').append(b) } function x(b, c) { var d, e; 'left' === b ? 'top' === c.position ? e = 'toptobottom' : 'bottom' === c.position && (e = 'bottomtotop') : 'right' === b ? 'top' === c.position || 'bottom' === c.position : b && 'center' !== b || ('top' === c.position ? e = 'toptobottom center' : 'bottom' === c.position && (e = 'bottomtotop center')), 'left' === c.position ? e = 'lefttoright' : 'right' === c.position && (e = 'righttoleft'), d = $('<div class="tooltip-arrow ' + e + ' "></div>'), $('#tooltip').append(d) } var c = $(this), e = c.data( 'tooltip' + evnt[0].toUpperCase() + evnt.substring(1) ), g = c.data('tooltipPosition') === d || '' === c.data('tooltipPosition') ? f.position : c.data('tooltipPosition'), h = !1, i = { bool: !1, side: '' }, j = c.offset(); if (h = e !== d && '' !== e && null !== e) { w(); var k = $('#tooltip'); k.html(e); var l = { triggerW: parseInt(c.width()) + parseInt(c.css('padding-left')) + parseInt(c.css('padding-right')), triggerH: parseInt(c.height()) + parseInt(c.css('padding-top')) + parseInt(c.css('padding-bottom')), triggerTop: j.top, triggerLeft: j.left, tlWidth: k.width() + parseInt(k.css('padding-left')) + parseInt(k.css('padding-right')), tlHeight: k.height() + parseInt(k.css('padding-top')) + parseInt(k.css('padding-bottom')), position: g }; m(l) } }).on(g, function() { $.fn.liteTooltip.removeElem(f) }) }) }, $.fn.liteTooltip.removeElem = function(b) { $('body').find('#tooltip').length > 0 && $('#tooltip').removeClass('animation-' + b.animation).fadeOut(50).remove() }, $.fn.liteTooltip.default = { space: 20, animation: 'slide', position: 'top', } }(jQuery, window, document); $('.liteTooltip').liteTooltip();
Подсказка – великолепное изобретение. Однако, идеальная подсказка – это… когда её нет. Если пользователю не нужны пояснения, интерфейс вебсайта построен правильно. Всё же есть случаи, когда она просто необходима.