iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
JavaScript

JavaScript 從入門到進階:結合 Three.js × GSAP 打造互動網頁系列 第 19 篇

Day19 把 GSAP 全部用起來:打造我的 JavaScript 探索基地

  • 分享至 

  • xImage
  •  

一、組合起來吧

前面幾天一直在學 GSAP 的不同功能,但如果每次都只是 gsap.to() 然後看一個方塊移動,好像還是有點無聊,所以今天直接來做一個完整的小作品。這次會把前面學過的所有功能以及動畫效果全部放進同一個網頁裡。

二、實作範例

這裡我們要製作一個簡易網頁,在進入網頁的同時文字會滑動進入畫面,且我製作了一個按鈕,點擊即可觸發事件,會有一個小視窗跳出來,接著在往下滑的同時,動畫跟文字都會依序出現

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript 從入門到進階:結合 Three.js × GSAP 打造互動網頁</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

    <section class="hero">
        <div class="hero-content">
            <p class="tag">MY JAVASCRIPT WORLD</p>

            <h1>
                開始我的<br>
                <span>JavaScript 冒險</span>
            </h1>

            <p class="description">
                從 JavaScript 到 GSAP,
                一步一步打造屬於自己的互動網頁。
            </p>

            <button class="start-btn" id="startBtn">
                開始探索 ↓
            </button>
        </div>
    </section>

    <div class="message" id="message">
        歡迎來到我的 JavaScript 世界!
    </div>

    <section class="skills">
        <div class="section-title">
            <p>WHAT I LEARNED</p>
            <h2>我的技能工具箱</h2>
        </div>

        <div class="skill-container">
            <div class="skill-card">
                <div class="number">01</div>
                <h3>JavaScript</h3>
                <p>
                    用 JavaScript 讓網頁開始具有互動性,
                    也開始理解 DOM、Event 和資料操作。
                </p>
            </div>

            <div class="skill-card">
                <div class="number">02</div>
                <h3>GSAP</h3>
                <p>
                    使用 GSAP 控制網頁動畫,
                    讓原本靜止的元素開始動起來。
                </p>
            </div>

            <div class="skill-card">
                <div class="number">03</div>
                <h3>ScrollTrigger</h3>
                <p>
                    讓使用者的滾動也可以成為動畫的一部分,
                    讓網頁開始有互動感。
                </p>
            </div>
        </div>
    </section>

    <section class="ending">
        <div class="ending-content">
            <p class="ending-tag">NEXT STEP</p>

            <h2>
                下一站
                <span>Three.js</span>
            </h2>

            <p>
                如果 2D 動畫已經這麼有趣,
                那麼 3D 世界又會變成什麼樣子?
            </p>

            <button class="next-btn">
                Enter the 3D World →
            </button>
        </div>
    </section>

    <script src="index.js" type="module"></script>
</body>
</html>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    background: #111;
    color: white;
}

.hero {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    background: #111;
}

.hero-content {
    max-width: 800px;
}

.tag,
.ending-tag {
    font-size: 14px;
    letter-spacing: 4px;
    margin-bottom: 25px;
}

.hero h1 {
    font-size: 72px;
    line-height: 1.1;
    margin-bottom: 30px;
}

.hero h1 span {
    color: #8b5cf6;
}

.description {
    font-size: 20px;
    line-height: 1.8;
    color: #aaa;
    margin-bottom: 40px;
}

button {
    border: none;
    padding: 16px 32px;
    border-radius: 50px;
    font-size: 16px;
    cursor: pointer;
}

.start-btn {
    background: #8b5cf6;
    color: white;
}

.next-btn {
    background: #111;
    color: white;
}

.message {
    position: fixed;
    top: 30px;
    left: 50%;
    transform: translateX(-50%);
    padding: 15px 30px;
    border-radius: 50px;
    background: white;
    color: #111;
    opacity: 0;
    pointer-events: none;
    z-index: 100;
}

.skills {
    min-height: 100vh;
    padding: 150px 10%;
    background: #181818;
}

.section-title {
    text-align: center;
    margin-bottom: 80px;
}

.section-title p {
    color: #8b5cf6;
    letter-spacing: 4px;
    margin-bottom: 15px;
}

.section-title h2 {
    font-size: 48px;
}

.skill-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 30px;
}

.skill-card {
    padding: 40px;
    min-height: 300px;
    border-radius: 20px;
    background: #222;
    border: 1px solid #333;
}

.number {
    color: #8b5cf6;
    font-size: 18px;
    margin-bottom: 50px;
}

.skill-card h3 {
    font-size: 30px;
    margin-bottom: 20px;
}

.skill-card p {
    color: #aaa;
    line-height: 1.8;
}

.ending {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    background: #8b5cf6;
}

.ending-content {
    max-width: 700px;
}

.ending h2 {
    font-size: 64px;
    margin-bottom: 30px;
}

.ending h2 span {
    color: #111;
}

.ending-content > p {
    font-size: 20px;
    line-height: 1.8;
    margin-bottom: 40px;
}
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

const heroTimeline = gsap.timeline();

heroTimeline
    .from(".tag", {
        y: 30,
        opacity: 0,
        duration: 0.6,
        ease: "power2.out"
    })
    .from(".hero h1", {
        y: 80,
        opacity: 0,
        duration: 1,
        ease: "power3.out"
    })
    .from(".description", {
        y: 30,
        opacity: 0,
        duration: 0.7,
        ease: "power2.out"
    })
    .from(".start-btn", {
        y: 20,
        opacity: 0,
        scale: 0.8,
        duration: 0.6,
        ease: "back.out(1.7)"
    });

const startBtn = document.querySelector("#startBtn");
const message = document.querySelector("#message");

startBtn.addEventListener("click", function() {
    gsap.to(message, {
        y: 20,
        opacity: 1,
        duration: 0.5,
        ease: "power2.out" //觸發事件,跳出視窗
    });

    gsap.to(message, {
        y: 0,
        opacity: 0,
        duration: 0.5,
        delay: 2,
        ease: "power2.in"
    });
});

gsap.from(".section-title", {
    y: 60,
    opacity: 0,
    duration: 1,
    ease: "power3.out",
    scrollTrigger: {
        trigger: ".skills",
        start: "top 70%"
    }
});

gsap.from(".skill-card", {
    y: 100,
    opacity: 0,
    duration: 0.8,
    stagger: 0.2,
    ease: "power3.out",
    scrollTrigger: {
        trigger: ".skill-container",
        start: "top 75%"
    }
});

const endingTimeline = gsap.timeline({
    scrollTrigger: {
        trigger: ".ending",
        start: "top 70%"
    }
});

endingTimeline
    .from(".ending-tag", {
        y: 30,
        opacity: 0,
        duration: 0.5
    })
    .from(".ending h2", {
        y: 60,
        opacity: 0,
        duration: 0.8,
        ease: "power3.out"
    })
    .from(".ending-content > p", {
        y: 30,
        opacity: 0,
        duration: 0.6
    })
    .from(".next-btn", {
        scale: 0.8,
        opacity: 0,
        duration: 0.6,
        ease: "back.out(1.7)"
    });

image
底下那一行字正在往上進入頁面,帶有點透明。
image
這裡有製作一個觸發事件的按鈕,點擊跳出小視窗
image
接著往下滑內容都會有依序的動畫進入頁面,因為設定了scrollTrigger
image
最後做一個結束畫面
image

三、使用了什麼

做到這裡,可以回頭看一下,我們不是為了使用語法而使用語法,而是每個功能都有自己的工作。而且我們至今所學都有好好用上,是不是很好玩!!

GSAP功能 在做什麼
from() 設定元素一開始的狀態
timeline() 控制多個動畫的順序
stagger 讓技能卡片依序出現
ease 讓動畫速度更自然
ScrollTrigger 讓動畫跟著使用者滾動觸發

四、結論

做到這裡,有沒有真的感受到自己將一個網站做出來,然後搭配動畫效果進場,為網頁增添了樂趣,GSAP 不只是讓網頁「動起來」,而是可以開始控制整個網頁的節奏。

而下一站,我想玩的東西就更不一樣了。如果現在的網頁已經可以做出這些動畫,那能不能直接在網頁裡做一個 3D 世界?

下一篇,正式進入 Three.js。


上一篇
Day18 不用按按鈕:讓滾動控制動畫
下一篇
Day20 網頁也能做 3D?第一次走進 Three.js 的世界
系列文
JavaScript 從入門到進階:結合 Three.js × GSAP 打造互動網頁 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言