欢迎来到哈比村
2026-01-07
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Image Zoom in with ScrollTrigger</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/modern-normalize/3.0.1/modern-normalize.min.css"
/>
<style>
:root {
--black: #1f1f1f;
--white: #fff;
}
body {
background-color: var(--black);
color: var(--white);
font-family: "Roboto", sans-serif;
font-optical-sizing: auto;
font-size: 20px;
line-height: 1.5;
}
.hero__content {
height: 100vh;
overflow-x: hidden;
width: 100%;
}
.hero__bg {
background-image: url("https://fecoder-pic-1302080640.cos.ap-nanjing.myqcloud.com/hobbiton.jpg");
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
filter: blur(3px) brightness(1.5);
/* initial fog */
height: 100vh;
width: 100%;
will-change: filter;
}
.hero__title {
color: var(--black);
filter: blur(10px);
font-size: clamp(3.125rem, 17.321vw + -1.357rem, 12.5rem);
line-height: clamp(4.688rem, 21.363vw + -0.84rem, 16.25rem);
left: 50%;
margin: 0;
opacity: 0;
padding: 0;
position: absolute;
top: 50vh;
transform: translate(-50%, -50%) scale(0.5);
z-index: 100;
}
.hero__cover {
--overlay-opacity: 1;
position: absolute;
left: 0;
top: 0;
height: 100vh;
width: 100vw;
perspective: 500px;
overflow: hidden;
z-index: 2;
}
.hero__cover::after {
background: radial-gradient(circle, rgba(0, 0, 0, 0) 20%, black 90%);
content: "";
inset: 0;
opacity: var(--overlay-opacity);
position: absolute;
pointer-events: none;
}
.hero__cover-img {
height: 100%;
-o-object-fit: cover;
object-fit: cover;
width: 100%;
pointer-events: none;
}
.section {
max-width: 600px;
margin: 0 auto;
padding: 100px 0;
}
.hobbiton {
position: relative;
}
.hobbiton::after {
background: radial-gradient(
circle,
rgba(0, 0, 0, 0) 40%,
rgba(0, 0, 0, 0.7) 90%
);
content: "";
inset: 0;
opacity: var(--overlay-opacity);
position: absolute;
pointer-events: none;
}
.hobbiton-img {
height: 100vh;
-o-object-fit: cover;
object-fit: cover;
width: 100%;
}
</style>
</head>
<body>
<main>
<div class="hero-container">
<section class="hero">
<div class="hero__content">
<div class="hero__bg"></div>
<h1 class="hero__title font-bold">Hobbiton</h1>
</div>
<div class="hero__cover">
<img
class="hero__cover-img"
src="https://fecoder-pic-1302080640.cos.ap-nanjing.myqcloud.com/hobbit-hole.webp"
alt=""
/>
</div>
</section>
</div>
</main>
<script src="https://unpkg.com/gsap@3/dist/gsap.min.js"></script>
<script src="https://unpkg.com/gsap@3/dist/ScrollSmoother.min.js"></script>
<script src="https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js"></script>
<script src="https://unpkg.com/gsap@3/dist/SplitText.min.js"></script>
<script>
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
ScrollSmoother.create({
smooth: 1,
effects: true,
normalizeScroll: true,
});
gsap
.timeline({
scrollTrigger: {
trigger: ".hero-container",
start: "top top",
end: "+=150%",
pin: true,
scrub: 1,
// markers: true
},
})
.to(".hero__cover-img", {
scale: 2,
z: 350,
transformOrigin: "center center",
ease: "power1.inOut",
})
.to(
".hero__cover",
{
"--overlay-opacity": 0,
ease: "power1.inOut",
},
"<" // sync with image zoom
)
.to(
".hero__bg",
{
scale: 1.1,
filter: "blur(0px) brightness(1)",
ease: "power1.inOut",
},
"<"
)
.to(
".hero__title",
{
scale: 1,
xPercent: -50,
yPercent: -50,
opacity: 1,
filter: "blur(0px)",
ease: "power1.inOut",
},
"<"
);
const splitLetters = SplitText.create(
document.querySelector(".opacity-reveal")
);
gsap.set(splitLetters.chars, { opacity: "0.2", y: 0 });
gsap
.timeline({
scrollTrigger: {
trigger: ".section-stick",
pin: true,
start: "center center",
end: "+=1500",
//markers: true,
scrub: 1,
},
})
.to(splitLetters.chars, {
opacity: "1",
duration: 1,
ease: "none",
stagger: 1,
})
.to({}, { duration: 10 })
.to(".opacity-reveal", {
opacity: "0",
scale: 1.2,
duration: 50,
});
</script>
</body>
</html>
