Task 9: Implement scroll animations and responsive design
- Add IntersectionObserver-based scroll reveal for all sections - Sections start at opacity:0/translateY(24px), animate to visible on scroll - Hero section immediately visible (above fold, no animation) - Staggered child card/item animations with 60ms delay per item - Animations fire once only (observer unobserved after reveal) - Fix hover transform specificity for cards, education, projects - Fix vital-card hover at hero-level specificity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+107
-1
@@ -755,6 +755,72 @@
|
|||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =========================================
|
||||||
|
SCROLL REVEAL ANIMATIONS
|
||||||
|
========================================= */
|
||||||
|
|
||||||
|
.cv-main section {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(24px);
|
||||||
|
transition: opacity 0.6s ease, transform 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-main section.visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero section should be immediately visible (above fold) */
|
||||||
|
.cv-main section.hero {
|
||||||
|
opacity: 1;
|
||||||
|
transform: none;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Staggered child card/item animations */
|
||||||
|
.cv-main section .vital-card,
|
||||||
|
.cv-main section .skill-item,
|
||||||
|
.cv-main section .timeline-entry,
|
||||||
|
.cv-main section .education-card,
|
||||||
|
.cv-main section .project-card,
|
||||||
|
.cv-main section .contact-item {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(16px);
|
||||||
|
transition: opacity 0.5s ease, transform 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-main section.visible .vital-card,
|
||||||
|
.cv-main section.visible .skill-item,
|
||||||
|
.cv-main section.visible .timeline-entry,
|
||||||
|
.cv-main section.visible .education-card,
|
||||||
|
.cv-main section.visible .project-card,
|
||||||
|
.cv-main section.visible .contact-item {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-enable hover transforms at matching specificity */
|
||||||
|
.cv-main section.visible .education-card:hover,
|
||||||
|
.cv-main section.visible .project-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-main section.visible .timeline-entry .timeline-card:hover {
|
||||||
|
transform: scale(1.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero vital cards get their own reveal since hero is always visible */
|
||||||
|
.cv-main .hero .vital-card {
|
||||||
|
opacity: 1;
|
||||||
|
transform: none;
|
||||||
|
transition: box-shadow 0.3s ease, transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cv-main .hero .vital-card:hover {
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
/* =========================================
|
/* =========================================
|
||||||
FOOTER
|
FOOTER
|
||||||
========================================= */
|
========================================= */
|
||||||
@@ -1686,9 +1752,10 @@
|
|||||||
var cvContent = document.getElementById('cv-content');
|
var cvContent = document.getElementById('cv-content');
|
||||||
cvContent.classList.add('revealed');
|
cvContent.classList.add('revealed');
|
||||||
|
|
||||||
// Initialize nav tracking, smooth scroll, and skill gauges after reveal
|
// Initialize nav tracking, smooth scroll, skill gauges, and scroll reveal after reveal
|
||||||
initNavTracking();
|
initNavTracking();
|
||||||
initSkillGauges();
|
initSkillGauges();
|
||||||
|
initScrollReveal();
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1777,6 +1844,45 @@
|
|||||||
gaugeObserver.observe(skillsSection);
|
gaugeObserver.observe(skillsSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =========================================
|
||||||
|
SCROLL REVEAL: Sections & staggered children
|
||||||
|
========================================= */
|
||||||
|
|
||||||
|
function initScrollReveal() {
|
||||||
|
var sections = document.querySelectorAll('.cv-main section');
|
||||||
|
|
||||||
|
var revealObserver = new IntersectionObserver(function(entries) {
|
||||||
|
entries.forEach(function(entry) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
var section = entry.target;
|
||||||
|
section.classList.add('visible');
|
||||||
|
|
||||||
|
// Stagger child cards/items
|
||||||
|
var children = section.querySelectorAll(
|
||||||
|
'.vital-card, .skill-item, .timeline-entry, .education-card, .project-card, .contact-item'
|
||||||
|
);
|
||||||
|
children.forEach(function(child, i) {
|
||||||
|
child.style.transitionDelay = (i * 60) + 'ms';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only animate once — stop observing after reveal
|
||||||
|
revealObserver.unobserve(section);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
threshold: 0.15
|
||||||
|
});
|
||||||
|
|
||||||
|
sections.forEach(function(section) {
|
||||||
|
// Hero is always visible (above the fold), skip it
|
||||||
|
if (section.classList.contains('hero')) {
|
||||||
|
section.classList.add('visible');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
revealObserver.observe(section);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user