gsap timeline示例-实现滚动切换手机颜色

前言

最近使用gsap有点上瘾。看过一个手机官网滚动切换手机颜色的效果,初次见还是很炫。所以呢,就去研究了下,发现也不过如此。我们现在使用gsap来实现它。

首先来看最终效果:

gsap timeline示例-实现滚动切换手机颜色

实现原理

1. 首先整个dom结构被分为两个部分:背景及其文案、手机图片
2. 通过绝对定位让三个背景、三张图片分别重叠,保证元素在同一位置
3. 通过切换不同组的高度来展示不同的背景与图片

思路有了,那就来实现它

实现步骤

DOM结构

		<section class="change-color bg-black relative overflow-hidden h-screen">
            <div class="images absolute w-full h-screen z-10">
                <div class="image orange h-full w-1/2 absolute overflow-hidden left-1/3 top-0">
                    <figure  style="background-image: url(https://photographer-files.s3.us-east-2.amazonaws.com/orange.png);"></figure>
                </div>
                <div class="image blue h-0 w-1/2 absolute overflow-hidden left-1/3 top-0">
                    <figure  style="background-image: url(https://photographer-files.s3.us-east-2.amazonaws.com/blue.png);"></figure>
                </div>
                <div class="image black h-0 w-1/2 absolute overflow-hidden left-1/3 top-0">
                    <figure  style="background-image: url(https://photographer-files.s3.us-east-2.amazonaws.com/black.png);"></figure>
                </div>
            </div>
            <div class="background absolute w-full h-screen">
                <div class="text-box orange absolute overflow-hidden bg-orange-300 h-full w-1/2">
                    <div class="text absolute h-screen left-1/2 top-0 flex items-center" style="transform: translate(-50%, 0)">
                        <strong class="text-orange-500 text-9xl font-bold">Orange</strong>
                    </div>
                </div>
                <div class="text-box blue absolute overflow-hidden bg-blue-200 h-0 w-1/2">
                    <div class="text absolute h-screen left-1/2 top-0 flex items-center" style="transform: translate(-50%, 0)">
                        <strong class="text-blue-900 text-9xl font-bold">Blue</strong>
                    </div>
                </div>
                <div class="text-box black absolute overflow-hidden bg-gray-700 h-0 w-1/2 ">
                    <div class="text absolute h-screen left-1/2 top-0 flex items-center" style="transform: translate(-50%, 0)">
                        <strong class="text-gray-900 text-9xl font-bold">Black</strong>
                    </div>
                </div>
            </div>
        </section>

tips: 使用tailwind,具体样式应该一看class就能看懂

需要注意

  1. 图片使用的是背景而不是img,因为图片会根据高度变化而变化;
  2. 除了第一组橙色,其他两组初始高度都为0;
  3. 需要通过z-index来控制层级,这样能够在动画时不至于调整上一组的高度。

图片增加了一点样式:

.change-color figure{
    width: 461px;
    height: 604px;
    transform: translate(0, 20%);
}

现在我们就能通过控制台调整高度实现一定的效果了:
在这里插入图片描述

动画实现

首先我们要清楚,我们需要两组动画
一组用来固定整个结构
一组用来实现高度变化

	// 用来固定
	const section = document.querySelector(".change-color");
 	gsap.to(section, {
        scrollTrigger: {
            trigger: section,
            start: "top top",
            end: "300% top",
            pin: true,
            //markers: true,
        }
    });

使用gsap.timeline来执行高度变化的动画:

	const imgBlue = section.querySelector('.image.blue');
    const imgBlack = section.querySelector('.image.black');
    const textBlue = section.querySelector('.text-box.blue');
    const textBlack = section.querySelector('.text-box.black');
    
    // 创建一个时间线,还是使用section作为触发器
    const tl = gsap.timeline({
        scrollTrigger: {
          trigger: section,
          start: "top top",
          end: "300% top",
          scrub: true // 是否重复执行,这个能保证我们向上滚动时让动画反着执行
        }
    });
    
    /**
     * .to() 表示目标属性变化到什么状态
     * [textBlue, imgBlue, ...] 表示同时执行textBlue、imgBlue
     * { height: '100%', ... } 表示目标最终的状态
     * .to().to() 表示执行完前一个动画后执行下一个
     * 
     */ 
    tl.to([textBlue, imgBlue], { height: '100%' })
    .to([textBlack, imgBlack], { height: '100%' });

注意点

我们两个动画的end属性的第一个值都是300%,是单个组元素高度的三倍,是因为我们需要在滚动的时候保证高度变化的高度与滚动距离一致。当然也可以是其他值,更详细的属性解释,可以参照苹果官网动画解析之airpods滚动光影效果

这样,我们的主要功能就全部实现了,但总感觉有点死板,那不如浅浅的再加一个进入的动画:

初始化动画

	const imgOrange = section.querySelector('.image.orange');
	
 	gsap.from(imgOrange, { 
        x: 800,
        transform: 'scale(0.8)',
        duration: 1.4,
        opacity: 0,
        ease: "expo.out",
        scrollTrigger: {
            trigger: section,
            start: "top top+=50%", // 这个保证只要元素进入页面,就能执行动画
            // markers: true,
        }
    })

这里使用from 表示目标元素从配置的属性恢复到我们css控制的初始状态
从这里也能看出来gsap创建动画的便利性

这样当页面进入的时候手机图片就会从右边想左移动的一个动画,同时也会变化透明度跟缩放比例。

完整代码

		<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
    <title>GSAP+TIMELINE</title>
</head>
<body>
    <main class="bg-slate-300 animate-demo ">
    	<!-- 这个是用来占位的,不知道为什么,前面必须要有一个有高度的元素才能实现滚动的功能 -->
    	<section style="height: 1px;" class="bg-black"></section>
        <section class="change-color bg-black relative overflow-hidden h-screen">
            <div class="images absolute w-full h-screen z-10">
                <div class="image orange h-full w-1/2 absolute overflow-hidden left-1/3 top-0">
                    <figure  style="background-image: url(https://photographer-files.s3.us-east-2.amazonaws.com/orange.png);"></figure>
                </div>
                <div class="image blue h-0 w-1/2 absolute overflow-hidden left-1/3 top-0">
                    <figure  style="background-image: url(https://photographer-files.s3.us-east-2.amazonaws.com/blue.png);"></figure>
                </div>
                <div class="image black h-0 w-1/2 absolute overflow-hidden left-1/3 top-0">
                    <figure  style="background-image: url(https://photographer-files.s3.us-east-2.amazonaws.com/black.png);"></figure>
                </div>
            </div>
            <div class="background absolute w-full h-screen">
                <div class="text-box orange absolute overflow-hidden bg-orange-300 h-full w-1/2">
                    <div class="text absolute h-screen left-1/2 top-0 flex items-center" style="transform: translate(-50%, 0)">
                        <strong class="text-orange-500 text-9xl font-bold">Orange</strong>
                    </div>
                </div>
                <div class="text-box blue absolute overflow-hidden bg-blue-200 h-0 w-1/2">
                    <div class="text absolute h-screen left-1/2 top-0 flex items-center" style="transform: translate(-50%, 0)">
                        <strong class="text-blue-900 text-9xl font-bold">Blue</strong>
                    </div>
                </div>
                <div class="text-box black absolute overflow-hidden bg-gray-700 h-0 w-1/2 ">
                    <div class="text absolute h-screen left-1/2 top-0 flex items-center" style="transform: translate(-50%, 0)">
                        <strong class="text-gray-900 text-9xl font-bold">Black</strong>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.4/gsap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.4/ScrollTrigger.min.js"></script>
    <script>
        function ready(fn) {
            if (document.readyState !== 'loading') {
                fn();
            } else {
                document.addEventListener('DOMContentLoaded', fn);
            }
        }
        function changeColor() {  
            const section = document.querySelector(".change-color");

            const imgOrange = section.querySelector('.image.orange');
            const imgBlue = section.querySelector('.image.blue');
            const imgBlack = section.querySelector('.image.black');

            const textBlue = section.querySelector('.text-box.blue');
            const textBlack = section.querySelector('.text-box.black');
            
            gsap.to(section, {
                scrollTrigger: {
                    trigger: section,
                    start: "top top",
                    end: "300% top",
                    pin: true,
                    //markers: true,
                }
            });
            gsap.from(imgOrange, { 
                x: 800,
                transform: 'scale(0.8)',
                duration: 1.4,
                opacity: 0,
                ease: "expo.out",
                scrollTrigger: {
                    trigger: section,
                    start: "top top+=50%",
                    // markers: true,
                }
            })
            const tl = gsap.timeline({
                scrollTrigger: {
                trigger: section,
                start: "top top",
                end: "300% top",
                scrub: true
                }
            });
            
            /**
             * .to() 表示目标属性变化到什么状态
             * [textBlue, imgBlue, ...] 表示同时执行textBlue、imgBlue
             * { height: '100%', ... } 表示目标最终的状态
             * .to().to() 表示执行完前一个动画后执行下一个
             * 
             */
            tl.to([textBlue, imgBlue], { height: '100%' })
            .to([textBlack, imgBlack], { height: '100%' });
        }

        function init() {  
            gsap.registerPlugin(ScrollTrigger);
            changeColor();
        }
        ready(init);
    </script>
</body>
</html>

拿去就能跑,你可以试试~

写在最后

感谢你的阅读,如果你觉得有用,欢迎评论、点赞、转发~
当然也希望你能关注我的公众号:前端大乱炖
在这里插入图片描述

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yanyi24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值