<div class="parent">
<div class="child"></div>
<div class="highlight"></div>
<pre class="output"></pre>
</div>
body {
margin: 0;
cursor: crosshair;
overflow: hidden auto;
}
.parent {
min-height: 280px;
margin: 80px 160px;
border: 4px dashed rgb(128 214 255 / 80%);
display: flex;
align-items: center;
background-color: rgb(128 214 255 / 50%);
}
.child {
position: absolute;
width: 120px;
height: 60px;
background-color: rgb(70 1 255 / 75%);
transform: translate(-50%, -50%);
}
.highlight {
position: absolute;
outline: 2px solid #ff6300;
transition: opacity 0.25s ease-in-out;
}
.output {
padding: 16px;
margin: 0;
font-size: 16px;
}
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');
const output = document.querySelector('.output');
const highlight = document.querySelector('.highlight');
const clamp = (min, max, value) => Math.max(min, Math.min(max, value));
const update = () => {
const parentRect = parent.getBoundingClientRect();
const childRect = child.getBoundingClientRect();
const top = clamp(parentRect.top, parentRect.bottom, childRect.top);
const right = clamp(parentRect.left, parentRect.right, childRect.right);
const bottom = clamp(parentRect.top, parentRect.bottom, childRect.bottom);
const left = clamp(parentRect.left, parentRect.right, childRect.left);
const width = right - left;
const height = bottom - top;
const totalArea = childRect.width * childRect.height;
const intersectionArea = width * height;
const intersectionRatio = intersectionArea / totalArea;
highlight.style.setProperty('top', `${top + scrollY}px`);
highlight.style.setProperty('left', `${left + scrollX}px`);
highlight.style.setProperty('width', `${width}px`);
highlight.style.setProperty('height', `${height}px`);
highlight.style.setProperty('opacity', intersectionRatio === 0 ? 0.5 : 1);
output.textContent = JSON.stringify({
actual: {
width: childRect.width,
height: childRect.height
},
intersection: {
width,
height
},
ratio: Number(intersectionRatio.toPrecision(3))
}, null, 2);
};
window.addEventListener('DOMContentLoaded', () => {
const parentRect = parent.getBoundingClientRect();
child.style.setProperty('top', `${parentRect.top}px`);
child.style.setProperty('left', `${parentRect.left + parentRect.width / 2}px`);
update();
});
window.addEventListener('mousemove', (event) => {
child.style.setProperty('top', `${event.pageY}px`);
child.style.setProperty('left', `${event.pageX}px`);
update();
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.