Título
Descripción de la card.
Nuevo core de css que vamos a usar para todos nuestros nuevos proyectos.
ver codigo y documentacion (para CMS): https://github.com/elan-sk/core-tailwidcss.git ver codigo y documentacion en (para next.js): https://github.com/elan-sk/core-tailwindcss-for-netxjs.git Slug: El core está organizado en módulos independientes que se importan en archivos Este core extiende Tailwind CSS con: Tailwind organiza el CSS en tres capas principales: Esto significa que: El sistema de colores tiene dos partes fundamentales: ¿Por qué @theme? ¿Qué hace esto?
Cuando aplicas Veamos cómo funciona el color primario: Problema anterior: Si cambias Solución actual: El texto se ajusta automáticamente según el fondo. Si cambias el valor de Roles disponibles: Tarjeta con colores automáticos: Hero section que cambia de tema: Antes (con media queries): ❌ Saltos bruscos entre breakpoints
❌ Mucho código
❌ Difícil de mantener Ahora (con clamp): ✅ Transición suave
✅ Una sola línea
✅ Se adapta a cualquier pantalla La parte El core aplica estilos predefinidos según el tipo de texto: Herramienta: Calculadora Clamp CSS Paso a paso: Define tus tamaños objetivo: Ingresa en la calculadora: Obtén el resultado: @utility text-custom {
font-size: var(--text-custom);
} Uso: Bootstrap usa containers con ¿Qué hace esto? No tiene Problema común: Solución del core: Uso: ¿Qué hace?
Organiza elementos en columna vertical con espaciado opcional. Implementación: ¿Cómo funciona Es una función especial de Tailwind v4 que toma el número en la clase: Filosofía:
Reemplazar el sistema de Implementación base: ¿Qué hace Grid con columnas específicas: ¿Por qué Permite que los elementos se encojan si el espacio es insuficiente, evitando overflow. ⚠️ IMPORTANTE: Uso de Gap en flex-grid Cuando uses ¿Por qué? El Uso correcto: Alternativa para gap horizontal: Si necesitas espaciado horizontal, usa ¿Qué hace Sobrescribe el Uso: Posicionar elementos con El padre debe estar posicionado: ¿Qué hace Uso: Centro absoluto (X e Y): ¿Por qué Solo centrado horizontal: Solo centrado vertical: Uso: Esquinas: Bordes completos: Uso práctico: Ejemplo visual: Tailwind usa una escala arbitraria ( El core incluye utilidades que convierten píxeles a ¿Cómo funciona? Ejemplos: Ejemplos: Ejemplos: Ejemplos: Ejemplos: Usa la escala de Tailwind ( *Usa las utilidades px- cuando:** Los botones en este core usan una técnica avanzada con pseudo-elementos para crear efectos hover sofisticados. ¿Por qué El botón tiene un pseudo-elemento Recordemos que Esto centra el pseudo-elemento. Al crecer desde ¿Qué hace esto? Cuando el botón está dentro de un fondo oscuro, automáticamente cambia su borde a blanco para mantener contraste. Ejemplo: Esta utilidad personalizada está diseñada para trabajar con imágenes de fondo en elementos HTML, configurando todas las propiedades necesarias para una correcta visualización. Propiedades de background: Propiedades para ocultar texto: Estas técnicas permiten mantener el texto en el HTML (para SEO y accesibilidad) pero ocultarlo visualmente cuando hay una imagen de fondo. Esta clase se usa junto con la utilidad de Tailwind La sintaxis Si necesitas URLs dinámicas, usa estilos inline: Hero section con imagen de fondo: Card con imagen de fondo: Banner con contenido centrado: Galería con imágenes dinámicas (PHP): Tailwind tiene su propia utilidad Nuestra ¿Para qué sirve? Visualiza la estructura del DOM con colores. Útil para detectar: Uso: ¿Qué hace esto? Crea un badge visual en la esquina superior derecha que muestra: Cómo funciona el Uso: ¿Para qué sirve? Visualiza solo los hijos directos, útil para debuggear: Uso: Recuerda: Estas clases usan El core define tres familias tipográficas con múltiples pesos cada una. ¿Qué hace @theme aquí? Define variables CSS que Tailwind convierte automáticamente en clases: Desglose: OpenSans (sans) - 4 pesos: ¿Por qué mismo Esto permite que el navegador elija automáticamente la variante correcta: ¿Por qué dos formatos? Orden de carga: Recuerda que las clases tipográficas ya tienen las fuentes asignadas: Entonces: ¿Qué técnicas usa? ¿Qué técnicas usa? ¿Qué técnicas usa? ¿Qué técnicas usa? ¿Qué técnicas usa? No uses colores literales para componentes reutilizables / ✅ BIEN / Directiva de Tailwind v4 para definir variables CSS que se convierten automáticamente en utilidades. Define una nueva clase de utilidad personalizada que no existe en Tailwind base. Organiza CSS en capas (base, components, utilities) para controlar especificidad. Función CSS para crear valores fluidos entre un mínimo y máximo. Sistema de nomenclatura basado en el rol del color (primary, secondary) en lugar del color literal (blue, red). Colores de texto que van "sobre" (on) un color de fondo, garantizando contraste adecuado. Propiedad CSS que define el tamaño base de un elemento flex antes de distribuir espacio restante. Función especial de Tailwind v4 que extrae el número de una clase (ej: Elemento generado por CSS que no existe en el HTML pero puede ser estilizado. Técnica para centrar elementos usando Elemento que limita el ancho del contenido y lo centra horizontalmente. Punto de ruptura donde el diseño cambia de disposición (ej: de móvil a tablet). Crea una card con:
Descripción de la card.
Crea un grid que sea: Crea un modal centrado con: Contenido Problema: Solución: Problema: No reconstruiste el CSS después de cambiar Solución: Reinicia tu build process (ej: Problema: El padre no tiene ancho suficiente o display inadecuado. Solución: Problema: Faltan clases o estructura incorrecta. Solución: Problema: El padre no tiene Solución: Si tienes dudas o sugerencias sobre el core: Este Core CSS te proporciona: ✅ Sistema de colores semánticos - Reutilización sin esfuerzo
✅ Tipografía responsive - Se adapta automáticamente
✅ Utilidades de layout - Maquetado rápido y consistente
✅ Componentes preconfigurados - Menos código personalizado
✅ Herramientas de debugging - Desarrollo más eficiente ¡Feliz desarrollo! 🚀 Versión: 2.0
Última actualización: Octubre 2025
Autor: Equipo de Frontend
Licencia: Uso interno
Guía Completa del Core CSS Tailwind
guia-core-css-tailwind
Categoría: Desarrollo Frontend
Última actualización: Octubre 2025
📋 Tabla de Contenidos
🏗️ Introducción y Arquitectura
Estructura del Proyecto
index.css:styles/
├── index.css → Archivo principal que importa todo
├── bases/
│ ├── index.css → Importa _base.css
│ └── _base.css → Estilos base del HTML
├── settings/
│ ├── index.css → Importa colores, containers, fonts, typography
│ ├── _colors.css → Sistema de colores semánticos
│ ├── _containers.css → Sistema de containers responsive
│ ├── _fonts.css → Importación de fuentes
│ └── _typography.css → Escalas tipográficas
├── atoms/
│ ├── index.css → Importa _buttons.css
│ └── _buttons.css → Componentes de botones
├── utilities/
│ ├── index.css → Importa utilidades varias
│ ├── _decorateds.css → Decoraciones (scrollbar, imágenes)
│ ├── _flex.css → Utilidades de flexbox
│ ├── _positions.css → Sistema de posicionamiento
│ ├── _sizes-rem.css → Conversión px → rem
│ └── _test.css → Herramientas de debug
├── libraries/
│ ├── index.css → Importa _swiper.css
│ └── _swiper.css → Estilos de Swiper.js
└── readme → Documentación del core
Filosofía del Core
🎨 Sistema de Capas de Tailwind
¿Qué son las capas?
@layer base {
/* Estilos base del HTML (h1, body, etc.) */
}
@layer components {
/* Componentes reutilizables (.btn-primary, .card, etc.) */
}
@layer utilities {
/* Utilidades de una sola responsabilidad (.flex-center, etc.) */
}Orden de Especificidad
base < components < utilities < estilos inline
Ejemplo Práctico
/* En _base.css */
@layer base {
a { @apply text-button } /* Todos los enlaces tamaño button */
}
/* Puedes sobrescribirlo con utilidades */
<a class="text-h3">Este enlace es más grande</a>
🎨 Sistema de Colores Semánticos
Arquitectura del Sistema
1. Definición de Variables (@theme)
@theme {
/* Color de fondo */
--color-primary: #f6993f;
/* Color de texto que va SOBRE ese fondo */
--color-on-primary: #ffffff;
}
bg-primary, text-on-primaryvar(--color-primary) en CSS personalizado2. Aplicación Automática (@layer base)
@layer base {
.bg-primary {
@apply text-on-primary /* ⬅️ Magia aquí */
}
}bg-primary a un elemento, automáticamente también aplica text-on-primary al texto.Anatomía de un Color Completo
/* 1. DEFINIMOS LAS VARIABLES */
@theme {
--color-primary-dk: #e3342f; /* Primario oscuro */
--color-primary: #f6993f; /* Primario normal */
--color-primary-lt: #ffed4a; /* Primario claro */
/* Textos que van sobre cada uno */
--color-on-primary-dk: #ffffff; /* Blanco sobre oscuro */
--color-on-primary: #ffffff; /* Blanco sobre normal */
--color-on-primary-lt: #1f2937; /* Oscuro sobre claro */
}
/* 2. CONECTAMOS FONDO CON TEXTO */
@layer base {
.bg-primary-dk { @apply text-on-primary-dk }
.bg-primary { @apply text-on-primary }
.bg-primary-lt { @apply text-on-primary-lt }
}¿Por Qué Este Sistema?
<button class="bg-orange-500 text-white">
Acción
</button>bg-orange-500 a bg-blue-500, debes también cambiar manualmente text-white a text-gray-900 (porque el azul claro necesita texto oscuro).<button class="bg-primary">
Acción
</button>--color-primary de naranja a azul claro, también cambias --color-on-primary de blanco a oscuro, ¡y todos los componentes se actualizan!Nomenclatura Semántica
[rol]-[variante]
↓ ↓
primary dk (dark)
(normal)
lt (light)
primary → Acciones principales, CTAssecondary → Acciones secundariastertiary → Acentos, decoraciónbackground → Fondo principal del sitiosurface → Fondos de tarjetas/seccionesoutline → Bordes y divisoressuccess/info/error → Mensajes de estadoPaleta Completa Explicada
@theme {
/*=== PRIMARIOS ===*/
/* Usa estos para botones principales, headers, CTAs */
--color-primary-dk: #e3342f;
--color-primary: #f6993f;
--color-primary-lt: #ffed4a;
/*=== SECUNDARIOS ===*/
/* Usa estos para acciones secundarias, info adicional */
--color-secondary-dk: #38c172;
--color-secondary: #4dc0b5;
--color-secondary-lt: #3490dc;
/*=== TERCIARIOS ===*/
/* Usa estos para acentos, decoración, elementos menores */
--color-tertiary-dk: #6574cd;
--color-tertiary: #9561e2;
--color-tertiary-lt: #f66d9b;
/*=== FONDOS ===*/
--color-background: #f8fafc; /* Fondo del body */
--color-surface: #f9f3ef; /* Tarjetas, cards */
--color-outline: #f66d9b; /* Bordes */
/*=== MENSAJES ===*/
--color-success: #22c55e; /* Operación exitosa */
--color-info: #94a3b8; /* Información neutral */
--color-error: #ef4444; /* Errores, alertas */
}Ejemplos de Uso Real
<article class="bg-surface p-6 rounded-lg">
<!-- ⬆️ bg-surface aplica automáticamente text-on-surface -->
<h3 class="text-h3 text-primary mb-4">
Título en color primario
</h3>
<p class="text-base">
Este párrafo hereda text-on-surface automáticamente.
No necesité especificar el color del texto.
</p>
<button class="bg-primary px-6 py-2 rounded-full">
<!-- ⬆️ bg-primary aplica automáticamente text-on-primary -->
Acción
</button>
</article><!-- Tema claro (texto oscuro automático) -->
<section class="bg-primary-lt py-16">
<h1 class="text-h1">Título</h1>
<p>Texto automáticamente oscuro (#1f2937)</p>
</section>
<!-- Tema oscuro (texto blanco automático) -->
<section class="bg-primary-dk py-16">
<h1 class="text-h1">Título</h1>
<p>Texto automáticamente blanco (#ffffff)</p>
</section>
📝 Tipografía Responsive con Clamp
El Problema que Resuelve
.text-h1 {
font-size: 32px;
}
@media (min-width: 768px) {
.text-h1 { font-size: 40px; }
}
@media (min-width: 1200px) {
.text-h1 { font-size: 48px; }
}.text-h1 {
font-size: clamp(2.55rem, 2.4rem + 0.686vw, 3rem);
}Anatomía de clamp()
clamp(MIN, PREFERIDO, MAX)
↓ ↓ ↓
2.55rem 2.4rem 3rem
+ 0.686vw
Cómo Funciona la Parte Variable
2.4rem + 0.686vw significa:
2.4rem es la base (38.4px)0.686vw crece proporcionalmente al ancho del viewport0.686vw = 9.6px38.4px + 9.6px = 48px (tope máximo)Implementación en el Core
@theme {
/* Cada tamaño es una función clamp() */
--text-h1: clamp(2.55rem, 2.4rem + 0.686vw, 3rem); /* 41-48px */
--text-h2: clamp(2.125rem, 2rem + 0.571vw, 2.5rem); /* 34-40px */
--text-h3: clamp(1.7rem, 1.6rem + 0.457vw, 2rem); /* 27-32px */
--text-h4: clamp(1.488rem, 1.4rem + 0.4vw, 1.75rem); /* 24-28px */
--text-header: clamp(1.275rem, 1.2rem + 0.343vw, 1.5rem); /* 20-24px */
--text-button: clamp(0.956rem, 0.9rem + 0.257vw, 1.125rem); /* 15-18px */
--text-base: clamp(0.903rem, 0.85rem + 0.243vw, 1.063rem); /* 14-17px */
--text-small: clamp(0.797rem, 0.75rem + 0.214vw, 0.938rem); /* 13-15px */
}
/* Creamos las clases de utilidad */
@utility text-h1 { font-size: var(--text-h1); }
@utility text-h2 { font-size: var(--text-h2); }
/* ... etc */Estilos Automáticos por Tipo
@layer base {
/* TÍTULOS */
:is(.text-h1, .text-h2, .text-h3, .text-h4) {
@apply font-serif /* Merriweather */
text-balance /* Balancea líneas */
font-bold /* Negritas */
leading-tight; /* Interlineado ajustado */
}
/* HEADER Y BOTONES */
.text-header,
.text-button {
@apply font-sans /* OpenSans */
font-semibold /* Semi-negritas */
text-balance; /* Balancea líneas */
}
/* TEXTO NORMAL */
:is(.text-base, .text-small) {
@apply font-sans /* OpenSans */
text-pretty /* Evita palabras huérfanas */
leading-normal; /* Interlineado normal */
}
}🛠️ Crear Nuevos Tamaños
14px20px
14203501400clamp(0.875rem, 0.7857rem + 0.3571vw, 1.25rem)
@theme {
--text-custom: clamp(0.875rem, 0.7857rem + 0.3571vw, 1.25rem);
}
### Familias Tipográficas
```css
@theme {
--font-serif: 'Merriweather', serif; /* Títulos */
--font-sans: 'OpenSans', sans-serif; /* Cuerpo */
--font-mono: 'RobotoMono', monospace; /* Código */
}<h1 class="font-serif">Título elegante</h1>
<p class="font-sans">Párrafo legible</p>
<code class="font-mono">console.log('código')</code>
📦 Sistema de Containers Bootstrap-like
Filosofía
max-width fijos por breakpoint. Este core replica ese sistema pero usando la sintaxis de Tailwind.Breakpoints Definidos
@theme {
--breakpoint-xs: 350px;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 992px;
--breakpoint-xl: 1200px;
--breakpoint-2xl: 1400px;
/* Max-widths por breakpoint */
--container-sm: 540px;
--container-md: 720px;
--container-lg: 960px;
--container-xl: 1140px;
--container-2xl: 1320px;
}Anatomía del Container Principal
@utility container {
@apply w-[90%] mx-auto px-4; /* Base: 90% ancho, centrado */
/* En cada breakpoint, aplica el max-width correspondiente */
@media (width < 576px) {
max-width: var(--container-sm); /* 540px */
}
@media (width >= 576px) {
max-width: var(--container-sm); /* 540px */
}
@media (width >= 768px) {
max-width: var(--container-md); /* 720px */
}
@media (width >= 992px) {
max-width: var(--container-lg); /* 960px */
}
@media (width >= 1200px) {
max-width: var(--container-xl); /* 1140px */
}
@media (width >= 1400px) {
max-width: var(--container-2xl); /* 1320px */
}
}
mx-auto1rem (px-4)Containers Específicos
/* Container pequeño: solo crece hasta 540px */
@utility container-sm {
@apply w-[90%] mx-auto px-4;
@media (width >= 576px) {
max-width: var(--container-sm);
}
}
/* Container mediano: crece hasta 720px */
@utility container-md {
@apply w-[90%] mx-auto px-4;
@media (width >= 576px) { max-width: var(--container-sm); }
@media (width >= 768px) { max-width: var(--container-md); }
}
/* ... y así sucesivamente hasta container-2xl */Container Full Width
@utility container-full {
@apply w-full mx-auto px-4;
}max-width, ocupa siempre el 100% del ancho disponible.Ejemplos Visuales
<!-- Layout típico de página -->
<!-- Hero: ancho completo -->
<section class="bg-primary">
<div class="container-full py-20">
<h1>Hero de ancho completo</h1>
</div>
</section>
<!-- Contenido: ancho adaptable estándar -->
<section class="bg-background">
<div class="container py-16">
<p>Se adapta a todos los breakpoints</p>
</div>
</section>
<!-- Texto: ancho más estrecho para legibilidad -->
<article class="bg-surface">
<div class="container-md py-12">
<p>Texto más cómodo de leer (máx 720px)</p>
</div>
</article>Tabla de Comparación
Clase
Móvil
SM (576px)
MD (768px)
LG (992px)
XL (1200px)
2XL (1400px)
container-full100%
100%
100%
100%
100%
100%
container-sm90%
540px
540px
540px
540px
540px
container-md90%
540px
720px
720px
720px
720px
container-lg90%
540px
720px
960px
960px
960px
container-xl90%
540px
720px
960px
1140px
1140px
container-2xl90%
540px
720px
960px
1140px
1320px
container90%
540px
720px
960px
1140px
1320px
🔲 Utilidades de Flexbox Avanzadas
1. Flex Center
/* Código repetitivo */
.elemento {
display: flex;
justify-content: center;
align-items: center;
}@utility flex-center {
@apply flex justify-center items-center;
}<div class="flex-center h-screen">
<h1>Perfectamente centrado</h1>
</div>2. Flex Container (Columna con Gap)
/* Sin gap */
@utility flex-container {
@apply flex flex-col;
}
/* Con gap usando escala de Tailwind */
@utility flex-container-* {
@apply flex flex-col;
gap: calc(var(--spacing) * --value(integer));
}
/* Con gap en píxeles */
@utility flex-container-px-* {
@apply flex flex-col;
gap: calc(--value(number) / 16 * 1rem);
}--value(integer)?<!-- flex-container-4 -->
<!-- --value(integer) = 4 -->
<!-- gap = 4 * var(--spacing) = 4 * 0.25rem = 1rem -->
<div class="flex-container-4">
<div>Item 1</div>
<div>Item 2</div>
<!-- ⬆️ gap de 1rem entre ellos -->
</div>
<!-- flex-container-px-24 -->
<!-- --value(number) = 24 -->
<!-- gap = 24 / 16 * 1rem = 1.5rem -->
<div class="flex-container-px-24">
<div>Item 1</div>
<div>Item 2</div>
<!-- ⬆️ gap de 24px (1.5rem) entre ellos -->
</div>3. Flex Grid (Sistema de Grid con Flexbox)
.row y .col-* de Bootstrap, pero más flexible.@utility flex-grid {
@apply flex flex-wrap;
& > * {
flex: 0 0 100%; /* Todos los hijos ocupan 100% */
}
}flex: 0 0 100%?flex: flex-grow flex-shrink flex-basis
↓ ↓ ↓
0 0 100%
flex-grow: 0 → No crece más allá de su tamaño baseflex-shrink: 0 → No se encoge menos de su tamaño baseflex-basis: 100% → Tamaño base es 100% del contenedor@utility flex-grid-3 {
@apply flex flex-wrap;
& > * {
flex: 0 1 calc(1 / 3 * 100%); /* 33.33% cada uno */
}
}flex-shrink: 1 aquí?flex-grid-*, debes tener mucho cuidado con el gap:
gap-y-* o gap-y-px-* (solo gap vertical) para espaciar las filasflex-grid-3 calcula que cada elemento ocupe exactamente 33.33% del ancho. Si agregas gap horizontal, los elementos ocuparán 33.33% + gap, excediendo el 100% y rompiendo el layout (igual que pasa con .row y gap en Bootstrap).<!-- ✅ CORRECTO: gap solo vertical -->
<div class="flex-grid-3 gap-y-4">
<div>Columna 1</div>
<div>Columna 2</div>
<div>Columna 3</div>
<div>Columna 4</div>
<div>Columna 5</div>
<div>Columna 6</div>
</div>
<!-- ✅ CORRECTO: gap en píxeles vertical -->
<div class="flex-grid-3 gap-y-px-24">
<div>Columna 1</div>
<div>Columna 2</div>
<div>Columna 3</div>
</div>
<!-- ❌ INCORRECTO: gap en ambos ejes -->
<div class="flex-grid-3 gap-4">
<div>Columna 1</div>
<div>Columna 2</div>
<div>Columna 3</div>
<!-- Los elementos se moverán a la siguiente línea -->
</div>
<!-- Grid responsive -->
<div class="flex-grid-2 md:flex-grid-3 lg:flex-grid-4 gap-y-6">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
<div>Card 4</div>
</div>padding en los elementos hijos:<div class="flex-grid-3 gap-y-4">
<div class="px-2">
<div class="bg-surface p-4">Contenido</div>
</div>
<div class="px-2">
<div class="bg-surface p-4">Contenido</div>
</div>
<div class="px-2">
<div class="bg-surface p-4">Contenido</div>
</div>
</div>4. Personalizando Hijos con
basis<div class="flex-grid-4 gap-4">
<!-- Hijo normal: 25% -->
<div>Normal</div>
<!-- Hijo que ocupa 50% -->
<div class="basis-1/2">Grande</div>
<!-- Hijo que ocupa 100% (nueva línea) -->
<div class="basis-full">Ancho completo</div>
<!-- Hijo que ocupa 75% -->
<div class="basis-3/4">Muy grande</div>
</div>basis-1/2?flex-basis del padre:.basis-1/2 { flex-basis: 50%; }Grid Dinámico con
--value@utility flex-grid-* {
@apply flex flex-wrap;
& > * {
flex: 0 1 calc(1 / --value(integer) * 100%);
}
}<!-- flex-grid-5 = 5 columnas -->
<div class="flex-grid-5">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<!-- flex-grid-8 = 8 columnas -->
<div class="flex-grid-8 gap-2">
<!-- 8 elementos por fila -->
</div>
📍 Sistema de Posicionamiento Absoluto
Filosofía
position: absolute requiere escribir código repetitivo. Este sistema lo simplifica con clases semánticas.Requisito Importante
<div class="relative"> <!-- ⬅️ Necesario -->
<div class="position-center">
Hijo posicionado
</div>
</div>1. Position Full (Cubre todo)
@utility position-full {
@apply absolute inset-0;
}inset-0?inset: 0; /* Shorthand para: */
top: 0;
right: 0;
bottom: 0;
left: 0;<div class="relative h-64">
<!-- Cubre todo el padre -->
<div class="position-full bg-primary/20">
Overlay
</div>
</div>2. Centrados Perfectos
@utility position-center {
@apply absolute
top-1/2 /* 50% desde arriba */
left-1/2 /* 50% desde izquierda */
-translate-1/2; /* Corrige el desplazamiento */
}-translate-1/2?top-1/2 y left-1/2 mueven la esquina superior izquierda al centro. Para centrar el centro del elemento, necesitamos moverlo hacia atrás:-translate-1/2 = transform: translate(-50%, -50%);@utility position-x-center {
@apply absolute
left-1/2
-translate-x-1/2;
}@utility position-y-center {
@apply absolute
top-1/2
-translate-y-1/2;
}<div class="relative h-96 bg-surface">
<!-- Centro absoluto -->
<div class="position-center">
<h2 class="text-h2">Centrado perfecto</h2>
</div>
<!-- Solo horizontal -->
<div class="position-x-center top-4">
<p>Top centrado horizontalmente</p>
</div>
</div>3. Esquinas y Bordes
/* Superior izquierda */
@utility position-tl {
@apply absolute top-0 left-0;
}
/* Superior derecha */
@utility position-tr {
@apply absolute top-0 right-0;
}
/* Inferior izquierda */
@utility position-bl {
@apply absolute bottom-0 left-0;
}
/* Inferior derecha */
@utility position-br {
@apply absolute bottom-0 right-0;
}/* Borde superior completo */
@utility position-t {
@apply absolute top-0 left-0 right-0;
}
/* Borde inferior completo */
@utility position-b {
@apply absolute bottom-0 left-0 right-0;
}
/* Borde izquierdo completo */
@utility position-l {
@apply absolute top-0 bottom-0 left-0;
}
/* Borde derecho completo */
@utility position-r {
@apply absolute top-0 bottom-0 right-0;
}<div class="relative h-96 bg-surface rounded-lg overflow-hidden">
<!-- Botón cerrar en esquina superior derecha -->
<button class="position-tr p-4 text-h4">✕</button>
<!-- Badge en esquina superior izquierda -->
<span class="position-tl bg-error px-3 py-1 text-small">
Nuevo
</span>
<!-- Barra de navegación superior -->
<nav class="position-t bg-primary h-16 flex-center">
Navigation
</nav>
<!-- Footer inferior -->
<footer class="position-b bg-surface p-4">
Footer
</footer>
</div>4. Centrados por Lado
/* Centrado en el borde superior */
@utility position-t-center {
@apply absolute
top-0
left-1/2
-translate-x-1/2;
}
/* Centrado en el borde inferior */
@utility position-b-center {
@apply absolute
bottom-0
left-1/2
-translate-x-1/2;
}
/* Centrado en el borde izquierdo */
@utility position-l-center {
@apply absolute
left-0
top-1/2
-translate-y-1/2;
}
/* Centrado en el borde derecho */
@utility position-r-center {
@apply absolute
right-0
top-1/2
-translate-y-1/2;
}<div class="relative h-96 bg-surface rounded-lg">
<!-- Badge centrado arriba -->
<div class="position-t-center bg-primary px-4 py-2 rounded-b-lg">
Top Badge
</div>
<!-- Badge centrado abajo -->
<div class="position-b-center bg-secondary px-4 py-2 rounded-t-lg">
Bottom Badge
</div>
<!-- Badge centrado izquierda -->
<div class="position-l-center bg-tertiary px-2 py-4 rounded-r-lg">
Left
</div>
<!-- Badge centrado derecha -->
<div class="position-r-center bg-success px-2 py-4 rounded-l-lg">
Right
</div>
</div>Diagrama de Posiciones
position-tl ──────── position-t-center ──────── position-tr
│ │ │
│ position-t (todo el top) │
│ │ │
│ │ │
position-l-center ─── position-center ─── position-r-center
│ │ │
│ │ │
│ position-b (todo el bottom) │
│ │ │
position-bl ──────── position-b-center ─────── position-br
📏 Utilidades de Tamaño con Conversión Automática
El Problema
w-4 = 1rem = 16px), pero a veces necesitas valores exactos en píxeles que se conviertan a rem automáticamente.La Solución
rem al vuelo:@utility w-px-* {
width: calc(--value(number) / 16 * 1rem);
}<div class="w-px-320">
<!-- --value(number) = 320 -->
<!-- width = 320 / 16 * 1rem = 20rem -->
</div>1. Width y Height
/* Tamaño combinado (cuadrado) */
@utility size-px-* {
height: calc(--value(number) / 16 * 1rem);
width: calc(--value(number) / 16 * 1rem);
}
/* Width */
@utility w-px-* {
width: calc(--value(number) / 16 * 1rem);
}
@utility max-w-px-* {
max-width: calc(--value(number) / 16 * 1rem);
}
@utility min-w-px-* {
min-width: calc(--value(number) / 16 * 1rem);
}
/* Height */
@utility h-px-* {
height: calc(--value(number) / 16 * 1rem);
}
@utility max-h-px-* {
max-height: calc(--value(number) / 16 * 1rem);
}
@utility min-h-px-* {
min-height: calc(--value(number) / 16 * 1rem);
}<!-- Cuadrado de 64x64px -->
<div class="size-px-64 bg-primary"></div>
<!-- Ancho específico -->
<div class="w-px-320 bg-surface p-4">
320px de ancho (20rem)
</div>
<!-- Contenedor con límites -->
<div class="min-w-px-200 max-w-px-800 bg-secondary">
Ancho entre 200px y 800px
</div>
<!-- Altura fija -->
<div class="h-px-500 bg-tertiary">
500px de alto
</div>2. Padding
/* Padding en todos los lados */
@utility p-px-* {
padding: calc(--value(number) / 16 * 1rem);
}
/* Padding horizontal (izquierda + derecha) */
@utility px-px-* {
padding-left: calc(--value(number) / 16 * 1rem);
padding-right: calc(--value(number) / 16 * 1rem);
}
/* Padding vertical (arriba + abajo) */
@utility py-px-* {
padding-top: calc(--value(number) / 16 * 1rem);
padding-bottom: calc(--value(number) / 16 * 1rem);
}
/* Padding individual */
@utility pt-px-* { padding-top: calc(--value(number) / 16 * 1rem); }
@utility pr-px-* { padding-right: calc(--value(number) / 16 * 1rem); }
@utility pb-px-* { padding-bottom: calc(--value(number) / 16 * 1rem); }
@utility pl-px-* { padding-left: calc(--value(number) / 16 * 1rem); }<!-- Padding uniforme -->
<div class="p-px-32 bg-primary">
32px de padding en todos los lados
</div>
<!-- Padding horizontal y vertical diferentes -->
<div class="px-px-24 py-px-16 bg-secondary">
24px horizontal, 16px vertical
</div>
<!-- Padding específico -->
<div class="pt-px-20 pb-px-40 px-px-16 bg-tertiary">
Top: 20px, Bottom: 40px, Lateral: 16px
</div>3. Margin (incluye negativos)
/* Margin en todos los lados */
@utility m-px-* {
margin: calc(--value(number) / 16 * 1rem);
}
/* Margin negativo */
@utility -m-px-* {
margin: calc(--value(number) / -16 * 1rem);
}
/* Margin horizontal */
@utility mx-px-* {
margin-left: calc(--value(number) / 16 * 1rem);
margin-right: calc(--value(number) / 16 * 1rem);
}
@utility -mx-px-* {
margin-left: calc(--value(number) / -16 * 1rem);
margin-right: calc(--value(number) / -16 * 1rem);
}
/* ... y todas las variaciones */<!-- Margin normal -->
<div class="m-px-20 bg-primary">
20px de margin
</div>
<!-- Margin negativo (overlap) -->
<div class="relative">
<div class="h-px-200 bg-secondary"></div>
<div class="-mt-px-50 bg-tertiary">
Sube 50px sobre el elemento anterior
</div>
</div>
<!-- Centrado con margin -->
<div class="w-px-600 mx-auto">
Centrado horizontalmente
</div>4. Gaps (para Flex y Grid)
@utility gap-px-* {
gap: calc(--value(number) / 16 * 1rem);
}
@utility gap-x-px-* {
column-gap: calc(--value(number) / 16 * 1rem);
}
@utility gap-y-px-* {
row-gap: calc(--value(number) / 16 * 1rem);
}<!-- Gap uniforme -->
<div class="flex gap-px-20">
<div>Item 1</div>
<div>Item 2</div>
</div>
<!-- Gap diferente por eje -->
<div class="flex flex-wrap gap-x-px-16 gap-y-px-24">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>5. Posicionamiento
/* Posiciones absolutas */
@utility top-px-* {
top: calc(--value(number) / 16 * 1rem);
}
@utility -top-px-* {
top: calc(--value(number) / -16 * 1rem);
}
/* ... similar para bottom, left, right, inset */<div class="relative h-96">
<!-- Posicionado a 20px del top -->
<div class="absolute top-px-20 left-px-30">
Posición exacta
</div>
<!-- Posición negativa -->
<div class="absolute -top-px-10 right-0">
Sale del contenedor 10px hacia arriba
</div>
<!-- Inset uniforme -->
<div class="absolute inset-px-15 bg-primary/20">
15px de separación en todos los lados
</div>
</div>¿Cuándo usar px-* vs la escala de Tailwind?
p-4, w-64) cuando:
🔘 Sistema de Botones con Pseudo-elementos
Anatomía de un Botón
1. Reset de Botones
@layer components {
/* Reseteo básico para todos los botones y enlaces */
:where(a, button) {
@apply !no-underline /* Sin subrayado */
text-button /* Tamaño tipográfico */
!font-semibold /* Semi-negritas */
text-outline; /* Color de texto por defecto */
& span {
@apply z-10; /* ⬅️ IMPORTANTE: pone el texto encima */
}
}
/* Estilos base compartidos */
:is(.btn-primary, .btn-secondary, .btn-tertiary) {
@apply inline-flex /* Flex para alinear contenido */
flex-center /* Centra el contenido */
border-3 /* Borde de 3px */
px-6 py-2 /* Padding interno */
rounded-full /* Bordes redondeados */
transition-all /* Transiciones suaves */
duration-300 /* Duración 300ms */
max-w-px-400; /* Máximo 400px */
}
}& span { z-10 }?::before que crece en hover. El z-10 asegura que el texto del <span> quede encima del pseudo-elemento.2. Botón Primary (con efecto hover)
@utility btn-primary {
@apply border-primary /* Borde color primario */
bg-primary /* Fondo color primario */
text-on-primary /* Texto sobre primario */
relative; /* Necesario para ::before */
/* Pseudo-elemento para el efecto hover */
&:before {
@apply block /* Es un elemento de bloque */
content-[''] /* Sin contenido, solo visual */
size-px /* Tamaño inicial mínimo */
position-center /* Centrado absoluto */
rounded-full /* Redondo */
origin-center /* Crece desde el centro */
duration-300 /* Duración de animación */
transition-all; /* Transición suave */
}
/* Estados hover, active, focus */
&:hover, &:active, &:focus {
@apply text-on-primary-dk; /* Cambia color de texto */
&::before {
@apply aspect-square /* Mantiene proporción */
bg-primary-dk; /* Fondo oscuro */
/* Crece 10px más que el botón */
width: calc(100% + 10px);
height: calc(100% + 10px);
}
}
}¿Cómo funciona
position-center?position-center es:position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);origin-center, se expande uniformemente desde el centro.3. Adaptación Automática en Fondos Oscuros
@layer utilities {
:is(.bg-primary-dk, .bg-primary, .bg-error) {
& .btn-primary {
@apply border-on-primary /* Borde blanco */
overflow-hidden; /* Esconde el desbordamiento */
}
}
}<!-- Botón en fondo claro -->
<section class="bg-background">
<button class="btn-primary">
<span>Acción</span>
<!-- Borde naranja -->
</button>
</section>
<!-- Botón en fondo oscuro -->
<section class="bg-primary-dk">
<button class="btn-primary">
<span>Acción</span>
<!-- Borde blanco automáticamente -->
</button>
</section>Uso Correcto del Botón
<!-- ✅ CORRECTO: con span -->
<button class="btn-primary">
<span>Texto del botón</span>
</button>
<!-- ✅ CORRECTO: con span e icono -->
<a href="#" class="btn-primary">
<span>Descargar</span>
<svg>...</svg>
</a>
<!-- ❌ INCORRECTO: sin span -->
<button class="btn-primary">
Texto sin span
<!-- No tendrá z-10, puede quedar detrás del ::before -->
</button>Ejemplo Completo con Estados
<div class="flex-container-px-16">
<!-- Estado normal -->
<button class="btn-primary">
<span>Normal</span>
</button>
<!-- Estado hover (simular con :hover en CSS) -->
<button class="btn-primary hover">
<span>Hover</span>
</button>
<!-- En fondo oscuro -->
<div class="bg-primary p-6">
<button class="btn-primary">
<span>En fondo oscuro</span>
</button>
</div>
</div>
🖼️ Utilidad para Imágenes de Fondo
La Clase bg-cover
Implementación
@utility bg-cover {
background-position: center center; /* Centra la imagen */
background-repeat: no-repeat; /* No repite la imagen */
background-size: 100%; /* Cubre el 100% del espacio */
display: block; /* Elemento de bloque */
font-size: 0; /* Oculta texto fallback */
overflow: hidden; /* Esconde desbordamientos */
text-indent: -999999px; /* Mueve texto fuera de vista */
}¿Cómo Funciona?
background-position: center center → Centra la imagen horizontal y verticalmentebackground-repeat: no-repeat → Evita que la imagen se repitabackground-size: 100% → Hace que la imagen cubra todo el espacio disponible
font-size: 0 → Reduce el tamaño del texto a 0text-indent: -999999px → Mueve el texto fuera de la vistaoverflow: hidden → Esconde cualquier contenido que se desbordeUso con Tailwind
bg-[url('...')]:<!-- ✅ CORRECTO: Combinar ambas clases -->
<div class="bg-[url('../images/hero.jpg')] bg-cover h-px-500">
Texto alternativo para SEO
</div>
<!-- Con posicionamiento relativo para contenido -->
<div class="bg-[url('../images/banner.jpg')] bg-cover h-px-400 relative">
<div class="position-center text-h1 text-white">
Contenido sobre la imagen
</div>
</div>⚠️ Limitación Importante
bg-[url('...')] SOLO funciona cuando se escribe directamente en el HTML.<!-- ✅ FUNCIONA: URL directa en la clase -->
<div class="bg-[url('../images/foto.jpg')] bg-cover"></div>
<!-- ❌ NO FUNCIONA: URL generada dinámicamente -->
<div class="bg-[url('<?= $imagen ?>')] bg-cover"></div>
<!-- ❌ NO FUNCIONA: Con JavaScript -->
<div class="bg-[url(${imagenUrl})] bg-cover"></div>
<!-- ❌ NO FUNCIONA: Con Twig -->
<div class="bg-[url('{{ imagen }}')] bg-cover"></div>Solución para URLs Dinámicas
<!-- ✅ SOLUCIÓN: Style inline con bg-cover -->
<div
class="bg-cover h-px-500"
style="background-image: url('../images/<?= $imagen ?>');"
>
Texto alternativo
</div>
<!-- Con JavaScript -->
<div
id="hero"
class="bg-cover h-px-400"
>
Texto alternativo
</div>
<script>
const hero = document.getElementById('hero');
hero.style.backgroundImage = `url('${imagenUrl}')`;
</script>
<!-- Con Twig -->
<div
class="bg-cover h-px-500"
style="background-image: url('{{ imagen }}');"
>
Texto alternativo
</div>Ejemplos Prácticos
<section class="bg-[url('../images/hero-bg.jpg')] bg-cover h-screen relative">
Hero Section
<!-- Overlay oscuro -->
<div class="position-full bg-primary-dk/60"></div>
<!-- Contenido -->
<div class="position-center z-10 text-center">
<h1 class="text-h1 text-white mb-4">Bienvenido</h1>
<p class="text-header text-white mb-8">
Subtítulo descriptivo
</p>
<button class="btn-primary">
<span>Comenzar</span>
</button>
</div>
</section><article class="relative rounded-lg overflow-hidden h-px-400">
<!-- Imagen de fondo -->
<div class="bg-[url('../images/card-bg.jpg')] bg-cover position-full">
Card con imagen de fondo
</div>
<!-- Contenido sobre la imagen -->
<div class="position-full bg-gradient-to-t from-primary-dk/90 to-transparent">
<div class="position-b p-6">
<h3 class="text-h3 text-white">Título de la Card</h3>
<p class="text-base text-white/90">Descripción</p>
</div>
</div>
</article><div class="bg-[url('../images/banner.jpg')] bg-cover h-px-300 flex-center relative">
Banner Section
<!-- Overlay -->
<div class="position-full bg-primary/50"></div>
<!-- Texto -->
<div class="relative z-10 text-center">
<h2 class="text-h2 text-white">Título del Banner</h2>
</div>
</div><?php
$imagenes = ['foto1.jpg', 'foto2.jpg', 'foto3.jpg'];
?>
<div class="flex-grid-3 gap-y-4">
<?php foreach($imagenes as $img): ?>
<div
class="bg-cover h-px-300 rounded-lg"
style="background-image: url('../images/<?= $img ?>');"
>
<?= $img ?>
</div>
<?php endforeach; ?>
</div>Combinaciones Útiles
<!-- Con altura y redondeo -->
<div class="bg-[url('../img/photo.jpg')] bg-cover h-px-400 rounded-lg">
Foto
</div>
<!-- Con ancho y altura fijos -->
<div class="bg-[url('../img/avatar.jpg')] bg-cover size-px-200 rounded-full">
Avatar
</div>
<!-- Responsive: altura diferente por breakpoint -->
<div class="bg-[url('../img/hero.jpg')] bg-cover
h-px-300 md:h-px-500 lg:h-screen">
Hero responsive
</div>
<!-- Con aspect ratio -->
<div class="bg-[url('../img/banner.jpg')] bg-cover aspect-video">
Banner 16:9
</div>Diferencia con bg-cover de Tailwind
bg-cover, pero esta es diferente:<!-- bg-cover de Tailwind: solo background-size: cover -->
<div class="bg-[url('...')] bg-cover bg-center bg-no-repeat">
Necesitas múltiples clases
</div>
<!-- bg-cover del Core: todo incluido -->
<div class="bg-[url('...')] bg-cover">
Una sola clase adicional
</div>bg-cover personalizada incluye:
🧪 Herramientas de Debugging
1. Test (Visualiza Jerarquía)
@utility test {
@apply !border-3 !border-red-500; /* Padre: rojo */
& > * {
@apply !border-3 !border-yellow-400; /* Hijos: amarillo */
& > * {
@apply !border-3 !border-green-400; /* Nietos: verde */
& > * {
@apply !border-3 !border-blue-400; /* Bisnietos: azul */
& > * {
@apply !border-3 !border-purple-400; /* Tataranietos: púrpura */
& > * {
@apply !border-3 !border-yellow-700; /* Más: amarillo oscuro */
}
}
}
}
}
}
<section class="test">
<div> <!-- Rojo -->
<article> <!-- Amarillo -->
<h2>Título</h2> <!-- Verde -->
<p> <!-- Azul -->
<span>Texto</span> <!-- Púrpura -->
</p>
</article>
</div>
</section>2. Test Responsive (Muestra Breakpoint Actual)
@utility test-responsive {
&, &.test, &.test-son {
@apply !border-3
!border-gray-200 /* < 350px: gris */
xs:!border-red-500 /* 350px+: rojo */
sm:!border-yellow-400 /* 576px+: amarillo */
md:!border-green-400 /* 768px+: verde */
lg:!border-blue-400 /* 992px+: azul */
xl:!border-purple-400 /* 1200px+: púrpura */
2xl:!border-yellow-700 /* 1400px+: amarillo oscuro */
!relative
/* Pseudo-elemento con el badge */
before:!absolute
before:!top-0
before:!right-0
before:!font-semibold
before:!px-2
before:!pb-0.5
before:!rounded-bl-lg
before:!text-small
before:!text-black
before:!block
/* Contenido del badge por breakpoint */
before:!content-['📱<_350']
before:!bg-gray-200
xs:before:!content-['📱xs:_350']
xs:before:!bg-red-500
xs:before:!text-white
sm:before:!content-['📱sm:_576']
sm:before:!bg-yellow-400
sm:before:!text-black
md:before:!content-['💻md:_768']
md:before:!bg-green-400
lg:before:!content-['💻lg:_992']
lg:before:!bg-blue-400
xl:before:!content-['🖥️xl:_1200']
xl:before:!bg-purple-400
2xl:before:!content-['🖥️2xl:_1400']
2xl:before:!bg-yellow-700
2xl:before:!text-white;
}
}
before:!content-[...]:/* En < 350px */
before::before {
content: '📱< 350';
background: #f3f4f6; /* gris */
}
/* En 576px+ */
before::before {
content: '📱sm: 576';
background: #fbbf24; /* amarillo */
}<section class="test-responsive">
<!-- Verás un badge que dice el breakpoint actual -->
<div class="container">
<h2>Contenido</h2>
</div>
</section>3. Test Son (Solo Hijos Directos)
@utility test-son {
@apply !border-3 !border-red-500; /* Padre: rojo */
& > * {
@apply !border-3 !border-yellow-400; /* Hijos: amarillo */
/* No aplica a nietos */
}
}
<div class="test-son flex-grid-3">
<div>Hijo 1 - amarillo</div>
<div>Hijo 2 - amarillo</div>
<div>
Hijo 3 - amarillo
<p>Nieto - sin borde</p>
</div>
</div>Cuándo Usar Cada Test
Herramienta
Úsala para...
testVer toda la estructura del DOM
test-responsiveVerificar breakpoints y diseño responsive
test-sonDebuggear layouts flex/grid
!important para sobrescribir cualquier estilo. Quítalas antes de producción.
🔤 Fuentes Personalizadas
Sistema de Fuentes
1. Definición de Variables
@theme {
--font-serif: 'Merriweather', serif; /* Títulos elegantes */
--font-sans: 'OpenSans', sans-serif; /* Texto legible */
--font-mono: 'RobotoMono', monospace; /* Código */
}
font-serif → usa Merriweatherfont-sans → usa OpenSansfont-mono → usa RobotoMono2. Importación de Fuentes (@font-face)
@layer base {
@font-face {
font-family: 'Merriweather';
src: url('../fonts/Merriweather24pt-Bold.woff2') format('woff2'),
url('../fonts/Merriweather24pt-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
}
font-family: Nombre que usarás en CSSsrc: Rutas a los archivos de fuente (woff2 primero para mejor soporte)font-weight: Peso específico de esta variantefont-style: Normal o italicfont-display: swap: Muestra fuente del sistema mientras carga la custom3. Múltiples Pesos
/* Bold (700) */
@font-face {
font-family: 'OpenSans';
src: url('../fonts/OpenSans-Bold.woff2') format('woff2');
font-weight: bold; /* 700 */
}
/* SemiBold (600) */
@font-face {
font-family: 'OpenSans';
src: url('../fonts/OpenSans-SemiBold.woff2') format('woff2');
font-weight: 600;
}
/* Medium (500) */
@font-face {
font-family: 'OpenSans';
src: url('../fonts/OpenSans-Medium.woff2') format('woff2');
font-weight: 500;
}
/* Regular (400) */
@font-face {
font-family: 'OpenSans';
src: url('../fonts/OpenSans-Regular.woff2') format('woff2');
font-weight: normal; /* 400 */
}font-family pero diferente font-weight?<p class="font-sans font-normal">Regular (400)</p>
<p class="font-sans font-medium">Medium (500)</p>
<p class="font-sans font-semibold">SemiBold (600)</p>
<p class="font-sans font-bold">Bold (700)</p>4. Formatos de Fuente
src: url('../fonts/OpenSans-Bold.woff2') format('woff2'),
url('../fonts/OpenSans-Bold.woff') format('woff');
Uso en el Proyecto
<!-- Título con serif -->
<h1 class="font-serif text-h1 font-bold">
Merriweather Bold
</h1>
<!-- Párrafo con sans -->
<p class="font-sans text-base font-normal">
OpenSans Regular para lectura cómoda
</p>
<!-- Código con mono -->
<code class="font-mono text-small">
const x = 42;
</code>Aplicación Automática
@layer base {
/* Títulos usan serif automáticamente */
:is(.text-h1, .text-h2, .text-h3, .text-h4) {
@apply font-serif font-bold;
}
/* Texto normal usa sans automáticamente */
:is(.text-base, .text-small) {
@apply font-sans;
}
}<!-- Ya tiene font-serif aplicado -->
<h2 class="text-h2">Título automático</h2>
<!-- Ya tiene font-sans aplicado -->
<p class="text-base">Párrafo automático</p>
🎯 Casos de Uso Completos
Ejemplo 1: Card de Producto
<article class="bg-surface rounded-lg overflow-hidden">
<!-- Imagen con badge -->
<div class="relative h-px-300">
<img src="producto.jpg" alt="Producto" class="position-full object-cover">
<span class="position-tl bg-error px-3 py-1 text-small">
-20%
</span>
</div>
<!-- Contenido -->
<div class="p-px-24">
<h3 class="text-h4 text-primary mb-2">Nombre del Producto</h3>
<p class="text-base mb-4">
Descripción breve del producto que se adapta automáticamente.
</p>
<!-- Precio -->
<div class="flex items-center gap-2 mb-4">
<span class="text-header text-secondary font-bold">$99.99</span>
<span class="text-small line-through text-on-surface/50">$124.99</span>
</div>
<!-- Botón -->
<button class="btn-primary w-full">
<span>Agregar al carrito</span>
</button>
</div>
</article>
bg-surface con text-on-surface automáticoposition-full para imagen que cubre todoposition-tl para badge en esquinah-px-300, p-px-24)text-primary, bg-error)text-h4, text-base)
Ejemplo 2: Hero Section Responsive
<section class="bg-primary py-16">
<div class="container">
<div class="flex-grid-2 lg:flex-grid-2 gap-y-8 items-center">
<!-- Contenido texto -->
<div class="flex-container-px-24">
<h1 class="text-h1">
Transforma tu Negocio con Nuestro Core CSS
</h1>
<p class="text-header">
Sistema de diseño profesional que acelera tu desarrollo
y garantiza consistencia visual.
</p>
<div class="flex gap-4 flex-wrap">
<button class="btn-primary">
<span>Comenzar ahora</span>
</button>
<button class="btn-primary">
<span>Ver demo</span>
</button>
</div>
</div>
<!-- Imagen -->
<div class="relative h-px-500">
<img
src="hero.jpg"
alt="Hero"
class="position-full object-cover rounded-lg"
>
<!-- Badge flotante -->
<div class="position-br -mb-px-30 -mr-px-30 bg-secondary px-6 py-4 rounded-lg">
<p class="text-h3 font-bold">+500</p>
<p class="text-small">Proyectos</p>
</div>
</div>
</div>
</div>
</section>
bg-primary aplica text-on-primary automáticamenteflex-grid-2 con responsive lg:flex-grid-2flex-container-px-24 organiza contenido con gapposition-br con márgenes negativos para efecto flotante
Ejemplo 3: Dashboard Layout
<div class="min-h-screen bg-background">
<!-- Header -->
<header class="bg-primary">
<div class="container-full">
<div class="flex justify-between items-center h-px-80 px-px-24">
<h1 class="text-header">Dashboard</h1>
<button class="btn-primary">
<span>Cerrar sesión</span>
</button>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container py-16">
<!-- Stats Grid -->
<div class="flex-grid-2 md:flex-grid-4 gap-y-6 mb-12">
<!-- Stat Card 1 -->
<div class="bg-surface p-6 rounded-lg relative">
<div class="position-tr">
<span class="text-h2">📊</span>
</div>
<p class="text-small text-secondary mb-2">Total Ventas</p>
<p class="text-h3 text-primary">$45,231</p>
<p class="text-small text-success mt-2">↑ 12.5%</p>
</div>
<!-- Stat Card 2 -->
<div class="bg-surface p-6 rounded-lg relative">
<div class="position-tr">
<span class="text-h2">👥</span>
</div>
<p class="text-small text-secondary mb-2">Usuarios</p>
<p class="text-h3 text-primary">1,234</p>
<p class="text-small text-success mt-2">↑ 8.2%</p>
</div>
<!-- Stat Card 3 -->
<div class="bg-surface p-6 rounded-lg relative">
<div class="position-tr">
<span class="text-h2">📦</span>
</div>
<p class="text-small text-secondary mb-2">Productos</p>
<p class="text-h3 text-primary">567</p>
<p class="text-small text-info mt-2">→ 0%</p>
</div>
<!-- Stat Card 4 -->
<div class="bg-surface p-6 rounded-lg relative">
<div class="position-tr">
<span class="text-h2">⭐</span>
</div>
<p class="text-small text-secondary mb-2">Rating</p>
<p class="text-h3 text-primary">4.8</p>
<p class="text-small text-success mt-2">↑ 0.3</p>
</div>
</div>
<!-- Chart Section -->
<div class="bg-surface p-px-32 rounded-lg">
<h2 class="text-h3 text-primary mb-6">Ventas del Mes</h2>
<div class="h-px-400 bg-background rounded flex-center">
<p class="text-base">Gráfico aquí</p>
</div>
</div>
</main>
</div>
position-tr para iconos en esquinah-px-80, p-6)
Ejemplo 4: Modal Centrado
<!-- Overlay -->
<div class="position-full bg-primary-dk/80 flex-center z-50">
<!-- Modal -->
<div class="bg-surface rounded-lg max-w-px-500 w-[90%] relative">
<!-- Botón cerrar -->
<button class="position-tr p-4 text-h4 hover:text-error transition-colors">
✕
</button>
<!-- Header -->
<div class="p-px-32 pb-px-16">
<h2 class="text-h3 text-primary">Confirmar Acción</h2>
</div>
<!-- Content -->
<div class="px-px-32 pb-px-32">
<p class="text-base mb-6">
¿Estás seguro de que deseas realizar esta acción?
Esta operación no se puede deshacer.
</p>
<!-- Actions -->
<div class="flex gap-4 justify-end">
<button class="btn-primary bg-surface border-outline text-on-surface hover:bg-outline">
<span>Cancelar</span>
</button>
<button class="btn-primary">
<span>Confirmar</span>
</button>
</div>
</div>
</div>
</div>
position-full para overlay que cubre toda la pantallaflex-center para centrar el modalposition-tr para botón cerrar en esquinamax-w-px-500 para ancho máximo del modalbg-primary-dk/80 para overlay semi-transparente
Ejemplo 5: Formulario Completo
<section class="bg-background py-16">
<div class="container-md">
<div class="bg-surface rounded-lg p-px-32">
<!-- Header -->
<header class="mb-8">
<h2 class="text-h2 text-primary">Contáctanos</h2>
<p class="text-base text-secondary">
Completa el formulario y te responderemos pronto
</p>
</header>
<!-- Form -->
<form class="flex-container-px-20">
<!-- Nombre -->
<div class="flex-container-px-8">
<label class="text-button font-semibold" for="nombre">
Nombre completo
</label>
<input
type="text"
id="nombre"
class="border-3 border-outline rounded-lg px-4 py-3 text-base
focus:border-primary focus:outline-none transition-colors"
placeholder="Juan Pérez"
>
</div>
<!-- Email -->
<div class="flex-container-px-8">
<label class="text-button font-semibold" for="email">
Email
</label>
<input
type="email"
id="email"
class="border-3 border-outline rounded-lg px-4 py-3 text-base
focus:border-primary focus:outline-none transition-colors"
placeholder="juan@example.com"
>
</div>
<!-- Mensaje -->
<div class="flex-container-px-8">
<label class="text-button font-semibold" for="mensaje">
Mensaje
</label>
<textarea
id="mensaje"
rows="5"
class="border-3 border-outline rounded-lg px-4 py-3 text-base
focus:border-primary focus:outline-none transition-colors
resize-none"
placeholder="Tu mensaje aquí..."
></textarea>
</div>
<!-- Checkbox -->
<div class="flex items-start gap-3">
<input
type="checkbox"
id="terminos"
class="mt-1 size-px-20 accent-primary cursor-pointer"
>
<label for="terminos" class="text-small cursor-pointer">
Acepto los términos y condiciones y la política de privacidad
</label>
</div>
<!-- Submit -->
<button type="submit" class="btn-primary w-full">
<span>Enviar mensaje</span>
</button>
<!-- Mensaje de éxito (oculto por defecto) -->
<div class="bg-success p-4 rounded-lg hidden">
<p class="text-base font-semibold">
✓ Mensaje enviado exitosamente
</p>
</div>
</form>
</div>
</div>
</section>
container-md para formulario más estrechoflex-container-px-20 organiza campos con gap uniformeflex-container-px-8 para label + input con gap pequeñofocus:border-primary para estados interactivosbg-success para mensajes de confirmación
📚 Mejores Prácticas
✅ Hacer
<!-- ✅ BIEN -->
<button class="bg-primary">Acción</button>
2. **Envuelve texto de botones en `<span>`**
```html
<!-- ✅ BIEN -->
<button class="btn-primary">
<span>Texto</span>
</button>
<!-- ❌ MAL -->
<button class="btn-primary">Texto</button>
<!-- ✅ BIEN -->
<h1 class="text-h1">Título</h1>Título
4. **Usa `flex-grid` en lugar de CSS Grid cuando sea posible**
```html
<!-- ✅ BIEN -->
<div class="flex-grid-3 gap-y-4">
<div>Item</div>
</div>
<!-- ❌ MAL -->
<div class="grid grid-cols-3 gap-4">
<div>Item</div>
</div>
<!-- ✅ BIEN -->
<!-- Hero: ancho completo -->
<div class="container-full">...</div>
6. **Usa herramientas de test durante desarrollo**
```html
<!-- ✅ Durante desarrollo -->
<section class="test-responsive">
<div class="flex-grid-3 test-son">
...
</div>
</section>
<!-- ✅ En producción (quita las clases test) -->
<section>
<div class="flex-grid-3">
...
</div>
</section>❌ Evitar
<!-- ❌ MAL -->
<div class="bg-blue-500 text-white">
Difícil de cambiar
</div>
/* ❌ MAL */
.mi-titulo {
font-size: 24px;
}
@media (min-width: 768px) {
.mi-titulo { font-size: 32px; }
}Mi Título
3. **No mezcles sistemas de medida inconsistentemente**
```html
<!-- ❌ MAL -->
<div class="p-4 h-px-320 gap-6 w-px-400">
Mezcla confusa
</div>
<!-- ✅ BIEN: Consistente con escala de Tailwind -->
<div class="p-4 h-80 gap-6 w-96">
...
</div>
<!-- ✅ BIEN: Consistente con px-* -->
<div class="p-px-16 h-px-320 gap-px-24 w-px-400">
...
</div>
<!-- ❌ MAL -->
<div class="absolute top-0 left-1/2 -translate-x-1/2">
Texto centrado arriba
</div>
5. **No dejes las clases de test en producción**
```html
<!-- ❌ MAL en producción -->
<section class="test-responsive">
...
</section>
<!-- ✅ BIEN -->
<section>
...
</section>
🔄 Flujo de Trabajo Recomendado
1. Planificación
_colors.css_containers.css2. Desarrollo
test-responsive para verificar breakpointstest o test-son para debuggear layoutsflex-grid para layouts rápidos3. Refinamiento
px-*4. Producción
test<span>
📖 Glosario de Conceptos
@theme
@utility
@layer
clamp()
Colores Semánticos
ON Colors
flex-basis
--value()
flex-grid-3 → --value(integer) = 3).Pseudo-elemento (::before, ::after)
position-center
position: absolute, top: 50%, left: 50% y transform: translate(-50%, -50%).Container
Breakpoint
🎓 Ejercicios Prácticos
Ejercicio 1: Card Simple
surfaceprimaryVer solución
```html
Título
Ejercicio 2: Grid Responsive
Ver solución
```html
Ejercicio 3: Modal Centrado
Ver solución
```html
Modal
🆘 Solución de Problemas Comunes
El texto del botón queda detrás del efecto hover
<button class="btn-primary">Texto sin span</button><button class="btn-primary">
<span>Texto con span</span>
</button>Los colores no cambian cuando modifico las variables
_colors.css.npm run dev).El container no se centra
<!-- Asegúrate de que el padre permita el centrado -->
<div class="w-full">
<div class="container">
Contenido centrado
</div>
</div>flex-grid no funciona correctamente
<!-- ✅ CORRECTO -->
<div class="flex-grid-3 gap-y-4">
<div>Item 1</div>
<div>Item 2</div>
</div>
<!-- ❌ INCORRECTO (usa gap en vez de gap-y) -->
<div class="flex-grid-3 gap-4">
<div>Item 1</div>
<div>Item 2</div>
<!-- Los elementos se moverán a la siguiente línea -->
</div>position-center no centra el elemento
position: relative.<div class="relative h-64"> <!-- ⬅️ Necesario -->
<div class="position-center">
Centrado
</div>
</div>
📞 Recursos Adicionales
Herramientas
Cursos de Tailwindcss
Contacto
🎉 Conclusión
Próximos Pasos