Always-in-viewport popup tooltips
by Vallek
HTML
<section class="box-item">
<div class="job__info info visually-hidden">
<h4>Заголовок</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi tempore eius, iste commodi aliquid deleniti vel corporis quaerat perspiciatis aut dolor tempora voluptatem, consectetur tenetur. Incidunt hic eveniet nam saepe.</p>
</div>
</section>
<section class="box-item">
<div class="job__info info visually-hidden">
<h4>Заголовок</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi tempore eius, iste commodi aliquid deleniti vel corporis quaerat perspiciatis aut dolor tempora voluptatem, consectetur tenetur. Incidunt hic eveniet nam saepe.</p>
</div>
</section>
<section class="box-item">
<div class="job__info info visually-hidden">
<h4>Заголовок</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi tempore eius, iste commodi aliquid deleniti vel corporis quaerat perspiciatis aut dolor tempora voluptatem, consectetur tenetur. Incidunt hic eveniet nam saepe.</p>
</div>
</section>
CSS
body {
display: flex;
justify-content: space-between;
}
.box-item {
display: flex;
flex-direction: column;
position: relative;
width: 150px;
height: 150px;
outline: 1px solid #e2e2e2;
background-color: rgb(240, 104, 41);
}
.box-item:nth-of-type(2) {
width: 300px;
}
.info {
display: block;
visibility: hidden;
position: absolute;
z-index: 0;
padding: 1rem 1rem 0;
box-shadow: 5px 3px 10px -3px rgb(56, 56, 56);
background-color: #fff;
width: 150px;
}
/* JS */
.visually-hidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.out-of-viewport {
visibility: visible;
right: 0;
z-index: 1;
transition: transform 0.2s ease-in,
z-index 0.1s ease-in 0.2s;
box-shadow: -5px 3px 10px -3px rgb(56, 56, 56);
}
.inside-viewport {
position: absolute;
visibility: visible;
left: 0;
z-index: 1;
transition: transform 0.2s ease-in,
z-index 0.1s ease-in 0.2s;
}
JavaScript
let hovered = document.querySelectorAll('.box-item');
let page = document.querySelector('.page');
function remove() {
target.classList.add('visually-hidden');
}
hovered.forEach(
function doit(el) {
let target = el.querySelector('.info');
let heading = el.querySelector('.box-item__heading');
el.addEventListener('mouseenter', isInViewport, { passive: true });
function isInViewport() {
let boxSide = el.offsetWidth;
let rightSide = window.innerWidth - el.getBoundingClientRect().right;
let leftSide = el.getBoundingClientRect().left;
let viewportWidth = window.innerWidth;
if (
target !== null &&
rightSide >= boxSide &&
viewportWidth >= 500
) {
target.classList.remove('visually-hidden');
target.classList.add('inside-viewport');
target.style.left = boxSide + 'px';
}
else {
if (
target !== null &&
leftSide >= boxSide &&
viewportWidth >= 500
) {
target.classList.remove('visually-hidden');
target.classList.add('out-of-viewport');
target.style.right = boxSide + 'px';
}
else {
return;
}
}
}
el.addEventListener('mouseleave', isOutViewport, { passive: true });
function isOutViewport() {
if (target !== null) {
target.classList.remove('out-of-viewport');
target.classList.remove('inside-viewport');
target.classList.add('visually-hidden');
}
else {
return;
}
}
if (target !== null) {
let removeIt = function remove() {
target.classList.add('visually-hidden');
};
target.addEventListener('mouseover', removeIt);
}
else {
return;
}
}
);