React + GSAP + ScrollTrigger + Vite ==> 炫酷3D动画网页 -- 上篇

3,554 阅读4分钟

该项目由React + vite 搭建 基于GSAP和ScrollTrigger实现炫酷3D动画网页

动画效果可以看gif图或者查看 线上地址仓库 2023-09-21 15.24.08.gif

本期带大家手把手实现一个基于GSAP和ScrollTrigger的炫酷3D动画网页,但是考虑到完全讲解篇幅过长,打算分几篇文章来更加细致讲解

这篇文章主要讲解以下部分

  • 项目搭建 React + Vite
  • 主要定义:root(根伪类)和一些全局的css样式和规则
  • 检测浏览器是否支持CSS变量
  • 加载图片资源loading效果
  • 封面文字实现效果

项目搭建

该项目小而精,就选vite来极速开发 而且配置也比较简单 开发体验也不错(热更新快)

npm create vite@latest project-name

本项目没啥可维护性 主要求快 也就不需要ts 选SWC提高编译速度 Img

启动project!

cd project-name
npm i
npm run dev

Img

定义全局规则

定义规范

我们可以创建一个style文件夹,再创建base.less(css/scss)文件来储存全局定义的css样式,之后可以用index.less文件将这些style文件夹的样式统一导出 像这样 Img

根伪类

定义根伪类(:root)的好处在于它允许创建全局的CSS变量(也称为自定义属性),这些变量可以在整个样式表中使用 同时也易于修改和定制,增强可读性

//base.less
*,
*::after,
*::before {
	box-sizing: border-box;
}
:root {
	font-size: 16px;
	--color-text: #fff;
	--color-bg: #000;
	--color-link: #fff;
	--color-link-hover: #907030;
	--color-title: #907030;
	--perspective: 1500px;
	--grid-item-ratio: 1.5;
	--grid-width: 100%;
	--grid-height: auto;
	--grid-gap: 2vw;
	--grid-columns: 4;
	--grid-inner-scale: 1;
}

如果要定义一个背景颜色我们只需要

background: var(--color-bg);

全局使用标准盒模型 box-sizing: border-box;使元素的宽度和高度包括边框和内边距

检测浏览器是否支持CSS变量

为什么要做这一步呢? 其实现代大多数浏览器基本的css属性都支持,但不乏有些,,, 不同的浏览器对CSS特性的支持程度不同,也可以通过这个网站这个细致查看Can I use ___?

为了检测浏览器是否支持CSS变量 以便在不同浏览器上提供一致的用户体验、动态调整样式和优化性能 可以通过supportsCssVars检测

主要做了一下操作

  • 设置页面支持 JavaScript 的标志:document.documentElement.className = 'js' 将网页的根元素的 className 属性设置为 'js',这通常用于标识页面已加载 JavaScript,以便在 CSS 中可以根据是否支持 JavaScript 来应用不同的样式
  • temp储存元素用于动态添加 CSS 规则
  • 给这个temp添加一个innerHTML属性并赋值一个css规则
  • isSupport储存是否支持(boolean) 判断window.CSS是否支持这个css规则并转化为boolean (!!)
export const supportsCssVars = function () {
	document.documentElement.className = 'js'
	let temp = document.createElement('style')
	temp.innerHTML = 'root: { --tmp-var: bold; }'
	document.head.appendChild(temp)
	const isSupport = !!(
		window.CSS &&
		window.CSS.supports &&
		window.CSS.supports('font-weight', 'var(--tmp-var)')
	)
	temp.parentNode.removeChild(temp)
	return isSupport
}

使用

useEffect(() => {
    supportsCssVars() || alert('该浏览器不支持css变量 请换个')
}, [])

加载图片资源loading效果

平时开发中比较常见的写法,请求数据的时候加个loading,待资源加载后再把这个loading隐藏掉 显示应有的内容 我们图片资源也比较多,所以还是简单写一个呼吸loading 效果类似 Img

主要是俩个地方

  • 关键帧loaderAnim
    • opacity 元素从不透明度 0 —> 1
    • scale3d 水平、垂直方向大小变为原来的一半
  • 动画 animation: loaderAnim 0.7s linear infinite alternate forwards;
    • loaderAnim动画持续0.7s 速度匀速变化 无限循环 每次循环后反向来回运动
    • 具体动画属性可查看mdn animation - MDN Web Docs
/* 页面loading */
.loading::before,
.loading::after {
	content: '';
	position: fixed;
	z-index: 1000;
}
.loading::before {
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: var(--color-bg);
}
.loading::after {
	top: 50%;
	left: 50%;
	width: 60px;
	height: 60px;
	margin: -30px 0 0 -30px;
	border-radius: 50%;
	opacity: 0.4;
	background: var(--color-link);
	animation: loaderAnim 0.7s linear infinite alternate forwards;
}
@keyframes loaderAnim {
	to {
		opacity: 1;
		transform: scale3d(0.5, 0.5, 1);
	}
}

loading!!

function App() {
	const [loading, setLoading] = useState(true)
	useEffect(() => {
		supportsCssVars() || alert('该浏览器不支持css变量 请换个')
		doSomething(()=>{
            /* ... */
            setLoading(false)
        })
	}, [])
	if (loading) return <div className="loading"></div>
    return <></>

封面文字实现效果

原型图是这样的: Img

这个实现比较简单 主要有两点

  • 布局用grid
    • place-items: center; display: grid; 俩行实现垂直居中
  • font-size用clamp兼容性处理
    • 属性font-size: clamp( , , ) 有三个值,分别是最小值、首选值和最大值
.intro {
	height: calc(100vh - 3rem);
	text-align: center;
	place-items: center;
	display: grid;
	margin-bottom: 30vh;
}
.intro__title {
	place-items: center;
	margin: 0;
	line-height: 0.9;
	display: grid;
	margin-top: 15vh;
	font-weight: 400;
}
.intro__title-pre {
	font-size: clamp(2rem, 8vw, 5rem);
	color: var(--color-title);
	text-transform: uppercase;
}
.intro__title-sub {
	font-size: clamp(1.5rem, 20vw, 8rem); /* clamp分别是最小值、首选值和最大值 */
	max-width: 15ch;
	margin: 0 auto;
}
.intro__info {
	max-width: 20ch;
	opacity: 0.6;
	margin-bottom: 4rem;
	padding-bottom: 1rem;
	line-height: 1.2;
	align-self: end;
}
<div>
    <main>
        <div className="intro">
            <h1 className="intro__title">
                <span className="intro__title-pre">On-Scroll</span>
                <span className="intro__title-sub">Perspective Grid Animations</span>
            </h1>
            <span className="intro__info">Scroll moderately to fully experience the animations</span>
        </div>
    </main>
</div>

今天的任务就圆满结束啦 有收获可以点赞收藏哦~

推荐文章