检查元素是否部分在视口中
Check if element is partially in viewport
我正在尝试确定元素是部分还是全部在视口中。
我发现这将确定一个元素是否完全可见,但在尝试确定部分可见性时一直感到困惑。我不想使用jQuery。
基本上,这个想法是页面上会有一个元素可能不在视图中。一旦用户将该元素滚动到视图中,即使是部分滚动,它也应该触发一个事件。我将通过绑定 onscroll 事件来处理事件触发器。我只需要检测正常工作。
function isInViewport(element) {
var rect = element.getBoundingClientRect();
var html = document.documentElement;
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || html.clientHeight) &&
rect.right <= (window.innerWidth || html.clientWidth)
);
}
任何帮助将不胜感激!
回答晚了,但大约一个月前我写了一个函数来做到这一点,它确定一个元素在视口中以百分比为单位的可见量。我在iPhone/iPad上的chrome,Firefox,ie11,ios中对其进行了测试。当元素的 X 百分比(作为 0 到 100 之间的数字)可见时,该函数返回 true。仅确定元素的测量值是否可见,而不确定元素是否隐藏,具有不透明度、可见性等。
const isElementXPercentInViewport = function(el, percentVisible) {
let
rect = el.getBoundingClientRect(),
windowHeight = (window.innerHeight || document.documentElement.clientHeight);
return !(
Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-rect.height) * 100)) < percentVisible ||
Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
)
};
一个基于element.offsetTop
、element.offsetLeft
、element.offsetHeight
、element.offsetWidth
、window.innerWidth
和window.innerHeight
的解决方案
(根据情况,您可能还需要考虑滚动位置)
function isInViewport(element){
if(element.offsetTop<window.innerHeight &&
element.offsetTop>-element.offsetHeight
&& element.offsetLeft>-element.offsetWidth
&& element.offsetLeft<window.innerWidth){
return true;
} else {
return false;
}
}
function test(){
alert(isInViewport(document.getElementById("elem"))?"Yes":"No");
}
#elem{width: 20px; height: 20px; background: red; }
#elem{position: absolute;top: -9px;left: 600px;}
<div id="elem"></div>
<button onclick="test()">Check</button>
function partInViewport(elem) {
let x = elem.getBoundingClientRect().left;
let y = elem.getBoundingClientRect().top;
let ww = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
let hw = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
let w = elem.clientWidth;
let h = elem.clientHeight;
return (
(y < hw &&
y + h > 0) &&
(x < ww &&
x + w > 0)
);
}
document.addEventListener("scroll", ()=>{
let el = document.getElementById("test");
if (partInViewport(el)) {
document.getElementById("container").style.backgroundColor = "green";
} else {
document.getElementById("container").style.backgroundColor = "red";
}
});
#test {
height: 200px;
width: 145px;
background-color: grey;
}
#container {
height: 400px;
width: 345px;
transform: translate(400px, 360px);
background-color: red;
display: grid;
align-items: center;
justify-items: center;
}
body {
height: 1500px;
width: 1500px;
}
<div id="container">
<div id="test"></div>
</div>
我此代码的示例:https://jsfiddle.net/xqpebwtv/27/
如何处理这个问题的现代方法是交叉观察者(IO)。使用 IO,您可以观察(顾名思义)元素并在进入视图时触发操作。您可以设置触发观察者的百分比(例如,视图中的 10%,视图中的 90%,...
我真的很喜欢链接页面中的这个例子,你有 4 个不同的元素。每个都有不同的触发百分比。
let observers = [];
startup = () => {
let wrapper = document.querySelector(".wrapper");
// Options for the observers
let observerOptions = {
root: null,
rootMargin: "0px",
threshold: []
};
// An array of threshold sets for each of the boxes. The
// first box's thresholds are set programmatically
// since there will be so many of them (for each percentage
// point).
let thresholdSets = [
[],
[0.5],
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
[0, 0.25, 0.5, 0.75, 1.0]
];
for (let i = 0; i <= 1.0; i += 0.01) {
thresholdSets[0].push(i);
}
// Add each box, creating a new observer for each
for (let i = 0; i < 4; i++) {
let template = document.querySelector("#boxTemplate").content.cloneNode(true);
let boxID = "box" + (i + 1);
template.querySelector(".sampleBox").id = boxID;
wrapper.appendChild(document.importNode(template, true));
// Set up the observer for this box
observerOptions.threshold = thresholdSets[i];
observers[i] = new IntersectionObserver(intersectionCallback, observerOptions);
observers[i].observe(document.querySelector("#" + boxID));
}
// Scroll to the starting position
document.scrollingElement.scrollTop = wrapper.firstElementChild.getBoundingClientRect().top + window.scrollY;
document.scrollingElement.scrollLeft = 750;
}
intersectionCallback = (entries) => {
entries.forEach((entry) => {
let box = entry.target;
let visiblePct = (Math.floor(entry.intersectionRatio * 100)) + "%";
box.querySelector(".topLeft").innerHTML = visiblePct;
box.querySelector(".topRight").innerHTML = visiblePct;
box.querySelector(".bottomLeft").innerHTML = visiblePct;
box.querySelector(".bottomRight").innerHTML = visiblePct;
});
}
startup();
body {
padding: 0;
margin: 0;
}
svg:not(:root) {
display: block;
}
.playable-code {
background-color: #f4f7f8;
border: none;
border-left: 6px solid #558abb;
border-width: medium medium medium 6px;
color: #4d4e53;
height: 100px;
width: 90%;
padding: 10px 10px 0;
}
.playable-canvas {
border: 1px solid #4d4e53;
border-radius: 2px;
}
.playable-buttons {
text-align: right;
width: 90%;
padding: 5px 10px 5px 26px;
}
.contents {
position: absolute;
width: 700px;
height: 1725px;
}
.wrapper {
position: relative;
top: 600px;
}
.sampleBox {
position: relative;
left: 175px;
width: 150px;
background-color: rgb(245, 170, 140);
border: 2px solid rgb(201, 126, 17);
padding: 4px;
margin-bottom: 6px;
}
#box1 {
height: 300px;
}
#box2 {
height: 175px;
}
#box3 {
height: 350px;
}
#box4 {
height: 100px;
}
.label {
font: 14px "Open Sans", "Arial", sans-serif;
position: absolute;
margin: 0;
background-color: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(0, 0, 0, 0.7);
width: 3em;
height: 18px;
padding: 2px;
text-align: center;
}
.topLeft {
left: 2px;
top: 2px;
}
.topRight {
right: 2px;
top: 2px;
}
.bottomLeft {
bottom: 2px;
left: 2px;
}
.bottomRight {
bottom: 2px;
right: 2px;
}
<template id="boxTemplate">
<div class="sampleBox">
<div class="label topLeft"></div>
<div class="label topRight"></div>
<div class="label bottomLeft"></div>
<div class="label bottomRight"></div>
</div>
</template>
<main>
<div class="contents">
<div class="wrapper">
</div>
</div>
</main>
你的代码说的是:
- 元素的顶部
- 必须位于窗口的顶部下方, 元素的左侧
- 必须位于窗口左侧的右侧,
- 元素的底部必须位于窗口底部的顶部,并且
- 元素的右侧必须位于窗口右侧的左侧
你想要什么:
- 元素的顶部必须低于窗口的
- 顶部,或者元素的底部必须高于窗口的底部,并且 元素的左侧必须位于窗口左侧的右侧,
- 或者元素的右侧必须位于窗口右侧的左侧
中获取您将要的内容,代码应该从这里足够简单。
这应该可以做到,不需要偏移量,因为我们正在比较客户端矩形。
function isPartiallyVisibleInViewport(element, viewport) {
var bound = element.getBoundingClientRect();
var bound2 = viewport.getBoundingClientRect();
return bound.bottom > bound2.top && bound.top < bound2.bottom;
}
此功能仅垂直检查,如果您还想水平检查,则必须扩展:
return bound.bottom > bound2.top && bound.top < bound2.bottom && bound.right > bound2.left && bound.left < bound2.right;
- 将视口底部滚动到元素底部
- 宽度为100%的CSS元素位于视口之外
- CSS3:当页面向下滚动到第一个视口时,是否可以在元素上触发转换
- 将html元素渲染到浏览器视口
- 缩放时使元素适应视口宽度
- 获取元素的编号's视口内的像素
- 获取元素相对于视口顶部的位置
- 当任何块级元素的视口较窄时,添加水平滚动条
- 不会转义视口的绝对定位元素
- 仅当具有相同类的元素的中间使用 jQuery 航点到达视口时,才淡入具有相同类的元素
- Javascript 在视口外的点获取元素
- 在鼠标移动其他元素时移动 svg 视口
- 跨浏览器:如何根据视口高度调整元素的垂直位置
- 当元素到达视口顶部时添加类
- 如何判断视口内元素的哪一部分
- 使用 Javascript,我如何相对于视口的中心缩放元素
- 为什么固定元素在放大(iPad)时会离开视口
- 使元素至少达到视口的高度
- 更改HTML元素'基于视口大小的宽度
- JavaScript检查元素是否在顶视口之外