inViewport
Determines if and element is inside the document viewport or not. Settings can be configured to determine if the element is partially inside the viewport using pixels or percentages.
by jwerre
HTML
<ul id="scroll-list">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li id="target"></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<div id="status">
OUT
</div>
<button id="flip-button">
Flip list
</button>
CSS
body {
font-family: sans-serif;
}
ul#scroll-list {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-items: flex-start;
}
ul#scroll-list.horizontal {
flex-direction: row;
}
ul#scroll-list li {
display: block;
flex: none;
box-sizing: border-box;
width: 100px;
height: 100px;
background: darkslategray;
margin: 20px;
text-align: center;
line-height: 100px;
color: white;
border-radius: 3px;
}
ul#scroll-list li#target.in {
background: lawngreen;
}
#status {
position: fixed;
left: calc(50% - 50px);
top: 50%;
width: 100px;
height: 100px;
line-height: 100px;
border: 1px solid darkslategray;
box-sizing: border-box;
color: darkslategray;
text-align: center;
font-weight: bold;
cursor: pointer;
border-radius: 3px;
}
#status.in {
/* color: lawngreen; */
border-color: lawngreen;
}
button#flip-button {
position: fixed;
left: calc(50% - 50px);
top: calc(50% + 120px);
border: none;
box-sizing: border-box;
background: darkslategray;
color: white;
padding: 5px 0;
width: 100px;
cursor: pointer;
border-radius: 3px;
outline: none;
}
button#flip-button:hover {
background: gray;
}
JavaScript
const scrolllist = document.getElementById('scroll-list');
const target = document.getElementById('target');
const status = document.getElementById('status');
const scrollOptions = {
partial: false,
offset: '50%', // pecentage
// offset: 50, // pixels
};
/**
Check whether an element is intirely or partially in the document viewport or not
@method inViewport
@param {Element} element the element to check
@param {Object} options
@param {Boolean} options.partial When true the element is considered inside the viewport if any part is visible.
@param {Number|String} options.offset Offset the element either by number of pixels or a string percentage e.g.:'50%'
@return {Boolean} Whether the element is inside the document viewport or not.
**/
const inViewport = ( element, options={} ) => {
if ( Object.prototype.toString.call(element) === '[object String]' ) {
element = document.querySelector(element);
}
if (!element) {
throw new Error('An HTMLElement or String containing a valid id (#my-elm) or class (.my-elm) name is required.');
}
const rect = element.getBoundingClientRect() || {};
const height = window.innerHeight || document.documentElement.clientHeight;
const width = window.innerWidth || document.documentElement.clientWidth;
let offsetX = 0;
let offsetY = 0;
if (options.partial) {
return rect.top <= height &&
rect.left <= width &&
rect.bottom > 0 &&
rect.right > 0;
}
if (options.offset) {
// if offset is a percentage
if ( /^[0-9]{1,3}%$/.test(options.offset) ) {
const percent = Math.abs(100 - options.offset.replace('%', ''));
const decimal = percent / 100;
offsetX = rect.width * decimal;
offsetY = rect.height * decimal;
} else if (!isNaN(options.offset)) {
offsetX = Number( options.offset );
offsetY = Number( options.offset );
}
}
return (rect.top + offsetY) >= 0 &&
(rect.bottom - offsetY) <= height &&
(rect.left + offsetX) >= 0 &&
(rect.right - offsetX) <=...