无论您是前端新手还是经验丰富的前端开发人员,构建一个能够生成酷炫前端效果的工具都能帮助您学习新知识、提升技能,甚至可能让您小有名气。
您可能遇到过一些流行的在线生成器
- 英雄生成器 和 CSS 网格生成器 由 Sarah Drasner 创建
- 玻璃化 CSS 生成器 由 Themesburg 创建
- 文字阴影 由 Components AI 创建(他们还有很多其他生成器)
多年来,我自己也玩得很开心,构建了 一些 这些 生成器。基本上,只要您遇到任何酷炫的前端效果,都可能有机会为其创建一个交互式生成器。
在本例中,我们将创建一个 动画背景渐变生成器。
在 Next 中搭建项目
这些项目的好处在于,它们完全属于您。 选择您想要的任何技术栈并开始构建。 我非常喜欢 Next.js,所以对于这个项目,我将从一个基本的 Create Next App 项目开始。
npx create-next-app animated-gradient-background-generator
这将生成我们开始所需的所有文件。 我们可以编辑 pages/index.js
文件,将其作为项目的框架。
import Head from "next/head"
import Image from "next/image"
export default function Home() {
return (
<>
<Head>
<title>Animated CSS Gradient Background Generator</title>
<meta name="description" content="A tool for creating animated background gradients in pure CSS." />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>
Animated CSS Gradient Background Generator
</h1>
</main>
</>
)
}
动画渐变?
在我写这篇文章的时候,如果您搜索“动画 CSS 渐变背景”,第一个结果是 这个 CodePen,由 Manuel Pinto 创建。
让我们看一下 CSS 代码
body {
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradient 15s ease infinite;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
这是一个很好的示例,我们可以将其作为生成动画的基础。
描述动画渐变的 React 组件
我们可以为生成器分解一些可配置选项
- 一个渐变颜色的数组
- 渐变的角度
- 动画的速度
为了更好地理解,我们想要使用一个高阶组件 context/SettingsContext.js
将这些设置作为数据提供给整个应用程序,并提供一些默认值。
import React, { useState, createContext } from "react"
const SettingsContext = createContext({ colorSelection: [] })
const SettingsProvider = ({ children }) => {
const [colorSelection, setColorSelection] = useState([
"deepskyblue",
"darkviolet",
"blue",
])
const [angle, setAngle] = useState(300)
const [speed, setSpeed] = useState(5)
return (
<SettingsContext.Provider
value={{
colorSelection,
setColorSelection,
angle,
setAngle,
speed,
setSpeed,
}}
>
{children}
</SettingsContext.Provider>
)
}
export { SettingsContext, SettingsProvider }
对于生成器的组件,我们想要创建
- 用于调整这些设置的控制组件。
- 用于显示生成动画渐变的视觉组件。
- 用于显示 CSS 代码输出的组件。
让我们从一个 Controls
组件开始,它包含用于调整设置的各种输入。
import Colors from "./Colors"
const Controls = (props) => (
<>
<Colors />
</>
)
export default Controls
我们可以将 SettingsProvider
和 Controls
组件添加到 pages/index.js
文件中。
import Head from "next/head"
import Image from "next/image"
import { SettingsProvider } from "../context/SettingsContext"
import Controls from "../components/Controls"
import Output from "../components/Output"
export default function Home() {
return (
<>
<Head>
...
</Head>
<SettingsProvider>
<main style={{ textAlign: "center", padding: "64px" }}>
<h1>Animated CSS Gradient Background Generator</h1>
<Controls />
<Output />
</main>
</SettingsProvider>
</>
)
}
我们的 SettingsProvider
以 CodePen 示例中的三个颜色作为默认值开始。 我们可以通过一个新的 Colors
组件验证是否通过 SettingsContext
获取了颜色设置。
import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const Colors = () => {
const { colorSelection } = useContext(SettingsContext)
return (
<>
{colorSelection.map((color) => (
<div>{color}</div>
))}
</>
)
}
export default Colors
让我们使用 Colors
组件显示单个颜色色块,并使用一个小的按钮通过 SettingsContext
删除它们。
import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const Colors = () => {
const { colorSelection, setColorSelection } = useContext(SettingsContext)
const onDelete = (deleteColor) => {
setColorSelection(colorSelection.filter((color) => color !== deleteColor))
}
return (
<div>
{colorSelection.map((color) => (
<div
key={color}
style={{
background: color,
display: "inline-block",
padding: "32px",
margin: "16px",
position: "relative",
borderRadius: "4px",
}}
>
<button
onClick={() => onDelete(color)}
style={{
background: "crimson",
color: "white",
display: "inline-block",
borderRadius: "50%",
position: "absolute",
top: "-8px",
right: "-8px",
border: "none",
fontSize: "18px",
lineHeight: 1,
width: "24px",
height: "24px",
cursor: "pointer",
boxShadow: "0 0 1px #000",
}}
>
×
</button>
</div>
))}
</div>
)
}
export default Colors
您可能会注意到,到目前为止我们一直在使用内联样式来编写 CSS。 这些都不重要! 我们在这里玩得开心,所以我们可以随心所欲地做任何事情。
处理颜色
接下来,我们创建一个 AddColor
组件,它包含一个按钮,用于打开一个颜色选择器,用于向渐变添加更多颜色。
对于颜色选择器,我们将安装 react-color
并使用 ChromePicker
选项。
npm install react-color
再次,我们将使用 SettingsContext
更新渐变颜色选择。
import React, { useState, useContext } from "react"
import { ChromePicker } from "react-color"
import { SettingsContext } from "../context/SettingsContext"
const AddColor = () => {
const [color, setColor] = useState("white")
const { colorSelection, setColorSelection } = useContext(SettingsContext)
return (
<>
<div style={{ display: "inline-block", paddingBottom: "32px" }}>
<ChromePicker
header="Pick Colors"
color={color}
onChange={(newColor) => {
setColor(newColor.hex)
}}
/>
</div>
<div>
<button
onClick={() => {
setColorSelection([...colorSelection, color])
}}
style={{
background: "royalblue",
color: "white",
padding: "12px 16px",
borderRadius: "8px",
border: "none",
fontSize: "16px",
cursor: "pointer",
lineHeight: 1,
}}
>
+ Add Color
</button>
</div>
</>
)
}
export default AddColor
处理角度和速度
现在颜色控制已经完成,让我们添加一些包含范围输入的组件,用于设置角度和动画速度。
以下是 AngleRange
组件的代码,SpeedRange
组件与此非常相似。
import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const AngleRange = () => {
const { angle, setAngle } = useContext(SettingsContext)
return (
<div style={{ padding: "32px 0", fontSize: "18px" }}>
<label
style={{
display: "inline-block",
fontWeight: "bold",
width: "100px",
textAlign: "right",
}}
htmlFor="angle"
>
Angle
</label>
<input
type="range"
id="angle"
name="angle"
min="-180"
max="180"
value={angle}
onChange={(e) => {
setAngle(e.target.value)
}}
style={{
margin: "0 16px",
width: "180px",
position: "relative",
top: "2px",
}}
/>
<span
style={{
fontSize: "14px",
padding: "0 8px",
position: "relative",
top: "-2px",
width: "120px",
display: "inline-block",
}}
>
{angle} degrees
</span>
</div>
)
}
export default AngleRange
现在到了最有趣的部分:渲染动画背景。 让我们使用一个 AnimatedBackground
包装组件将动画应用到页面的整个背景。
import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const AnimatedBackground = ({ children }) => {
const { colorSelection, speed, angle } = useContext(SettingsContext)
const background =
"linear-gradient(" + angle + "deg, " + colorSelection.toString() + ")"
const backgroundSize =
colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%"
const animation =
"gradient-animation " +
colorSelection.length * Math.abs(speed - 11) +
"s ease infinite"
return (
<div style={{ background, "background-size": backgroundSize, animation, color: "white" }}>
{children}
</div>
)
}
export default AnimatedBackground
我们正在调用渐变的 CSS 动画 gradient-animation
。 我们需要将其添加到 styles/globals.css
文件中才能触发动画。
@keyframes gradient-animation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
让它对用户有用
接下来,让我们添加一些代码输出,以便用户可以复制粘贴生成的 CSS 代码并将其用在自己的项目中。
import React, { useContext, useState } from "react"
import { SettingsContext } from "../context/SettingsContext"
const Output = () => {
const [copied, setCopied] = useState(false)
const { colorSelection, speed, angle } = useContext(SettingsContext)
const background =
"linear-gradient(" + angle + "deg," + colorSelection.toString() + ")"
const backgroundSize =
colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%"
const animation =
"gradient-animation " +
colorSelection.length * Math.abs(speed - 11) +
"s ease infinite"
const code = `.gradient-background {
background: ${background};
background-size: ${backgroundSize};
animation: ${animation};
}
@keyframes gradient-animation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}`
return (
<div
style={{ position: "relative", maxWidth: "640px", margin: "64px auto" }}
>
<pre
style={{
background: "#fff",
color: "#222",
padding: "32px",
width: "100%",
borderRadius: "4px",
textAlign: "left",
whiteSpace: "pre",
boxShadow: "0 2px 8px rgba(0,0,0,.33)",
overflowX: "scroll",
}}
>
<code>{code}</code>
<button
style={{
position: "absolute",
top: "8px",
right: "8px",
background: "royalblue",
color: "white",
padding: "8px 12px",
borderRadius: "8px",
border: "none",
fontSize: "16px",
cursor: "pointer",
lineHeight: 1,
}}
onClick={() => {
setCopied(true)
navigator.clipboard.writeText(code)
}}
>
{copied ? "copied" : "copy"}
</button>
</pre>
</div>
)
}
export default Output
让它有趣
有时添加一个按钮来设置随机值会很有趣(也很有用),就像这样。 这让用户可以快速尝试,看看他们可以从该工具中获得哪些结果。 它也是一个学习如何 生成随机十六进制颜色 的好机会。
import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const Random = () => {
const { setColorSelection, setAngle, setSpeed } = useContext(SettingsContext)
const goRandom = () => {
const numColors = 3 + Math.round(Math.random() * 3)
const colors = [...Array(numColors)].map(() => {
return "#" + Math.floor(Math.random() * 16777215).toString(16)
})
setColorSelection(colors)
setAngle(Math.floor(Math.random() * 361))
setSpeed(Math.floor(Math.random() * 10) + 1)
}
return (
<div style={{ padding: "48px 0 16px" }}>
<button
onClick={goRandom}
style={{
fontSize: "24px",
fontWeight: 200,
background: "rgba(255,255,255,.9)",
color: "blue",
padding: "24px 48px",
borderRadius: "8px",
cursor: "pointer",
boxShadow: "0 0 4px #000",
border: "none",
}}
>
RANDOM
</button>
</div>
)
}
export default Random
总结
在发布项目之前,您可能还需要进行一些收尾工作
- 使用您的项目信息更新
package.json
文件。 - 添加一些指向您个人网站、项目代码库的链接,并对贡献者表示感谢。
- 更新
README.md
文件,该文件由 Create Next App 生成,包含默认内容。
就这样! 我们已经准备好发布我们的新酷炫前端生成器,并收获等待我们的名利双收了!
您可以在 GitHub 上 查看此项目的代码,演示已 部署到 Netlify。