Sync: implement scroll-reveal animations for cards with responsive visibility adjustments

This commit is contained in:
Matt Batchelder
2026-02-21 16:47:11 -05:00
parent 66b6b9cbfb
commit 8f43b6c584
2 changed files with 42 additions and 9 deletions

View File

@@ -97,6 +97,17 @@ img, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; transition: color var(--transition); }
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 */
body,
.site-header,
@@ -4128,6 +4139,14 @@ p:last-child { margin-bottom: 0; }
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 ── */
@media (prefers-reduced-motion: reduce) {
.cam-subject--2, .cam-subject--3,

View File

@@ -134,17 +134,31 @@ document.addEventListener('DOMContentLoaded', () => {
const cards = document.querySelectorAll('.oribi-card, .feature-card, .industry-card, .pricing-card, .value-card, .platform-row');
if (cards.length && 'IntersectionObserver' in window &&
!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'; });
const io = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
io.unobserve(entry.target);
cards.forEach(c => c.classList.add('scroll-hidden'));
/* Use rAF to ensure the class is applied before observing avoids
Safari quirk where elements already in-viewport don't fire. */
requestAnimationFrame(() => {
const io = new IntersectionObserver((entries) => {
entries.forEach(entry => {
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' });
cards.forEach(c => io.observe(c));
}, 4000);
}
});