Me gustaría que los elementos div aparezcan y desaparezcan al desplazarse sobre ellos cambiando la opacidad. Suena muy simple, pero no puedo hacer que funcione.
El problema que tengo es que los div están en el medio de mi página y no en la parte superior, por lo que scrollTop no debería funcionar, ¿verdad?
var fade = $('.b_wrapper');
var range = 400;
$(window).on('scroll', function() {
var st = $(this).scrollTop();
fade.each(function() {
var offset = $(this).offset().top;
var height = $(this).outerHeight();
offset = offset + height / 1;
$(this).css({
'opacity': 1 - (st + offset - range) / range
});
});
});
.content {
height: 100px;
}
.b_wrapper {
background: lightgreen;
margin-top: 40px;
padding: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<div class="content"></div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
<div class="b_wrapper">
<p>this is a div</p>
</div>
( JsViolín )
Puede utilizar la API Intersection Observer . Observa los cambios en la intersección entre un elemento de destino y su elemento antepasado o la ventana gráfica.
Primero, crea un nuevo observador con opciones:
let options = {
root: null,
threshold: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
}
let observer = new IntersectionObserver(callback, options);
root especifica el elemento antepasado (que lo contiene), por ejemplo, con document.querySelector() , o la ventana gráfica con null .
threshold puede tomar una serie de umbrales de intersección para observar, que usaremos directamente como opacidad para nuestros elementos. Entonces, cada vez que la relación de intersección de un elemento con la ventana gráfica alcanza uno de estos valores, se activa la devolución de llamada. (Puede usar una función aquí para construir la matriz si desea una secuencia más detallada y no desea escribir todo a mano).
A continuación, agregue cada elemento al observador:
for (const target of document.querySelectorAll('.b_wrapper')) {
observer.observe(target);
}
La devolución de llamada es muy simple, ya que podemos usar directamente la relación de intersectionRatio proporcionada como opacidad:
let callback = (entries, observer) => {
entries.forEach((entry) => {
entry.target.style.opacity = entry.intersectionRatio
});
};
Tanto para empezar. Lea la documentación , es excelente y tiene muchos ejemplos.
let callback = (entries, observer) => {
entries.forEach((entry) => {
entry.target.style.opacity = entry.intersectionRatio
});
};
let options = {
root: null,
threshold: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
}
let observer = new IntersectionObserver(callback, options);
for (const target of document.querySelectorAll('.b_wrapper')) {
observer.observe(target);
}
.b_wrapper{
margin: 20px;
padding: 20px;
background: lightgreen;
}
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
<div class="b_wrapper"><p>this is a div</p></div>
Probablemente no sea el mejor, pero aquí está mi intento:
Al desplazarme, compruebo la posición de cada elemento para ver cuál está más centrado
Al cambiar el tamaño de la ventana, actualizo el valor del centro de la pantalla
let centerOfScreen = window.innerHeight / 2;
let pageScroll;
let closestCenteredDivPosition = 999999;
let currentIndex;
let wrappers = document.getElementsByClassName("wrapper");
let positions = [];
for (let e of wrappers) {
positions.push(e.offsetTop + e.offsetHeight / 2);
}
highlightMostCenteredDiv = () => {
pageScroll = document.documentElement.scrollTop || document.body.scrollTop;
let currentValue;
for (let i = 0; i < positions.length; i++) {
currentValue = Math.abs(positions[i] - centerOfScreen - pageScroll);
if (closestCenteredDivPosition > currentValue) {
closestCenteredDivPosition = currentValue;
currentIndex = i;
}
}
if (!document.querySelector(".current")) {
wrappers[currentIndex].classList.add("current");
} else {
if (wrappers[currentIndex] != document.querySelector(".current")) {
document.querySelector(".current").classList.remove("current");
wrappers[currentIndex].classList.add("current");
}
}
closestCenteredDivPosition = 999999;
}
highlightMostCenteredDiv();
document.addEventListener("scroll", highlightMostCenteredDiv)
window.addEventListener("resize", () => {
centerOfScreen = window.innerHeight / 2;
})
body {
margin: 0;
}
.wrapper {
background-color: orange;
height: 100px;
width: 100%;
margin: 50px 0;
opacity: 0.3;
transition: opacity 1s ease;
}
.current {
opacity: 1;
}
<div class="wrapper"></div>
<div class="wrapper"></div>
<div class="wrapper"></div>
<div class="wrapper"></div>
<div class="wrapper"></div>
<div class="wrapper"></div>
<div class="wrapper"></div>
<div class="wrapper"></div>