Ya sea que esté comenzando en el front-end o lo haya estado haciendo durante mucho tiempo, crear una herramienta que pueda generar algo de magia en el front-end puede ayudarlo a aprender algo nuevo, desarrollar sus habilidades y tal vez incluso conseguirlo. un poco de notoriedad.
Es posible que se haya encontrado con algunos de estos populares generadores en línea:
- The Hero Generator y CSS Grid Generator de Sarah Drasner
- Generador de CSS Glassmorphism de Themesburg
- Text Shadows by Components AI (y tienen un montón más)
Me divertí construyendo algunos de estos yo mismo a lo largo de los años. Básicamente, cada vez que te encuentres con algo interesante en el front-end, es posible que tengas la oportunidad de hacer un generador interactivo para eso.
En este caso, vamos a hacer un generador de degradado de fondo animado.
Andamiaje del proyecto en Siguiente
Lo bueno de estos proyectos es que son todos tuyos. Elija la pila que desee y póngase en marcha. Soy un gran admirador de Next.js, así que para este proyecto, comenzaré como un proyecto básico de Create Next App.
npx create-next-app animated-gradient-background-generator
Esto genera todos los archivos que necesitamos para comenzar. Podemos editar pages/index.js
para ser el caparazón de nuestro proyecto.
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="https://css-tricks.com/favicon.ico" />
</Head>
<main>
<h1>
Animated CSS Gradient Background Generator
</h1>
</main>
</>
)
}
¿Gradientes animados?
En el momento en que estoy escribiendo este artículo, si haces una búsqueda de fondo de degradado CSS animado, el primer resultado es este lápiz de Manuel Pinto.
Echemos un vistazo al 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%;
}
}
Este es un gran ejemplo que podemos usar como base para la animación generada.
Un componente de React para describir un degradado animado
Podemos desglosar algunas posibles opciones configurables para el generador:
- Una variedad de colores degradados
- El ángulo del gradiente
- La velocidad de la animación.
Para poner en contexto, queremos proporcionar esta configuración como datos en toda nuestra pequeña aplicación utilizando un componente de orden superior, context/SettingsContext.js
junto con algunos valores predeterminados.
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 }
Para los componentes de nuestro generador, queremos crear:
- componentes de control para ajustar estos ajustes,
- un componente de visualización visual para el degradado animado generado, y
- un componente para la salida del código CSS.
Empecemos con un Controls
componente que contiene las diversas entradas que usamos para ajustar la configuración.
import Colors from "./Colors"
const Controls = (props) => (
<>
<Colors />
</>
)
export default Controls
Podemos agregar nuestro SettingsProvider
y Controls
componentes a 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>
</>
)
}
Nuestra SettingsProvider
comienza con los tres colores de nuestro ejemplo de CodePen como valores predeterminados. Podemos verificar que estamos obteniendo la configuración de color a través de nuestro SettingsContext
en un nuevo Colors
componente.
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
Usemos el Colors
componente para mostrar muestras de color individuales con un pequeño botón para eliminar a través de nuestro 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
Puede notar que hemos estado usando estilos en línea para CSS en este momento. ¡A quien le importa! Nos estamos divirtiendo aquí, así que podemos hacer lo que sea que haga flotar nuestros barcos.
Manejo de colores
A continuación, creamos un AddColor
componente con un botón que abre un selector de color utilizado para agregar más colores al degradado.
Para el selector de color, instalaremos react-color
y usa el ChromePicker
opción.
npm install react-color
Una vez más, utilizaremos SettingsContext
para actualizar la selección de color degradado.
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
Ángulo y velocidad de manejo
Ahora que nuestros controles de color están terminados, agreguemos algunos componentes con entradas de rango para configurar el ángulo y la velocidad de animación.
Aquí está el código para AngleRange
con SpeedRange
siendo muy similar.
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
Ahora viene la parte divertida: renderizando el fondo animado. Apliquemos esto a todo el fondo de la página con un AnimatedBackground
componente de envoltura.
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
Llamamos a la animación CSS para el degradado. gradient-animation
. Necesitamos agregar eso a styles/globals.css
para activar la animación:
@keyframes gradient-animation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
Haciéndolo útil para los usuarios
A continuación, agreguemos algunos resultados de código para que las personas puedan copiar y pegar el CSS generado y usarlo en sus propios proyectos.
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
Haciéndolo divertido
A veces es divertido (y útil) agregar un botón que establece valores aleatorios en un generador como este. Eso les da a las personas una forma de experimentar rápidamente y ver qué tipo de resultados pueden obtener de la herramienta. También es una oportunidad para buscar cosas interesantes como cómo generar colores hexadecimales aleatorios.
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
Terminando
Habrá algunas cosas finales que querrá hacer para concluir su proyecto para el lanzamiento inicial:
- Actualizar
package.json
con la información de su proyecto. - Agregue algunos enlaces a su sitio personal, el repositorio del proyecto y dé el crédito donde corresponda.
- Actualizar el
README.md
archivo que fue generado con contenido predeterminado por Create Next App.
¡Eso es! ¡Estamos listos para lanzar nuestro nuevo generador de cosas de front-end y cosechar las recompensas de la fama y la fortuna que nos esperan!
Puede ver el código de este proyecto en GitHub y la demostración está alojada en Netlify.