首页特效-极光背景
首页展示极光动画历程
tip
该效果来源自 Aceternity UI , 作者秀肌肉的一个舞台, 效果是怎么炫酷怎么来, 没有统一的设计语言, 没有组件分类……
作为前端小白的笔者, 移植时属实踩了不少坑, 下面的顺序是最后整理的正确顺序
废话不多说, 先看效果图
组件依赖
Tailwind CSS
: 非常流行的可插件样式的CSS框架Framer motion
: 基于React的用来高效实现各种交互和动画效果的开源库
Tailwind CSS配置
https://ui.shadcn.com/docs/installation/manual#add-tailwind-css
danger
注意, 每次修改配置文件后, 启动前执行清除缓存, 否则可能导致配置不生效 npm cache clear --force
1. 安装依赖
pnpm add tailwindcss-animate class-variance-authority clsx tailwind-merge lucide-react
// 样式配置文件初始化
pnpm tailwindcss init -p
2. 路径配置
@site
: 表示项目根目录
@site/tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
}
}
- 别名
@
是首选项, 也可以根据需要使用其他别名
3. 基础配置
@site/tailwind.config.js
/** @type {import('tailwindcss').Config} */
const {
default: flattenColorPalette,
} = require("tailwindcss/lib/util/flattenColorPalette");
module.exports = {
content: [
"./src/**/*.{md,mdx,js,jsx,ts,tsx}",
"./docs/**/*.{md,mdx,js,jsx,ts,tsx}",
"./blog/**/*.{md,mdx,js,jsx,ts,tsx}",
],
darkMode: "class",
theme: {
extend: {
animation: {
aurora: "aurora 60s linear infinite",
},
keyframes: {
aurora: {
from: {
backgroundPosition: "50% 50%, 50% 50%",
},
to: {
backgroundPosition: "350% 50%, 350% 50%",
},
},
},
},
},
plugins: [
addVariablesForColors,
require("tailwindcss-animate"),
],
corePlugins: {
preflight: false, // 禁用 Tailwind 的基础样式重置
},
// important: '#tailwind-wrapper', // 增加所有 Tailwind 类的优先级
}
function addVariablesForColors({ addBase, theme }: any) {
let allColors = flattenColorPalette(theme("colors"));
let newVars = Object.fromEntries(
Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
);
addBase({
":root": newVars,
});
}
tip
corePlugins:{preflight: false,},
- 禁用 Tailwind 的基础样式重置
这里需要 强调一下, 是解决 TailWind
基础样式与脚手架样式冲突的关键点
4. 全局样式配置
learn more about using CSS variables for theming in the theming section.
@site/src/css/custom.css
@tailwind screens;
@tailwind base;
.tailwind {
@tailwind components !important;
@tailwind utilities;
}
@tailwind base;
- 引入基础样式@tailwind components !important;
- 引入组件样式, 且样式优先级最高@tailwind utilities;
- 引入实用工具类@tailwind screens;
- 引入屏幕断点, 用于相应式设计.tailwind
类选择器, 主要是想用容器包裹这些样式, 便于部分组件单独使用样式, 比如我的友链和导航
5. 创建文件
@site/components.json
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
Framer motion
pnpm add framer-motion
组件实现
配置postcss引入插件
引入
tailwindcss
和autoprefixer
插件可以便捷地应用 Tailwind CSS 进行样式设计,并确保生成的 CSS 在不同浏览器中的兼容性
postcss.config.js
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
};
创建组件
修改文件@site/src/components/HomepageFeatures/index.tsx
import React, { ReactNode } from "react";
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { motion } from "framer-motion";
import styles from './styles.module.css';
// 用于合并和处理 CSS 类名, 通过其参数可以动态生成背景样式
function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export const AuroraBackground = ({
className,
children,
showRadialGradient = true,
...props
}) => {
return (
(<main>
<div
className={cn(
// "relative flex flex-col h-[100vh] items-center justify-center bg-zinc-50 dark:bg-zinc-900 text-slate-950 transition-bg", // 暗色控制后的样式是否与下方一致??
"relative flex flex-col h-[100vh] items-center justify-center dark:bg-zinc-900 text-slate-950 transition-bg",
className
)}
{...props}>
<div className="absolute inset-0 overflow-hidden">
<div
// I'm sorry but this is what peak developer performance looks like // trigger warning
className={cn(`
[--white-gradient:repeating-linear-gradient(100deg,var(--white)_0%,var(--white)_7%,var(--transparent)_10%,var(--transparent)_12%,var(--white)_16%)]
[--dark-gradient:repeating-linear-gradient(100deg,var(--black)_0%,var(--black)_7%,var(--transparent)_10%,var(--transparent)_12%,var(--black)_16%)]
[--aurora:repeating-linear-gradient(100deg,var(--blue-500)_10%,var(--indigo-300)_15%,var(--blue-300)_20%,var(--violet-200)_25%,var(--blue-400)_30%)]
[background-image:var(--white-gradient),var(--aurora)]
dark:[background-image:var(--dark-gradient),var(--aurora)]
[background-size:300%,_200%]
[background-position:50%_50%,50%_50%]
filter blur-[10px] invert dark:invert-0
after:content-[""] after:absolute after:inset-0 after:[background-image:var(--white-gradient),var(--aurora)]
after:dark:[background-image:var(--dark-gradient),var(--aurora)]
after:[background-size:200%,_100%]
after:animate-aurora after:[background-attachment:fixed] after:mix-blend-difference
pointer-events-none
absolute -inset-[10px] opacity-50 will-change-transform`, showRadialGradient &&
`[mask-image:radial-gradient(ellipse_at_100%_0%,black_10%,var(--transparent)_70%)]`)}></div>
</div>
{children}
</div>
</main>)
);
}
export default function HomepageFeatures(): JSX.Element {
return (
<div className="tailwind">
<AuroraBackground className={styles.features}>
<motion.div
initial={{ opacity: 0.3, y: 200 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{
delay: 0,
duration: 1,
ease: "easeInOut",
}}
className="relative flex flex-col gap-4 items-center justify-center px-4"
>
<div className="text-3xl md:text-7xl font-bold dark:text-white text-center">
Background lights are cool you know.
</div>
{/* <div className="font-extralight text-base md:text-4xl dark:text-neutral-200 py-4">
And this, is chemical burn.
</div>
<button className="bg-black dark:bg-white rounded-full w-fit text-white dark:text-black px-4 py-2">
Debug now
</button> */}
</motion.div>
</AuroraBackground>
</div>
);
}
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | N/A | AuroraBackground 组件要显示的内容 |
className | string | N/A | 附加的样式 |
showRadialGradient | boolean | true | 是否展示渐变效果 |
...props | object | N/A | 传递过来的属性 |
引入组件
@site/src/pages/index.tsx
export default function Home(): JSX.Element {
const {siteConfig} = useDocusaurusContext();
return (
<Layout
// title={`Hello from ${siteConfig.title}`}
description="Description will go into a meta tag in <head />">
{/* <HomepageHeader /> */}
<main>
<HomepageFeatures />
</main>
</Layout>
);
}