Me gusta trabajar con componentes con estilo. Le permiten escribir CSS en su JavaScript, manteniendo su CSS muy cerca de su JavaScript para un solo componente. Como desarrollador front-end al que le encanta diseccionar una página web y dividirla en componentes reutilizables, la idea de los componentes con estilo me alegra. El enfoque es limpio y modular y no tengo que buscar en un archivo CSS gigantesco para ver si ya existe una clase que necesito. Tampoco tengo que agregar una clase a ese archivo CSS interminable y sentirme culpable por hacer que ese archivo ya gigantesco sea aún más grande.
Sin embargo, a medida que continúo en el camino del uso de componentes con estilo, comencé a darme cuenta de que, si bien es excelente separar los estilos CSS para que sean específicos de los componentes singulares, estoy comenzando a repetirme mucho por el bien de la organización. mis estilos por componente. He estado creando nuevas declaraciones CSS y, por lo tanto, nuevos componentes con estilo para cada componente, y estoy viendo una gran cantidad de duplicaciones en mi CSS. No, los componentes con estilo no siempre son exactamente iguales, pero dos de las tres líneas de CSS coincidirían con dos de las tres líneas de CSS en otro componente. ¿Realmente necesito repetir este código cada lugar donde necesito estos estilos?
Tome flexbox, por ejemplo. Flexbox es excelente para diseños receptivos. Alineará los elementos de cierta manera y, con cambios mínimos, se puede modificar para que se vea bien en diferentes tamaños de pantalla. Entonces, la mayoría de las veces, me encuentro escribiendo:
display: flex;
flex-direction: row; /* the default; in react native, column is the default */
Casi con la misma frecuencia, me encontré escribiendo:
display: flex;
flex-direction: column;
Los dos fragmentos de código anteriores son bastante comunes: el primero toma todos los elementos secundarios y los coloca uno al lado del otro, de izquierda a derecha, en una fila. El segundo toma todos los elementos secundarios y los coloca uno encima y otro debajo del otro, de arriba a abajo, en una columna. Cada uno de estos fragmentos de código se puede hacer más específico; sin embargo, podemos agregar diferentes propiedades para especificar aún más cómo queremos que los elementos secundarios se distribuyan en la página. Si queremos que los elementos estén espaciados uniformemente en el ancho de pantalla disponible, por ejemplo, podemos agregar la siguiente línea a cada fragmento de código:
justify-content: space-evenly;
Además, hay otras propiedades, como align-items
que podemos añadir para personalizar aún más la disposición de estos elementos. Entonces, si tenemos tres componentes diferentes que requieren un diseño de caja flexible, pero tienen propiedades diferentes adicionales, ¿cómo podemos usar componentes con estilo de una manera no repetitiva?
Inicialmente, tiene sentido crear tres conjuntos de estilos para cada componente, así:
// component one
const ComponentOne = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
`
// component two
const ComponentTwo = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
`
// component three
const ComponentThree = styled.div`
display: flex;
flex-direction: row;
justify-content: space-evenly;
`
Los estilos enumerados anteriormente harán el trabajo. Los tres componentes tienen elementos secundarios dispuestos en una fila, colocados de izquierda a derecha, con un espacio diferente entre cada elemento secundario. Sin embargo, tener las mismas dos líneas de código repetidas tres veces agrega CSS hinchado.
Para evitar repetirnos, podemos extender un componente base a cada uno de los otros componentes y luego agregar los orzuelos adicionales que necesitamos a esos componentes:
// flex row component
const ExampleFlex = `
display: flex;
flex-direction: row;
`
// component one
const ComponentOne = styled(ExampleFlex)`
justify-content: flex-start;
`
// component two
const ComponentTwo = styled(ExampleFlex)`
justify-content: space-between;
`
// component three
const ComponentThree = styled(ExampleFlex)`
justify-content: space-evenly;
`
Eso se siente mucho mejor. No solo esta versión, en la que nos extendemos fuera del <ExampleFlex />
componente: elimine el código repetitivo, pero también mantiene el código relacionado con la visualización de elementos en una fila en un solo lugar. Si necesitáramos actualizar ese código relacionado con la dirección de los elementos a una columna, podemos hacerlo en un lugar en lugar de tres.
Nota IMPORTANTE: Cuando extiende estilos fuera de otro componente, los estilos que heredan de ese componente base deben enumerarse después del componente base, como en el ejemplo anterior. Colocación <ComponentOne />
sobre <ExampleFlex />
causaría un error que dice: Error de referencia no capturado: no se puede acceder a ‘ExampleFlex’ antes de la inicialización.
Para llevar esta idea un paso más allá, la siguiente demostración muestra una situación en la que es posible que necesite estilos similares en dos elementos de interfaz de usuario diferentes en la página, pero cada uno de esos elementos tiene sus pequeñas diferencias.
Como puede ver, tanto la navegación que se encuentra en la parte superior de la página como el pie de página que se encuentra en la parte inferior de la página deben colocarse en una dirección de fila en pantallas más grandes y luego cambiar a un diseño de columna en dispositivos móviles. Sin embargo, los dos elementos difieren en que la navegación en la parte superior de la página debe estar alineada a la izquierda para dejar espacio para el logotipo a la derecha, mientras que los enlaces de pie de página deben estar alineados a la derecha. Debido a estas diferencias, tiene sentido crear dos componentes con estilos diferentes para cada uno de estos elementos; el <Navigation />
elemento para la navegación superior y el <Footer />
componente para la parte inferior de la página de navegación.
Los estilos de navegación superiores se ven así:
const Navigation = styled.div`
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 10px;
width: calc(100% - 20px);
@media (max-width: 768px) {
flex-direction: column;
}
`
Mientras que los estilos del pie de página inferior se ven así:
const Footer = styled.div`
align-items: center;
display: flex;
flex-direction: row;
justify-content: flex-end;
padding: 10px;
width: calc(100% - 20px);
@media (max-width: 768px) {
flex-direction: column;
}
`
¿La única diferencia en esos dos elementos? El justify-content
propiedad. Además, el <LeftSideNav />
usos de los componentes display: flex
con la misma consulta de medios.
Fuera de estos tres componentes que comparten mucho del mismo CSS, el <NavItem />
componente y <FooterNavItem />
son componentes de enlace muy similares con ligeras diferencias. Entonces, ¿cómo secamos esto?
Al observar el ejemplo a continuación, verá que el CSS que se reutiliza en varios componentes se puede extraer en su propio componente del que nos extendemos para realizar los cambios específicos que podríamos necesitar para componentes más específicos.
Con los cambios implementados, nuestro archivo JavaScript que contiene todos los componentes con estilo es 10 líneas más corto que la versión anterior. Si bien eso puede parecer una pequeña diferencia, a medida que crecen las aplicaciones, estos cambios podrían ayudar a minimizar el CSS que se envía con una aplicación a medida que se agregan estilos.
¡También está el apoyo polimórfico “como”!
Además de extender los estilos de un componente a otro, los componentes con estilo también nos brindan un accesorio polimórfico llamado “como” que aplica estilos de un componente dado a otro elemento siempre que se especifique ese nuevo elemento. Esto es útil en situaciones en las que la interfaz de usuario de dos elementos puede tener el mismo aspecto, pero la funcionalidad HTML subyacente detrás de esos dos elementos es diferente.
Tome como ejemplo los botones y enlaces diseñados como botones. Si bien a primera vista parecen tener una funcionalidad similar (se puede hacer clic en ambos para activar una acción), los dos tienen propósitos funcionalmente diferentes. Un botón es excelente para enviar un formulario o cambiar el diseño de la página actual en la que se encuentra, pero un enlace lo llevará a un recurso.
He creado un bolígrafo a continuación que ilustra esto. A primera vista, los dos botones se ven iguales. Sin embargo, el de la derecha, es en realidad un <a>
elemento con estilo como un botón, mientras que el de la izquierda es un elemento real <button>
elemento. Estos dos botones podrían ser parte de la navegación de un sitio en el futuro, y uno necesita vincularse a un sitio externo. En un primer intento de construir estos dos elementos, tiene sentido ver el código de cada componente como en el primer ejemplo que vimos.
Si sabemos que estos dos elementos tendrán exactamente los mismos estilos, podemos diseñar cada uno como un <Button />
, agrupando el componente con estilo con el JavaScript que acompaña al botón que estamos creando. Luego aplicamos esos mismos estilos exactos a un <Link />
componente que especificamos:
Mirando el bolígrafo de arriba, puede ver que hemos eliminado todo el CSS duplicado relacionado con el estilo de estos dos elementos. En lugar de repetir el CSS para que el botón se use en el componente de enlace, podemos aplicar pasar un valor a la prop como esta:
<Button as="a" href="https://css-tricks.com/dry-ing-up-styled-components/#" ... >I am a Link!</Button>
Esto nos da la posibilidad de cambiar el elemento a una etiqueta HTML manteniendo los estilos que ya hemos definido para el Botón.
Extender los estilos de línea de base, y tal vez incluso mantener algunos de ellos juntos en un solo globalStyles.js
file — es una forma efectiva de SECAR nuestro código de componentes con estilo, haciéndolo mucho más manejable. Mantener el CSS al mínimo no solo mejora el rendimiento de un sitio web, sino que también puede evitar que los desarrolladores tengan que buscar líneas de CSS en el futuro.