Hero editorial
Titular grande con una palabra subrayada a mano y un círculo de color.
Diseñamos lo quetodavíano existe.
Un estudio pequeño para productos que necesitan ideas claras antes que pantallas bonitas.
- Identidad
- Producto digital
- Sitios web
- Sistemas de diseño
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
/**
* Hero editorial: titular grande con una palabra en cursiva subrayada a mano, un círculo de color y una columna de texto asimétrica.
* Las líneas suben y el subrayado se dibuja una sola vez al cargar. Solo CSS, sin JavaScript.
*
* <EditorialHero
* lead="Diseñamos lo que" highlight="todavía" tail="no existe."
* description="Un estudio pequeño para productos que necesitan ideas claras."
* primary={{ label: "Cuéntanos tu idea", href: "/contacto" }}
* secondary={{ label: "Ver proyectos", href: "/proyectos" }}
* services={["Identidad", "Producto", "Sitios web"]}
* />
*/
import type { CSSProperties } from "react";
type Cta = { label: string; href: string };
export type EditorialHeroProps = {
lead?: string;
highlight?: string;
tail?: string;
description?: string;
primary?: Cta;
secondary?: Cta;
services?: string[];
/** Color del círculo y el subrayado. */
accent?: string;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gche-root { --gche-ink: #101012; --gche-accent: #5b3cff; position: relative; display: grid; grid-template-rows: 1fr auto; box-sizing: border-box; min-height: 640px; overflow: hidden; padding: clamp(24px, 4.5vw, 64px); background: #fbfbfa; color: var(--gche-ink); font-family: inherit; }
.gche-orb { position: absolute; top: -13vw; right: -9vw; width: min(36vw, 520px); aspect-ratio: 1; border-radius: 50%; background: var(--gche-accent); animation: gche-drift 14s ease-in-out infinite alternate; }
.gche-orb::after { content: ""; position: absolute; left: -26%; bottom: -18%; width: 52%; aspect-ratio: 1; border-radius: 50%; background: #ff8fb8; mix-blend-mode: multiply; }
.gche-main { position: relative; display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: clamp(24px, 4vw, 64px); align-items: end; padding-block: clamp(56px, 11vw, 150px) clamp(28px, 4vw, 48px); }
.gche-title { margin: 0; font-family: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif; font-size: clamp(38px, 6.2vw, 92px); font-weight: 400; line-height: .98; white-space: nowrap; letter-spacing: -.04em; text-wrap: balance; }
.gche-line { display: block; overflow: hidden; padding-bottom: .26em; margin-bottom: -.26em; }
.gche-line > span { display: inline-block; animation: gche-rise 1.1s cubic-bezier(.16, 1, .3, 1) both; }
.gche-line:nth-child(2) > span { animation-delay: .12s; } .gche-line:nth-child(3) > span { animation-delay: .24s; }
.gche-hl { position: relative; font-style: italic; }
.gche-hl svg { position: absolute; left: -2%; bottom: -.1em; width: 104%; height: .22em; overflow: visible; }
.gche-hl path { fill: none; stroke: var(--gche-accent); stroke-width: 6; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; animation: gche-draw 1.1s cubic-bezier(.65, 0, .35, 1) .7s forwards; vector-effect: non-scaling-stroke; }
.gche-side { position: relative; z-index: 1; display: grid; gap: 26px; padding-bottom: .5em; }
.gche-side p { margin: 0; max-width: 34ch; font-size: clamp(16px, 1.45vw, 19px); line-height: 1.6; color: #3d3d46; }
.gche-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 26px; }
.gche-primary { display: inline-flex; align-items: center; min-height: 52px; padding: 0 28px; border-radius: 999px; background: var(--gche-ink); color: #fff; font-size: 16px; font-weight: 600; text-decoration: none; transition: background-color .3s, transform .3s cubic-bezier(.16, 1, .3, 1); }
.gche-primary:hover { background: var(--gche-accent); transform: translateY(-2px); }
.gche-secondary { padding-bottom: 2px; border-bottom: 1.5px solid currentColor; color: inherit; font-size: 16px; font-weight: 600; text-decoration: none; transition: color .25s, border-color .25s; }
.gche-secondary:hover { color: var(--gche-accent); }
.gche-primary:focus-visible, .gche-secondary:focus-visible { outline: 2px solid var(--gche-accent); outline-offset: 4px; }
.gche-foot { position: relative; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 32px; padding-top: 20px; border-top: 1.5px solid var(--gche-ink); font-size: 14px; font-weight: 600; letter-spacing: .01em; }
@keyframes gche-rise { from { transform: translateY(105%); } }
@keyframes gche-draw { to { stroke-dashoffset: 0; } }
@keyframes gche-drift { to { transform: translate(-3vw, 3vw) scale(1.05); } }
@media (max-width: 860px) {
.gche-main { grid-template-columns: 1fr; align-items: start; padding-top: 72px; }
.gche-title { white-space: normal; }
.gche-orb { top: -22vw; right: -24vw; width: 70vw; opacity: .22; }
}
@media (prefers-reduced-motion: reduce) { .gche-orb, .gche-line > span { animation: none; } .gche-hl path { animation: none; stroke-dashoffset: 0; } }
`;
export function EditorialHero({
lead = "Diseñamos lo que",
highlight = "todavía",
tail = "no existe.",
description = "Un estudio pequeño para productos que necesitan ideas claras antes que pantallas bonitas.",
primary = { label: "Cuéntanos tu idea", href: "#contacto" },
secondary = { label: "Ver proyectos", href: "#proyectos" },
services = ["Identidad", "Producto digital", "Sitios web", "Sistemas de diseño"],
accent,
className,
style,
}: EditorialHeroProps) {
return (
<>
<style>{CSS}</style>
<section className={["gche-root", className].filter(Boolean).join(" ")} style={{ ["--gche-accent" as string]: accent, ...style } as CSSProperties}>
<span className="gche-orb" aria-hidden="true" />
<div className="gche-main">
<h1 className="gche-title">
<span className="gche-line"><span>{lead}</span></span>
<span className="gche-line"><span><span className="gche-hl">{highlight}<svg viewBox="0 0 300 16" preserveAspectRatio="none" aria-hidden="true"><path pathLength="1" d="M3 11 C 50 2, 110 14, 170 6 S 265 9, 297 4" /></svg></span></span></span>
<span className="gche-line"><span>{tail}</span></span>
</h1>
<div className="gche-side">
<p>{description}</p>
<div className="gche-actions">
<a className="gche-primary" href={primary.href}>{primary.label}</a>
<a className="gche-secondary" href={secondary.href}>{secondary.label}</a>
</div>
</div>
</div>
<ul className="gche-foot" style={{ margin: 0, listStyle: "none", padding: "20px 0 0" }}>
{services.map((service) => <li key={service}>{service}</li>)}
</ul>
</section>
</>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/hero-editorialEjemplo de uso de Hero editorial
Después de copiar editorial-hero.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { EditorialHero } from "./editorial-hero";
export default function Ejemplo() {
return <EditorialHero lead="Ejemplo" />;
}Propiedades de EditorialHero
EditorialHero acepta 10 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
lead? | string | Opcional. |
highlight? | string | Opcional. |
tail? | string | Opcional. |
description? | string | Opcional. |
primary? | Cta | Opcional. |
secondary? | Cta | Opcional. |
services? | string[] | Opcional. |
accent? | string | Color del círculo y el subrayado. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Accesibilidad y rendimiento
El archivo tiene 102 líneas (6 KB) y define 3 animaciones con @keyframes. Esto es lo que hace Hero editorial por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
- Expone su estado a tecnologías de apoyo con atributos aria-*.
Acerca del producto
Un hero de aire editorial: titular enorme en tipografía con serifa del sistema, una palabra en cursiva que se subraya con un trazo dibujado, un círculo de color que flota y una columna de texto asimétrica con llamadas a la acción. Las líneas suben y el subrayado se dibuja una sola vez.
Incluye
Una sección completa en un solo archivo React + TypeScript, con los estilos dentro. No usa Tailwind ni bibliotecas externas.
- Titular en tres partes: lead, highlight y tail
- Subrayado SVG que se dibuja al cargar
- Color de acento configurable
- Se apila en pantallas estrechas
- Sin JavaScript
Cómo usarlo
Todas las propiedades tienen valor por defecto. Pasa lead, highlight, tail, description, primary, secondary y services para tu contenido.