I always disliked how basic HTML tooltips are and often find myself employing modals to display more information, but it feels like the wrong solution from a UX perspective in most cases. To that end, I have put together the following solution.
Due to the self-taught nature of my work, I fully expect there is a lot of room for improvement and would be most grateful to anyone who can identify and explain anything I have done inefficiently, or downright badly.
I have employed jQuery within this, which was entirely unnecessary and was done so for brevity. I am interested in opinions (and research!) which would indicate if there are any disadvantages to this. Most sites I work on would be using Twitter Bootstrap and so would have jQuery included anyway. Would a purely vanilla solution offer any noticeable advantages? Could it be done without making the code more messy and more difficult to follow?
$(function() {
// SETTINGS
var distanceFromCursor = 5; // pixel offset from cursor to top-left of tooltip
var zIndexBase = 100; // z-index start point
// INIT
tooltipUnstickyAll(); // set default behaviour to follow the cursor
tooltipRaiseAll(zIndexBase); // set z-index on all tooltips
// FUNCTIONS
function getTarget(e) {
return $("#tooltip" + e.target.attributes['data-tooltip'].value).eq(0); // return a jQuery object representation of the tooltip element relating to the data-tooltip value
}
function isSticky(e) {
return getTarget(e).attr('data-sticky'); // return value of data-sticky for the relevant tooltip, should always be true|false
}
function tooltipUnstickyAll() {
$(".tooltip").attr('data-sticky', false); // make sure all tooltips are unsticky to begin with, so they will always appear first time
}
function tooltipShow(target, x, y, z) {
$(".tooltip[data-sticky='false']").hide(); // make sure all non-sticky tooltips are hidden
target.show(); // display the current tooltip
tooltipMove(target, x, y); // move tooltip to the cursor
tooltipRaise(target, z);
}
function tooltipHide(target) {
target.hide(); // hide the current tooltip
}
function tooltipMove(target, x, y) {
target[0].style.top = (y + distanceFromCursor) + 'px'; // move the tooltip to match the cursor
target[0].style.left = (x + distanceFromCursor) + 'px'; // move the tooltip to match the cursor
}
function tooltipStickyToggle(target) {
target.attr('data-sticky',target.attr('data-sticky')=="false"); // toggle value of data-sticky attribute of the target between true|false
}
function tooltipHideAll() {
$(".tooltip").hide(); // hide all the tooltips
}
function tooltipRaiseAll(z) {
$(".tooltip").css('z-index', z); // set z-index on all tooltips
}
function tooltipRaise(target, z) {
target.css('z-index', z); // set z-index on target
}
function highestZindex() {
indexHighest = zIndexBase;
$(".tooltip").each(function() {
var indexCurrent = parseInt($(this).css("z-index"), 10);
if(indexCurrent > indexHighest) {
indexHighest = indexCurrent;
}
});
return indexHighest + 1;
}
// EVENTS
$(".tooltipable")
.mouseover(function(e) {
if (isSticky(e)=="false") tooltipShow(getTarget(e), e.clientX, e.clientY, highestZindex());
})
.mouseout(function(e) {
if (isSticky(e)=="false") tooltipHide(getTarget(e));
})
.mousemove(function(e) {
if (isSticky(e)=="false") tooltipMove(getTarget(e), e.clientX, e.clientY);
})
.click(function(e) {
tooltipStickyToggle(getTarget(e));
if (isSticky(e)=="false") tooltipMove(getTarget(e), e.clientX, e.clientY);
})
.dblclick(function(e) {
tooltipHideAll();
tooltipUnstickyAll();
e.preventDefault();
});
});
.tooltip {
display:none;
position:absolute;
padding: 8px;
border-radius: 15px;
border: 2px solid #73AD21;
background: #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<h1>Hover your cursor over some of the images</h1>
<h4>Click to toggle tooltip stickyness</h4>
<h4>Double click to hide all tooltips</h4>
<!--
Anything you want to have a tooltip
Just give it class="tooltipable" and set data-tooltip= any value you want
Numbers are used here but you can use what you like, names might make more sense in some contexts
-->
<img class="tooltipable" data-tooltip="1" src="https://placeholdit.imgix.net/~text?txtsize=19&txt=200%C3%97300&w=200&h=300">
<img class="tooltipable" data-tooltip="2" src="https://placeholdit.imgix.net/~text?txtsize=19&txt=150%C3%97300&w=150&h=300">
<img class="tooltipable" data-tooltip="3" src="https://placeholdit.imgix.net/~text?txtsize=19&txt=320%C3%97300&w=320&h=300">
<!--
Create a div for each tooltip
The class="tooltip" is entirely a styling thing, it's not necessary for functionality
Just give it id="tooltipX" where X corresponds to the data-tooltip value used elsewhere
Fire any markup you want in the divs and away you go
-->
<div class="tooltip" id="tooltip1">
Put some text in here
<p>Make it multiline</p>
Some of it can be <strong>bold</strong> or whatever you want
</div>
<div class="tooltip" id="tooltip2">
Be inventive, fire some <a href="https://google.co.uk">links</a> into it
</div>
<div class="tooltip" id="tooltip3">
Or go crazy with some images like this one
<br>
<img src="https://placeholdit.imgix.net/~text?txtsize=19&txt=80%C3%9760&w=80&h=60">
</div>