Escuela Frontend
React

CSS-en-JS: Styled Components en React

Leira Sánchez
Autora
Leira Sánchez

¿Qué es CSS-en-JS?

CSS-en-JS es un patrón que utiliza JavaScript para inyectar estilo al DOM. De esta manera, puedes dar estilo a tus componentes basado en el estado del mismo. Bibliotecas o frameworks como React, Angular, y Vue empacan HTML y JavaScript en un solo archivo. Las bibliotecas de CSS-en-JS, te proveen una manera de incluir las reglas de CSS para el componente en el mismo archivo, manteniendo así la modalidad del framework.

Styled Components

¿Qué es?

Styled Components es una de las librerías más populares para inyectar CSS en JavaScript. No es específica para React ni para ningún otro framework. La puedes utilizar junto con cualquier framework basado en componentes.

Gráfica sobre la cantidad de estrellas de las librerías más populares de CSS-en-JS

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545084/articles/css-en-js/library-popularity_bnrclv.png

Utiliza template literals u objetos para crear componentes con estilo que puedes usar directamente en tu código.

Los tratas igual que a los componentes que ya conoces por lo que puedes pasar props, poner componentes dentro de otros componentes, darle un id, ser reutilizados, entre otras.

Para dar estilo puedes usar CSS y otras funcionalidades adicionales popularizadas por pre-procesadores como Sass.

Styled Components añade una clase única a cada componente para evitar problemas de especificidad. Además, esto asegura que el buscador solo cargue el código necesario para cada página de tu aplicación.

Otras bibliotecas mítigan este riesgo inyectando CSS directamente en el HTML (conocido como inline styles). Esta modalidad previene el uso de funcionalidades como pseudo selectors y media queries.

Una de las ventajas más importantes de Styled Components es que automáticamente añade los prefijos de buscadores. Solo te tienes que preocupar por escribir CSS y ellos se preocupan porque funcione en la mayoría de los buscadores más utilizados. Aquí puedes ver la lista de los buscadores que apoyan.

Pre-Requisitos

Este artículo asume que tienes conocimientos básicos de CSS, HTML, JavaScript y React.

Instalación

Para instalar styled-components puedes utilizar npm o yarn. En mis ejemplos utilizaré npm.

  • Desde el directorio principal de tu aplicación ejecuta el siguiente comando:

    npm install -save styled-components

  • En cada archivo en el que lo quieras utilizar, debes importarlo. En la parte superior del archivo escribe:

    import styled from "styled-components";

    ¡Listo!

Estilizar Componentes de React

👉 Recuerda borrar los archivos de *.css qué create-react-app genera para que no tengas ningún conflicto con tus estilos. Si deseas mantener algunos de estos estilos, puedes cambiarlos a Styled Components.

Básico

Empezaremos dándole estilo a un botón básico.

const Button = () => {
return <button>Botón Básico</button>;
};
export default Button;

De momento, así se ve el botón.

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545084/articles/css-en-js/basic-button_jaadzu.png

Este botón contiene solo los estilos del buscador. Muy aburrido, ¿no?

Para darle estilo, importamos styled-components en la parte superior del archivo. Esto te permite utilizar objetos, como en React, o template literals.

En mis ejemplos estaré utilizando template literals.

Por ahora, el botón es solo un elemento de HTML. Con Styled Components lo convertiremos en un componente que se comportará como cualquier otro componente de React. La diferencia es que este tendrá sus estilos en una clase única. Por esto, el nombre del componente estilizado tendrá que empezar con letra mayúscula.

Debes crear una constante fuera del componente Button. Puedes colocarlo debajo de las importaciones.

import styled from "styled-components";
const PrettyButton = styled.button`
background-color: pink;
border: 2px solid pink;
border-radius: 5px;
color: black;
padding: 10px;
box-shadow: 5px 5px 5px 0px lightgray;
`;
const Button = () => {
return <PrettyButton>¡Botón con estilo!</PrettyButton>;
};
export default Button;

Notarás que styled utiliza notación de punto para obtener el elemento de HTML que deseas estilizar. En este caso, utilizamos button, pero igual podemos poner div, h1, o cualquier otro elemento de HTML. Entre los backticks, escribes CSS al igual que lo harías en un archivo de CSS.

En el componente Button, <PrettyButton> reemplaza a <button>.

Este botón ahora luce así.

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545084/articles/css-en-js/pretty-button_snfxdc.png

👉 Usuarios de VS Code: puedes añadir la extensión vscode-styled-components para obtener syntax highlighting e IntelliSense en tus styled components.

Heredar Estilos de un Componente Existente

Tal vez necesitas otro botón idéntico al anterior, pero con un color de fondo diferente. Tu primer impulso puede ser copiar el componente anterior y simplemente cambiarle el color. Styled Components nos provee una mejor manera que no requiere duplicar código. Podemos utilizar el constructor styled().

const InheritedButton = styled(StyledPrettyButton)`
background-color: lightblue;
border: 2px solid lightblue;
`;

Entre los paréntesis deberás colocar el styled component que deseas extender. Luego, solo añade los estilos que quieras sobreponer.

Este nuevo botón luce así.

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545084/articles/css-en-js/extended-button_gnbxgz.png

Estilos Condicionados a Props

Una de las funcionalidades más poderosas de Styled Components es la habilidad de estilizar componentes de acuerdo al estado.

Lo demostraré con un botón que cambia de color al presionarlo. Estaré utilizando el hook de React useState() para manejar el estado del botón.

Primero, importo el hook y creo el componente básico, sin estilos.

import { useState } from "react";
const Button = () => {
const [isPink, setIsPink] = useState(false);
return (
<button onClick={() => setIsPink(!isPink)}>
¡Cambio de Color!
</button>
);
};
export default Button;

Utilicé useState() para cambiar el estado del botón que dictará si el fondo del botón será rosado o no mediante el valor de isPink. Al comienzo, no será rosado por lo que iniciamos el estado como false. Al presionar el botón setIsPink(!isPink)cambiará el estado a true. Al volver a presionarlo, volverá a su color original.

Ahora estamos listos para estilizar nuestro componente.

Para que Styled Components pueda notar este cambio de estado hay que hacer dos cosas.

1. Añade la variable de estado isPink como prop en el componente del botón

const Button = () => {
const [isPink, setIsPink] = useState(false);
return (
<StyledButton isPink={isPink} onClick={() => setIsPink(!isPink)}>
¡Cambio de Color!
</StyledButton>
);
};
export default Button;

2. Obtén la prop en el estilo que quieras cambiar de acuerdo al estado

import { useState } from "react";
import styled from "styled-components";
const StyledButton = styled.button`
background-color: ${(props) => (props.isPink ? "pink" : "#3c7f8b")};
border: 2px solid ${(props) => (props.isPink ? "pink" : "#3c7f8b")};
border-radius: 5px;
color: ${(props) => (props.isPink ? "black" : "white")};
padding: 10px;
:hover {
box-shadow: 5px 5px 5px 0px lightgray;
}
`;

Botón cambia de color al presionarlo

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545084/articles/css-en-js/color-changing-button_chkdbl.gif

👉 ¡No olvides importar styled-components en la parte superior del archivo!

Estilos en línea con CSS Prop

A veces editamos estilos en línea para iterar rápidamente antes de decidir sobre uno en particular. En React, los estilos se escriben en forma de objeto. Si utilizas la css prop de Styled Components, podrás escribir estilos en línea de manera estándar pues también utiliza template literals.

Otra ventaja, es que Styled Components obtiene éstos estilos y los convierte en una clase única. De esta manera, el HTML no se llena de estilos en línea. Al igual que los estilos en línea de HTML, estas propiedades también pueden ser sobrescritas por un Styled Component si éste incluye !important.

Para utilizar esta prop, tendrás que importar el macro de styled components. En el tope del archivo, donde importas Styled Components simplemente añade /macro al final. Se verá así:

import styled from 'styled-components/macro';

Aquí va un ejemplo utilizando la css prop para lograr el mismo estilo que el <PrettyButton> que estilizamos en la sección Básico.

<button css={`
background-color: pink;
border: 2px solid pink;
border-radius: 5px;
color: black;
margin: 10%;
padding: 10px;
box-shadow: 5px 5px 5px 0px lightgray;
`}
>
¡Botón con CSS prop!
</button>

En el próximo ejemplo podrás notar que a pesar de que incluí un estilo en línea para cambiar el color del text a blanco, este se mantiene negro. Ya que en el styled component sobrepuse que el color fuese negro con !important.

const InlineButton = styled(PrettyButton)`
color: black !important;
`;
<InlineButton
css={"background-color:lightgreen; color: white;"}
>
Botón En Línea
</InlineButton>

Botón con estilos en línea utilizando css prop

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545084/articles/css-en-js/inline-button_rfaoyc.png

Estilos Globales

Los styled components que hemos visto hasta el momento están aislados de otros componentes. Las classes de CSS generadas son solo locales. ¿Qué pasa si queremos inyectar estilos que apliquen a toda nuestra aplicación? Algunos ejemplos de esto pueden ser el fuente, colores, etc..

Styled Components provee una función para esto. En este caso tenemos que importar createGlobalStyle.

Para añadir estilos globales con Styled Components, hay dos pasos.

1. Crea un archivo de JavaScript en /src para los estilos globales.

En mi ejemplo, le llamaré GlobalStyles.js.

Luego, debes crear un componente con los estilos globales y exportarlo.

import { createGlobalStyle } from "styled-components";
const GlobalStyles = createGlobalStyle`
body {
background-color: whitesmoke;
font-family: Arial, sans-serif;
margin: 0;
}
`;
export default GlobalStyles;

2. Añade tu componente como el primer componente en App.js, en el tope del árbol de React.

import Header from "./components/Header";
import PrettyButton from "./components/PrettyButton";
import Button from "./components/Button";
import GlobalStyles from "./components/GlobalStyles";
export default function App() {
return (
<>
<GlobalStyles />
<Header />
<PrettyButton />
<Button />
</>
);
}

¡Listo!

👉 Aunque muchos de los conceptos que hemos discutido hasta ahora funcionan con React Native, createGlobalStyle no es uno de ellos.

Animaciones

La función keyframes de Styled Components nos permite crear animaciones sin tener que sin tener que añadirlas a nivel global. Esta genera una instancia única que puede ser utilizada a través de toda la aplicación.

Para crear animaciones necesitas tomar tres pasos:

1. Importa keyframes y crea los keyframes

import styled, { keyframes } from "styled-components";
const rotatingText = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;

2. Crea el styled component y exportalo

export const Animation = styled.div`
animation: ${rotatingText} 3s linear infinite;
font-size: 2em;
`;

3. Añádelo al árbol de React colocándolo en App.js

Esta animación luce así.

Texto Escuela Frontend rotando

https://res.cloudinary.com/escuela-frontend/image/upload/v1630545075/articles/css-en-js/animation_rz2ahf.gif

Temas

Puedes utilizar temas para cambiar los estilos, mayormente los colores, de tu aplicación. Es muy útil para crear una versión dark mode y una versión light mode, por ejemplo.

Styled Components provee una función para aplicar un tema a una aplicación. Puedes crear un archivo independiente para el tema, o puedes crearlo dentro del mismo archivo de App.js. Independientemente de cual opción escojas, debes importar el ThemeProvider.

import { ThemeProvider } from "styled-components";

Este componente toma una prop llamada theme con un objeto con los estilos del tema.

1. Crea el objeto

const theme = {
colors: {
powderWhite: "#FFFDF9",
persianGreen: "#06B49A",
lightBlue: "#AFDBD2",
darkTeal: "#3c7f8b"
},
fonts: ["Arial", "sans-serif"],
fontSizes: {
text: "1rem",
subtitles: "2rem",
titles: "3rem"
}
}

2. Crea el styled component y exportalo

const Theme = ({ children }) => (
<ThemeProvider theme={theme}>{children}</ThemeProvider>
);
export default Theme;

3. Impórtalo en App.js y envuelve el árbol de React con el componente del tema

...
import Theme from "./Theme";
export default function App() {
return (
<>
<Theme>
<GlobalStyles />
<Header />
<PrettyButton />
<Animation>Escuela Frontend</Animation>
<Button />
</Theme>
</>
);
}

theme será una prop que puedes acceder desde cada propiedad de los styled components. La puedes utilizar de la misma forma en que utilizamos el estado isPink para cambiar el color de un botón en una de las secciones anteriores.

Organización

Es cierto que una de las atracciones de Styled Components es la habilidad de colocar los estilos en el mismo archivo que el componente. También puedes reutilizar los componentes con estilo en cualquier parte de tu aplicación. Por ejemplo, puedes tener un botón simple estilizado que forme parte de otros componentes. En lugar de duplicar el styled component, puedes crear un archivo solo de estilos y exportar cada uno.

Conclusión

Styled Components te permite darle estilo a tus componentes manteniendo la modularidad de React. Puedes utilizar funcionalidades adicionales a las que trae CSS en formato de template literal o de objeto y no te tienes que preocupar por añadirle los prefijos de buscadores. ¡Styled Components lo hace por ti!

Sandbox

Puedes jugar con los componentes que creé durante el artículo en este codesandbox.

Artículos Relacionados

¿Quieres mejorar tus habilidades de frontend?