Sync: implement scroll-reveal animations for cards with responsive visibility adjustments
This commit is contained in:
@@ -97,6 +97,17 @@ img, video { max-width: 100%; display: block; }
|
|||||||
a { color: inherit; text-decoration: none; transition: color var(--transition); }
|
a { color: inherit; text-decoration: none; transition: color var(--transition); }
|
||||||
a:hover { color: var(--color-primary); }
|
a:hover { color: var(--color-primary); }
|
||||||
|
|
||||||
|
/* ── Scroll-reveal animation classes ───────────────────────── */
|
||||||
|
.scroll-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(24px);
|
||||||
|
}
|
||||||
|
.scroll-visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
transition: opacity .5s ease, transform .5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
/* Smooth theme transition */
|
/* Smooth theme transition */
|
||||||
body,
|
body,
|
||||||
.site-header,
|
.site-header,
|
||||||
@@ -4128,6 +4139,14 @@ p:last-child { margin-bottom: 0; }
|
|||||||
50% { transform: translateY(-50%) scale(1.08); }
|
50% { transform: translateY(-50%) scale(1.08); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Responsive scale-down ── */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.cam-stage { transform: scale(0.85); transform-origin: center center; }
|
||||||
|
}
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.cam-stage { transform: scale(0.72); transform-origin: center center; }
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Reduced-motion ── */
|
/* ── Reduced-motion ── */
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.cam-subject--2, .cam-subject--3,
|
.cam-subject--2, .cam-subject--3,
|
||||||
|
|||||||
@@ -134,17 +134,31 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const cards = document.querySelectorAll('.oribi-card, .feature-card, .industry-card, .pricing-card, .value-card, .platform-row');
|
const cards = document.querySelectorAll('.oribi-card, .feature-card, .industry-card, .pricing-card, .value-card, .platform-row');
|
||||||
if (cards.length && 'IntersectionObserver' in window &&
|
if (cards.length && 'IntersectionObserver' in window &&
|
||||||
!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||||
cards.forEach(c => { c.style.opacity = '0'; c.style.transform = 'translateY(24px)'; c.style.transition = 'opacity .5s ease, transform .5s ease'; });
|
cards.forEach(c => c.classList.add('scroll-hidden'));
|
||||||
const io = new IntersectionObserver((entries) => {
|
/* Use rAF to ensure the class is applied before observing – avoids
|
||||||
entries.forEach(entry => {
|
Safari quirk where elements already in-viewport don't fire. */
|
||||||
if (entry.isIntersecting) {
|
requestAnimationFrame(() => {
|
||||||
entry.target.style.opacity = '1';
|
const io = new IntersectionObserver((entries) => {
|
||||||
entry.target.style.transform = 'translateY(0)';
|
entries.forEach(entry => {
|
||||||
io.unobserve(entry.target);
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.classList.remove('scroll-hidden');
|
||||||
|
entry.target.classList.add('scroll-visible');
|
||||||
|
io.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { threshold: 0.05, rootMargin: '0px 0px 80px 0px' });
|
||||||
|
cards.forEach(c => io.observe(c));
|
||||||
|
});
|
||||||
|
/* Safety net: reveal any still-hidden elements after 4 s so content
|
||||||
|
is never permanently invisible (e.g. iOS Safari edge-cases). */
|
||||||
|
setTimeout(() => {
|
||||||
|
cards.forEach(c => {
|
||||||
|
if (c.classList.contains('scroll-hidden')) {
|
||||||
|
c.classList.remove('scroll-hidden');
|
||||||
|
c.classList.add('scroll-visible');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, { threshold: 0.1, rootMargin: '0px 0px 60px 0px' });
|
}, 4000);
|
||||||
cards.forEach(c => io.observe(c));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user