14. Estilos en React
🎨 14.1 Formas de aplicar estilos en React
Section titled “🎨 14.1 Formas de aplicar estilos en React”Opciones disponibles
Section titled “Opciones disponibles”| Método | Descripción | Scope |
|---|---|---|
| CSS tradicional | Archivos .css importados | Global |
| Inline styles | Objeto style en JSX | Componente |
| CSS Modules | Archivos .module.css | Componente |
| styled-components | CSS-in-JS | Componente |
| Tailwind CSS | Clases utilitarias | Componente |
📄 14.2 CSS tradicional
Section titled “📄 14.2 CSS tradicional”Importar archivos CSS
Section titled “Importar archivos CSS”/* styles.css */.boton {padding: 10px 20px;background-color: #3498db;color: white;border: none;border-radius: 5px;cursor: pointer;}
.boton:hover {background-color: #2980b9;}
.boton-peligro {background-color: #e74c3c;}
.boton-peligro:hover {background-color: #c0392b;}// Componente.jsximport './styles.css';
function Botones() {return ( <div> <button className="boton">Normal</button> <button className="boton boton-peligro">Peligro</button> </div>);}Clases condicionales
Section titled “Clases condicionales”import './styles.css';
function Boton({ variante, disabled }) {// Construir className dinámicamenteconst clases = `boton ${variante === 'peligro' ? 'boton-peligro' : ''} ${disabled ? 'boton-disabled' : ''}`.trim();
return <button className={clases}>Click</button>;}
// O usando template literalsfunction Boton2({ activo }) {return ( <button className={`boton ${activo ? 'activo' : 'inactivo'}`}> Click </button>);}Librería classnames
Section titled “Librería classnames”npm install classnamesimport classNames from 'classnames';import './styles.css';
function Boton({ variante, disabled, activo }) {const clases = classNames('boton', { 'boton-peligro': variante === 'peligro', 'boton-exito': variante === 'exito', 'boton-disabled': disabled, 'activo': activo});
return <button className={clases}>Click</button>;}
// Resultado: "boton boton-peligro activo" (según props)✏️ 14.3 Inline styles
Section titled “✏️ 14.3 Inline styles”Sintaxis de estilos inline
Section titled “Sintaxis de estilos inline”function Tarjeta() {// Los estilos son objetos JavaScriptconst estilos = { padding: '20px', backgroundColor: '#f5f5f5', // camelCase borderRadius: '8px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)'};
return ( <div style={estilos}> <h2 style={{ color: '#333', marginBottom: '10px' }}> Título </h2> <p style={{ color: '#666' }}>Contenido</p> </div>);}Estilos dinámicos
Section titled “Estilos dinámicos”function Barra({ progreso, color }) {return ( <div style={{ width: '100%', height: '20px', backgroundColor: '#eee', borderRadius: '10px' }}> <div style={{ width: `${progreso}%`, height: '100%', backgroundColor: color || '#3498db', borderRadius: '10px', transition: 'width 0.3s ease' }} /> </div>);}
// Uso<Barra progreso={75} color="#2ecc71" />📦 14.4 CSS Modules
Section titled “📦 14.4 CSS Modules”¿Qué son CSS Modules?
Section titled “¿Qué son CSS Modules?”CSS Modules generan nombres de clase únicos automáticamente, evitando conflictos de estilos entre componentes.
/* Boton.module.css */.boton {padding: 10px 20px;background-color: #3498db;color: white;border: none;border-radius: 5px;}
.boton:hover {background-color: #2980b9;}
.primario {background-color: #3498db;}
.secundario {background-color: #95a5a6;}// Boton.jsximport styles from './Boton.module.css';
function Boton({ variante = 'primario', children }) {return ( <button className={`${styles.boton} ${styles[variante]}`}> {children} </button>);}
// El className resultante será algo como:// "Boton_boton_x7d3f Boton_primario_a2b1c"Composición de estilos
Section titled “Composición de estilos”/* Card.module.css */.card {padding: 20px;border-radius: 8px;box-shadow: 0 2px 8px rgba(0,0,0,0.1);}
.header {font-size: 1.5rem;margin-bottom: 10px;}
.body {color: #666;}
/* Componer estilos */.cardDestacada {composes: card;border: 2px solid gold;background-color: #fffdf0;}import styles from './Card.module.css';
function Card({ destacada, titulo, children }) {return ( <div className={destacada ? styles.cardDestacada : styles.card}> <h2 className={styles.header}>{titulo}</h2> <div className={styles.body}>{children}</div> </div>);}💅 14.5 styled-components
Section titled “💅 14.5 styled-components”Instalación
Section titled “Instalación”npm install styled-componentsCrear componentes estilizados
Section titled “Crear componentes estilizados”import styled from 'styled-components';
// Crear componente estilizadoconst Boton = styled.button`padding: 10px 20px;background-color: #3498db;color: white;border: none;border-radius: 5px;cursor: pointer;
&:hover { background-color: #2980b9;}
&:disabled { background-color: #bdc3c7; cursor: not-allowed;}`;
const BotonPeligro = styled(Boton)`background-color: #e74c3c;
&:hover { background-color: #c0392b;}`;
// Usofunction App() {return ( <div> <Boton>Normal</Boton> <BotonPeligro>Peligro</BotonPeligro> <Boton disabled>Deshabilitado</Boton> </div>);}Props dinámicas
Section titled “Props dinámicas”import styled from 'styled-components';
const Boton = styled.button`padding: ${props => props.size === 'large' ? '15px 30px' : '10px 20px'};background-color: ${props => props.primary ? '#3498db' : '#95a5a6'};color: white;border: none;border-radius: 5px;font-size: ${props => props.size === 'large' ? '18px' : '14px'};
&:hover { opacity: 0.9;}`;
// Uso<Boton primary>Primario</Boton><Boton>Secundario</Boton><Boton primary size="large">Grande</Boton>Tema global
Section titled “Tema global”import styled, { ThemeProvider } from 'styled-components';
// Definir temaconst tema = {colores: { primario: '#3498db', secundario: '#2ecc71', peligro: '#e74c3c', texto: '#333', fondo: '#f5f5f5'},espaciado: { sm: '8px', md: '16px', lg: '24px'}};
// Usar tema en componentesconst Boton = styled.button`padding: ${props => props.theme.espaciado.md};background-color: ${props => props.theme.colores.primario};color: white;`;
const Contenedor = styled.div`background-color: ${props => props.theme.colores.fondo};padding: ${props => props.theme.espaciado.lg};`;
// Proveer temafunction App() {return ( <ThemeProvider theme={tema}> <Contenedor> <Boton>Click</Boton> </Contenedor> </ThemeProvider>);}🌊 14.6 Tailwind CSS
Section titled “🌊 14.6 Tailwind CSS”Instalación con Vite
Section titled “Instalación con Vite”npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p// tailwind.config.jsexport default {content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}",],theme: { extend: {},},plugins: [],}/* src/index.css */@tailwind base;@tailwind components;@tailwind utilities;Uso básico
Section titled “Uso básico”function Tarjeta({ titulo, children }) {return ( <div className="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow"> <h2 className="text-xl font-bold text-gray-800 mb-4"> {titulo} </h2> <p className="text-gray-600"> {children} </p> </div>);}
function Boton({ variante = 'primario', children }) {const estilos = { primario: 'bg-blue-500 hover:bg-blue-600 text-white', secundario: 'bg-gray-500 hover:bg-gray-600 text-white', peligro: 'bg-red-500 hover:bg-red-600 text-white'};
return ( <button className={`px-4 py-2 rounded font-medium transition-colors ${estilos[variante]}`}> {children} </button>);}Clases responsivas
Section titled “Clases responsivas”function Layout() {return ( <div className="container mx-auto px-4"> {/* Grid responsivo */} <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="p-4 bg-white rounded shadow">Item 1</div> <div className="p-4 bg-white rounded shadow">Item 2</div> <div className="p-4 bg-white rounded shadow">Item 3</div> </div>
{/* Texto responsivo */} <h1 className="text-2xl md:text-4xl lg:text-6xl font-bold"> Título Responsivo </h1>
{/* Ocultar/mostrar */} <div className="hidden md:block"> Solo visible en md y superior </div> </div>);}Estados y variantes
Section titled “Estados y variantes”function Input({ error }) {return ( <input className={` w-full px-4 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100 disabled:cursor-not-allowed ${error ? 'border-red-500' : 'border-gray-300'} `} />);}
function Boton() {return ( <button className=" px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 active:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-300 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 "> Click </button>);}📊 14.7 Comparación de métodos
Section titled “📊 14.7 Comparación de métodos”| Característica | CSS | Modules | styled | Tailwind |
|---|---|---|---|---|
| Scope | Global | Local | Local | Utility |
| Pseudo-clases | ✅ | ✅ | ✅ | ✅ |
| Media queries | ✅ | ✅ | ✅ | ✅ |
| Props dinámicas | ❌ | ❌ | ✅ | Parcial |
| Bundle size | Bajo | Bajo | Medio | Bajo* |
| Curva aprendizaje | Baja | Baja | Media | Media |
📝 Resumen
Section titled “📝 Resumen”
🐝