Cómo utilizar componentes con estilo en React
Si bien el enfoque basado en componentes ha marcado el comienzo de una nueva frontera en la forma en que creamos aplicaciones web, no está exento de imperfecciones, una de las cuales es su usabilidad y escalabilidad con CSS. Esto ha dado origen a una nueva forma de construir y administrar nuestros estilos de una manera específica para cada componente , también conocida como CSS-in-JS.
Los componentes con estilo son una herramienta CSS-in-JS que cierra la brecha entre los componentes y el estilo, ofreciendo numerosas características para que pueda comenzar a diseñar componentes de una manera funcional y reutilizable. En este artículo, aprenderá los conceptos básicos de los componentes con estilo y cómo aplicarlos correctamente a sus aplicaciones React. Deberías haber trabajado en React previamente antes de seguir este tutorial. Si está buscando varias opciones para diseñar componentes de React, puede consultar nuestra publicación anterior sobre el tema .
El núcleo de CSS es la capacidad de apuntar a cualquier elemento HTML, globalmente, sin importar su posición en el árbol DOM. Esto puede ser un obstáculo cuando se usa con componentes, porque los componentes exigen, en un grado razonable, colocación (es decir, mantener activos como estados y estilos) más cerca de donde se usan (lo que se conoce como localización).
En las propias palabras de React, los componentes con estilo son " primitivas visuales para componentes " y su objetivo es brindarnos una forma flexible de diseñar componentes. El resultado es un estrecho acoplamiento entre los componentes y sus estilos.
Nota: Los componentes con estilo están disponibles tanto para React como para React Native, y aunque definitivamente deberías consultar la guía de React Native, aquí nos centraremos en los componentes con estilo para React.
¿Por qué componentes con estilo?
Además de ayudarle a determinar el alcance de los estilos, los componentes con estilo incluyen las siguientes características:
- Prefijos de proveedores automáticos
Puede utilizar propiedades CSS estándar y los componentes con estilo agregarán prefijos de proveedores en caso de que sean necesarios. - Nombres de clase únicos
Los componentes con estilo son independientes entre sí y usted no tiene que preocuparse por sus nombres porque la biblioteca lo maneja por usted. - Eliminación de estilos muertos
Los componentes con estilo eliminan los estilos no utilizados, incluso si están declarados en su código. - y muchos más .
Instalación
Instalar componentes con estilo es fácil. Puedes hacerlo a través de un CDN o con un gestor de paquetes como Yarn…
yarn add styled-components
… o npm:
npm i styled-components
Nuestra demostración utiliza create-react-app .
Empezando
Quizás lo primero que notará sobre los componentes con estilo es su sintaxis, que puede resultar desalentadora si no comprende la magia detrás de los componentes con estilo . Para decirlo brevemente, los componentes con estilo utilizan literales de plantilla de JavaScript para cerrar la brecha entre componentes y estilos. Entonces, cuando creas un componente con estilo, lo que en realidad estás creando es un componente de React con estilos. Se parece a esto:
import styled from "styled-components";// Styled component named StyledButtonconst StyledButton = styled.button` background-color: black; font-size: 32px; color: white;`;function Component() { // Use it like any other component. return StyledButton Login /StyledButton;}
Aquí StyledButton
está el componente con estilo y se representará como un botón HTML con los estilos contenidos. styled
es un método de utilidad interno que transforma el estilo de JavaScript en CSS real.
En HTML y CSS sin formato, tendríamos esto:
button { background-color: black; font-size: 32px; color: white;}button Login /button
Si los componentes con estilo son componentes de React, ¿podemos usar accesorios? Si podemos.
Adaptación basada en accesorios
Los componentes con estilo son funcionales , por lo que podemos diseñar fácilmente elementos de forma dinámica. Supongamos que tenemos dos tipos de botones en nuestra página, uno con fondo negro y el otro azul. No tenemos que crear dos componentes con estilo para ellos; Podemos adaptar su estilo en función de sus accesorios.
import styled from "styled-components";const StyledButton = styled.button` min-width: 200px; border: none; font-size: 18px; padding: 7px 10px; /* The resulting background color will be based on the bg props. */ background-color: ${props = props.bg === "black" ? "black" : "blue";`;function Profile() { return ( div StyledButton bg="black"Button A/StyledButton StyledButton bg="blue"Button B/StyledButton /div )}
Debido a que StyledButton
es un componente de React que acepta accesorios, podemos asignar un color de fondo diferente según la existencia o el valor del bg
accesorio.
Sin embargo, notarás que no le hemos dado a nuestro botón un type
. Vamos a hacer eso:
function Profile() { return ( StyledButton bg="black" type="button" Button A /StyledButton StyledButton bg="blue" type="submit" onClick={() = alert("clicked")} Button B /StyledButton / );}
Los componentes con estilo pueden diferenciar entre los tipos de accesorios que reciben. Saben que type
es un atributo HTML, por lo que en realidad lo renderizan button type="button"Button A/button
mientras usan el bg
accesorio en su propio procesamiento. ¿Observó cómo también adjuntamos un controlador de eventos?
Hablando de atributos, una sintaxis extendida nos permite administrar accesorios usando el attrs
constructor . Mira esto:
const StyledContainer = styled.section.attrs((props) = ({ width: props.width || "100%", hasPadding: props.hasPadding || false,}))` --container-padding: 20px; width: ${(props) = props.width}; // Falls back to 100% padding: ${(props) = (props.hasPadding "var(--container-padding)") || "none"};`;
¿Observa que no necesitamos un ternario al establecer el ancho? Esto se debe a que ya le hemos configurado un valor predeterminado con width: props.width || "100%",
. Además, utilizamos propiedades personalizadas de CSS porque podemos.
Nota: Si los componentes con estilo son componentes de React y podemos pasar accesorios, ¿podemos también usar estados? La cuenta de GitHub de la biblioteca tiene un problema que aborda este mismo asunto.
Estilos extendidos
Digamos que está trabajando en una página de destino y ha configurado su contenedor en un ancho máximo determinado para mantener todo centrado. Tienes un StyledContainer
para eso:
const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto;`;
Luego descubres que necesitas un contenedor más pequeño, con un relleno de 10 píxeles en ambos lados, en lugar de 20 píxeles. Su primer pensamiento podría ser crear otro componente con estilo, y estaría en lo cierto, pero no pasará mucho tiempo antes de que se dé cuenta de que está duplicando estilos.
const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto;`;const StyledSmallContainer = styled.section` max-width: 1024px; padding: 0 10px; margin: 0 auto;`;
Antes de continuar y crear StyledSmallContainer
, como en el fragmento anterior, aprendamos cómo reutilizar y heredar estilos. Es más o menos como spread
funciona el operador:
const StyledContainer = styled.section` max-width: 1024px; padding: 0 20px; margin: 0 auto;`;// Inherit StyledContainer in StyledSmallConatinerconst StyledSmallContainer = styled(StyledContainer)` padding: 0 10px;`;function Home() { return ( StyledContainer h1The secret is to be happy/h1 /StyledContainer );}function Contact() { return ( StyledSmallContainer h1The road goes on and on/h1 /StyledSmallContainer );}
En su StyledSmallContainer
, obtendrá todos los estilos de StyledContainer
, pero se anulará el relleno. Tenga en cuenta que, normalmente, obtendrá un elemento de sección renderizado para StyledSmallContainer
, porque eso es lo que StyledContainer
se representa. Pero eso no significa que esté grabado en piedra o que sea inmutable.
El accesorio polimórfico “como”
Con el as
accesorio polimórfico , puedes intercambiar el elemento final que se renderiza. Un caso de uso es cuando heredas estilos (como en el último ejemplo). Si, por ejemplo, prefieres a div
a section
for StyledSmallContainer
, puedes pasar el as
accesorio a tu componente con estilo con el valor de tu elemento preferido, así:
function Home() { return ( StyledContainer h1It’s business, not personal/h1 /StyledContainer );}function Contact() { return ( StyledSmallContainer as="div" h1Never dribble when you can pass/h1 /StyledSmallContainer );}
Ahora, StyledSmallContainer
se representará como un archivo div
. Incluso podría tener un componente personalizado como valor:
function Home() { return ( StyledContainer h1It’s business, not personal/h1 /StyledContainer );}function Contact() { return ( StyledSmallContainer as={StyledContainer} h1Never dribble when you can pass/h1 /StyledSmallContainer );}
No lo des por sentado.
Sintaxis similar a SCSS
El preprocesador CSS Stylis permite que los componentes con estilo admitan una sintaxis similar a SCSS, como el anidamiento:
const StyledProfileCard = styled.div` border: 1px solid black; .username { font-size: 20px; color: black; transition: 0.2s; :hover { color: red; } + .dob { color: grey; } }`;function ProfileCard() { return ( StyledProfileCard h1 className="username"John Doe/h1 p className="dob" Date: span12th October, 2013/span /p p className="gender"Male/p /StyledProfileCard );}
Animación
Los componentes con estilo tienen un keyframes
asistente que ayuda a construir fotogramas clave de animación (reutilizables). La ventaja aquí es que los fotogramas clave se separarán de los componentes con estilo y se podrán exportar y reutilizar cuando sea necesario.
import styled, {keyframes} from "styled-components";const slideIn = keyframes` from { opacity: 0; } to { opacity: 1; }`;const Toast = styled.div` animation: ${slideIn} 0.5s cubic-bezier(0.4, 0, 0.2, 1) both; border-radius: 5px; padding: 20px; position: fixed;`;
Estilo global
Si bien el objetivo original de CSS-in-JS y, por extensión, de los componentes con estilo es determinar el alcance de los estilos, también podemos aprovechar el estilo global de los componentes con estilo. Debido a que trabajamos principalmente con estilos con alcance, podría pensar que es una configuración de fábrica invariable, pero estaría equivocado. Piénselo: ¿qué es realmente el alcance? Es técnicamente posible para nosotros (en nombre del estilo global) hacer algo similar a esto:
ReactDOM.render( StyledApp App / /StyledApp, document.getElementById("root"));
Pero ya contamos con una función auxiliar createGlobalStyle
cuya única razón de existencia es el estilo global. Entonces, ¿por qué negarle su responsabilidad?
Una cosa que podemos usar createGlobalStyle
es normalizar el CSS :
import {createGlobalStyle} from "styled-components";const GlobalStyle = createGlobalStyle` /* Your css reset here */`;// Use your GlobalStylefunction App() { return ( div GlobalStyle / Routes / /div );}
Nota: Los estilos creados con createGlobalStyle
no aceptan hijos. Obtenga más información en la documentación .
En este punto, quizás te preguntes por qué deberíamos molestarnos createGlobalStlye
en usarlo. Aquí hay algunas razones:
- No podemos apuntar a nada fuera del renderizado raíz sin él (por ejemplo,
html
,body
etc.). createGlobalStyle
inyecta estilos pero no representa ningún elemento real. Si observa detenidamente el último ejemplo, notará que no especificamos ningún elemento HTML para representar. Esto es genial porque es posible que en realidad no necesitemos el elemento. Después de todo, lo que nos preocupa son los estilos globales. Nos dirigimos a selectores en general, no a elementos específicos.createGlobalStyle
no tiene alcance y se puede representar en cualquier lugar de nuestra aplicación y será aplicable siempre que esté en el DOM. Piense en el concepto , no en la estructura .
import {createGlobalStyle} from "styled-components";const GlobalStyle = createGlobalStyle` /* Your css reset here */ .app-title { font-size: 40px; }`;const StyledNav = styled.nav` /* Your styles here */`;function Nav({children}) { return ( StyledNav GlobalStyle / {children} /StyledNav );}function App() { return ( div Nav h1 className="app-title"STYLED COMPONENTS/h1 /Nav Main / Footer / /div );}
Si piensa en la estructura, entonces app-title
no debe diseñarse como se establece en GlobalStyle
. Pero no funciona de esa manera. Dondequiera que elija renderizar su componente GlobalStyle
, se inyectará cuando se renderice su componente .
Tenga cuidado : createGlobalStyles
solo se procesará si está en el DOM.
Ayudante CSS
Ya hemos visto cómo adaptar estilos basados en accesorios. ¿Y si quisiéramos ir un poco más allá? La función auxiliar de CSS ayuda a lograrlo. Supongamos que tenemos dos campos de entrada de texto con estados: vacío y activo, cada uno con un color diferente. Podemos hacer esto:
const StyledTextField = styled.input` color: ${(props) = (props.isEmpty ? "none" : "black")};`;
Todo esta bien. Posteriormente, si necesitamos agregar otro estado de relleno, tendríamos que modificar nuestros estilos:
const StyledTextField = styled.input` color: ${(props) = props.isEmpty ? "none" : props.active ? "purple" : "blue"};`;
Ahora la operación ternaria está ganando complejidad. ¿Qué pasa si más adelante agregamos otro estado a nuestros campos de entrada de texto? ¿O qué pasa si queremos darle a cada estado estilos adicionales además del color? ¿Te imaginas meter los estilos en la operación ternaria? El css
ayudante resulta útil.
const StyledTextField = styled.input` width: 100%; height: 40px; ${(props) = (props.empty css` color: none; backgroundcolor: white; `) || (props.active css` color: black; backgroundcolor: whitesmoke; `)}`;
Lo que hemos hecho es expandir nuestra sintaxis ternaria para dar cabida a más estilos y con una sintaxis más comprensible y organizada. Si la afirmación anterior parece incorrecta, es porque el código está intentando hacer demasiado. Entonces, retrocedamos y refinemos:
const StyledTextField = styled.input`width: 100%;height: 40px;// 1. Empty state${(props) = props.empty css` color: none; backgroundcolor: white; `}// 2. Active state${(props) = props.active css` color: black; backgroundcolor: whitesmoke; `}// 3. Filled state${(props) = props.filled css` color: black; backgroundcolor: white; border: 1px solid green; `}`;
Nuestro refinamiento divide el estilo en tres partes diferentes, manejables y fáciles de entender. Es una victoria.
Administrador de hojas de estilo
Al igual que el asistente CSS, StyleSheetManager
es un método auxiliar para modificar cómo se procesan los estilos. Se necesitan ciertos accesorios, como disableVendorPrefixes
(puede consultar la lista completa ), que le ayudarán a excluirse de los prefijos de proveedores de su subárbol.
import styled, {StyleSheetManager} from "styled-components";const StyledCard = styled.div` width: 200px; backgroundcolor: white;`;const StyledNav = styled.div` width: calc(100% - var(--side-nav-width));`;function Profile() { return ( div StyledNav / StyleSheetManager disableVendorPrefixes StyledCard This is a card /StyledCard /StyleSheetManager /div );}
disableVendorPrefixes
se pasa como accesorio para StyleSheetManager
. Por lo tanto, los componentes con estilo incluidos en StyleSheetManager
se deshabilitarían, pero no los que están en StyledNav
.
Depuración más sencilla
Al presentarle componentes con estilo a uno de mis colegas, una de sus quejas fue que es difícil ubicar un elemento renderizado en el DOM, o en React Developer Tools, para el caso. Este es uno de los inconvenientes de los componentes con estilo: al intentar proporcionar nombres de clase únicos, asigna hashes únicos a los elementos, que resultan ser crípticos, pero los hace displayName
legibles para facilitar la depuración.
import React from "react";import styled from "styled-components";import "./App.css";const LoginButton = styled.button` background-color: white; color: black; border: 1px solid red;`;function App() { return ( div className="App" LoginButtonLogin/LoginButton /div );}
De forma predeterminada, los componentes con estilo se representan LoginButton
como buttonLogin/button
en DOM y como LoginButton
en React Developer Tools, lo que facilita la depuración. Podemos alternar el displayName
valor booleano si no queremos este comportamiento. Esto requiere una configuración de Babel.
Nota : En la documentación babel-plugin-styled-components
se especifica el paquete, así como un .babelrc
archivo de configuración. El problema con esto es que, debido a que estamos usando create-react-app
, no podemos configurar muchas cosas a menos que expulsemos. Aquí es donde entran las macros de Babel.
Necesitaremos instalar babel-plugin-macros
con npm o Yarn y luego crear un babel-plugin-macros.config.js
en la raíz de nuestra aplicación, con el contenido:
module.exports = { styledComponents: { displayName: true, fileName: false, },};
Con el fileName
valor invertido, displayName
tendrá el prefijo del nombre del archivo para una precisión aún más única.
Ahora también necesitamos importar desde macro
:
// Beforeimport styled from "styled-components";// Afterimport styled from "styled-components/macro";
Conclusión
Ahora que puedes componer tu CSS mediante programación, no abuses de esa libertad. Por si sirve de algo, haga todo lo posible para mantener la cordura en los componentes que diseñó. No intentes escribir condicionales pesados, ni supongas que todo debe ser un componente con estilo. Además, no se abstraiga demasiado creando componentes de estilo incipientes para casos de uso que sólo supone que están a la vuelta de la esquina.
Recursos adicionales
- Documentación , componentes con estilo
- “ Construcción de un sistema de componentes reutilizables con React.js y componentes con estilo ”, Lukas Gisder-Dubé
- Uso con Next.js
- Uso con Gatsby
(ks, ra, yk, al, il)Explora más en
- CSS
- Reaccionar
- CSS en JS
- javascript
- Herramientas
Deja un comentario