HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Tooltip-overlay following the mouse pointer

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
tooltiptheoverlayfollowingpointermouse

Problem

The purpose is to attach a tooltip-element to arbitrary HTML-elements.

The tooltip appears when the user hovers an element. Follows the mouse-pointer while moving over the element.



/**
* Attaches a tooltip to every element in the result-set.

* @param { string } selector - An CSS-selector.
* @param { number } horizontalOffset - Horizontal
* distance to the mouse pointer.
* @param { number } VerticalOffset - Vertical distance
* to the mouse pointer.
*
* All parameter are optional. But providing a valid
* selector is indispensable for the function to work.
*
* Usage example:
* ... })('.tooltip-item', 10, 5);
*/
(function(selector, horizontalOffset, verticalOffset) {
var items;

selector = selector || '.tooltip';
horizontalOffset = horizontalOffset || 5;
verticalOffset = verticalOffset || 5;

items = document.querySelectorAll(selector);
items = Array.prototype.slice.call(items);

items.forEach(function(item) {
// Every time the pointer moves over the element the
// CSS-rule in overwritten with new values for
// top and left.
item.addEventListener('mousemove', function(e) {
let countCssRules = document.styleSheets[0].cssRules.length;
let newRule = selector +
':hover:after { display: block; ' +
'left: ' + (e.offsetX + horizontalOffset) + 'px; ' +
'top: ' + (e.offsetY + verticalOffset) + 'px; }';

document.styleSheets[0].insertRule(newRule, countCssRules);
});
});
})('.tooltip-item', 10, 5);

`.wrap {
width: 1000px;
margin: 50px auto;
font-family: georgia, serif;
background-color: cornsilk;
padding: 20px 30px;
}

div.tooltip-item {
background-color: orange;
width: 450px;
height: 100px;
border: 1px solid black;
border-radius: 8px;
margin: 60px 10px;
}

.tooltip-item {
position: relative;
cursor: pointer;
}

.tooltip-item:after {
content: attr(data-message);
position: absolute;
left: 10

Solution

I found this post and took your code and made some changes. I wanted to have a very small piece of javascript code that supported style-able tooltips.

First, the way you were editing the CSS was to add an additional style every time the mouse moves. This will create hundreds of style additions in just a few seconds of mouse movement, so very inefficient over time. To avoid this, I created a blank style for the hover class and preserved reference to this style definition. I then modified the style using this reference, rather than creating new styles every time the handler is called.

Second, the code doesn't account for if the value is blank. The tooltip will show a blank box, instead of not showing at all. So I added a conditional to hide the tooltip if this is case.

Third, you can select a CSS style by data attribute, so there is no need to specify a .tooltip class for the element. So I dropped that.

Forth, setting the position of the tooltip element relative to the hover element has glitches. If the hover element is inside another element, the tooltip width will be glitchy and often too narrow if the parent element is something small, like a table cell. There are workarounds, such as setting a fixed width of the tooltip element, but this isn't ideal. There is another workaround to contain the tooltip in a wrapper div, but you cannot do this because html is not allowed when using the CSS content attribute. The fix I used is to set the tooltip to "display: fixed", and set position based on screen coordinates. This allows me to use max-width while shorter tooltips are only the width of the text.

A final note: this solution is probably not ideal on a mobile device. But I am using this for a desktop environment, so it works for this class of usage.



document.addEventListener('DOMContentLoaded', function() {
var cssSheet = document.styleSheets[0];
var hoverIndex = cssSheet.insertRule('[data-tooltip]:hover:after {}', cssSheet.cssRules.length);
var cssHover = cssSheet.cssRules[hoverIndex];
Array.from(document.querySelectorAll('[data-tooltip]')).forEach(function (item) {
item.addEventListener('mousemove', function (e) {
if (this.dataset.tooltip == '') {
cssHover.style.display = 'none';
return;
}
cssHover.style.display = 'block';
cssHover.style.left = (e.clientX + 15) + 'px';
cssHover.style.top = (e.clientY + 15) + 'px';
});
});
});

[data-tooltip] {
border-bottom: 1px dotted #777;
cursor: help;
}

[data-tooltip]:after {
content: attr(data-tooltip);
display: none;
position: fixed;
max-width: 600px;
background: #ffd;
border: 1px solid #999;
padding: 12px;
color: #000;
border-radius: 3px;
margin: 0;
font-size: 14px;

left: 50px;
top:25px;
z-index: 10;

box-shadow: 0px 0px 5px rgba(0,0,0,.2);

line-height: 1.3em;
}


Hover over me!

Context

StackExchange Code Review Q#139327, answer score: 5

Revisions (0)

No revisions yet.