the elements must be in the document to read offsetHeight and other properties, a hidden (display:none
) or out of the document element has no size.
coordinates right/bottom are different from CSS right/bottom properties, in CSS,
right: the distance from the right edge.
bottom: the distance from the bottom edge.
inline elements (such as <span>, <code>, <b>)
may span multiple lines and consist of multiple rectangles.
const { log } = console;
// โญ๏ธ $all(): select all element
function $all(selector, parent = document) {
return parent.querySelectorAll(selector);
}
// ๐ธ elem.showMessageUnder()
Element.prototype.showMessageUnder = function(html, {
timeout = 5,
showRectInfo = true,
}={}) {
// โญ๏ธ bounding rect
let rect = this.getBoundingClientRect();
log(rect);
// create <div> element
let div = document.createElement('div');
// better to use a css class for the style here (โญ๏ธ don't forget "px"!)
div.style.cssText = `position: fixed; color: red; background: lightyellow; left: ${rect.left}px; top: ${rect.bottom}px; padding: 4px; border: solid black 1px; opacity: 0.7`;
if (showRectInfo) {
html += `<br><code>{x: ${rect.x.toFixed(0)}, y: ${rect.y.toFixed(0)}, width: ${rect.width.toFixed(0)}, height: ${rect.height.toFixed(0)}}</code>`;
}
div.innerHTML = html;
document.body.append(div); // add to the DOM tree
if (timeout > 0) {
setTimeout(() => div.remove(), timeout * 1000); // remove from DOM
}
return div;
};
// click handler
document.onclick = (event) => {
const tag = event.target.tagName;
if (tag !== 'BUTTON') {
log(`clicked on a <${tag}>`); return;
}
$all('span').forEach(span => {
span.showMessageUnder(`bounding rect:`); // ๐ธ custom method
});
};