Hay solo dos cosas difíciles en Ciencias de la Computación: Invalidación de caché y nombrar las cosas.
— Phil Karlton
De aquí a un tiempo esa cita a tomado especial relevancia en mi vida como desarrollador. Los proyectos en los que trabajo cada vez se hacen mas grandes y complejos, y esto no se limita solo al back-end, sino que también el front-end y como no, a CSS.
Afortunadamente hay guiás que nos ayudan a ponerle nombre a las cosas, estas guiás se denominan "Convenciones de Nombres" (Naming Conventions) y son fundamentales para escribir código limpio, ordenado y fácil de mantener.
Las convenciones de nombres nos ayudan a nombrar de forma consistente nuestras clases y a organizar nuestro código de manera coherente. BEM, SUIT CSS y Title CSS son algunas de las convenciones más populares que podemos utilizar para lograr esto.
BEM
En mi opinión, BEM es la metodología más ampliamente utilizada de todas. Como se indica en getbem, independientemente de la metodología CSS que utilices (OOCSS, SMACSS o ATOMIC), BEM te será de gran utilidad para organizar tu código de una manera que sea fácil de entender a primera vista.
Las reglas de BEM son simples y se resumen en tres conceptos principales:
1. Bloque (Block)
Sintaxis: <component-name>
El bloque encapsula una entidad independiente que es significativa por sí misma. Aunque los bloques se pueden anidar o interactuar, cada uno es independiente y tiene sentido por sí solo.
Por ejemplo, la clase .card
es un bloque. Una .card
recibe este nombre porque es un elemento independiente y reutilizable (por lo tanto, se utilizan clases en lugar de IDs). Puedes anidarla o listarla, pero sigue siendo independiente y reutilizable.
.card { background-color: #eee; }
2. Elemento (Element)
Sintaxis: <component>__<element-name>
Los elementos son parte de un bloque y, por lo tanto, dependen de este. Un ejemplo concreto podría ser un título para el bloque .card
. La clase CSS se forma combinando el nombre del bloque con dos guiones bajos y el nombre del elemento:
.card__title { color: #111; }
Cabe señalar que, debido a que los elementos ya indican en su nombre a qué bloque pertenecen, no es necesario indicar su dependencia en el código.
Mal
.card .card__title { color: #111; }
Bien
.card__title { color: #111; }
3. Modificador (Modifier)
Sintaxis: <component|element>--<modifier-name>
Los modificadores son todos aquellas clases que modifican o agregan estilo a un bloque o elemento. La clase CSS se forma como el nombre del bloque o elemento más dos guiones.
Por ejemplo, en determinados contextos, es posible que deseemos cambiar el color de una .card
.
.card--dark { background-color: #111; }
Nuevamente, como su nombre lo indica, este modificador solo debe usarse en elementos de .card
y, por lo tanto, no es necesario añadir dicha restricción al CSS.
Mal
.card .card--dark { background-color: #111; }
Bien
.card--dark { background-color: #111; }
Nota sobre BEM
Como habrás notado, tanto los elementos como los modificadores tienen un carácter que los identifica (_
o -
), y este carácter se repite dos veces. Esto es para diferenciar el uso de estos caracteres como una utilidad semántica en lugar de un separador de nombre común. Por lo tanto, es perfectamente aceptable usar cualquiera de estas dos opciones:
.card__sub-title { color: #111; }
.card__sub_title { color: #111; }
La elección entre ellos dependerá de tu equipo y su preferencia. Lo importante es ser coherente y utilizar siempre la misma opción en tu código.
SUIT CSS
SUIT CSS se basa en nombres de clase estructuradas y guiones significativos (es decir, no usar guiones simplemente para separar palabras).
SUIT CSS divide las clases en dos principales conceptos: utilidades (utilities) y componentes (components)
Utilidades (Utilities)
Sintaxis: u-[sm-|md-|lg-]<utilityName>
Las utilidades son recursos de "bajo nivel estructural" que se pueden aplicar directamente a cualquier elemento dentro de un componente. En esencia, son modificadores globales. Si conoces TailwindCSS estarás familiarizado con las utilidades (TailwindCSS solo utiliza utilidades).
Un marco CSS de utility-first repleto de clases como
.flex
,.pt-4
,.text-center
y.rotate-90
que se pueden componer para crear cualquier diseño, directamente en markup.— TailwindCSS
En SUIT CSS las utilidades deben partir con la letra u continuado por un guion y su nombre en camelCase. A su vez, SUIT CSS hace la salvedad de que si hay un modificador de tamaño como sm
, md
o lg
se debe agregar entre la u y el nombre con otro guion extra de separación. Ejemplos de esto sería:
.u-floatLeft { float: left; }
.u-block { display: block; }
.u-md-block { /* ... */ }
Si bien la documentación de SUIT CSS no lo indica, para las utility class puede ser útil agregar la clausula !important
. En mi opinión, este es el único contexto en donde está bien hacer uso de !important
dado que en ningún caso deberías utilizar dos clases de utilidad que sean contradictorias.
.u-floatLeft { float: left !important; }
.u-block { display: block !important; }
Esto solo tiene sentido si utilizas clases de utilidad que sean atómicas, osea, que apliquen un solo estilo. Nuevamente, en mi opinión, las clases de utilidad deben ser atómicas.
Compoenentes (Components)
Sintaxis: [<namespace>-]<ComponentName>[-descendentName][--modifierName]
A diferencia de BEM en SUIT CSS los componentes pueden ser cualquier elemento al que queramos darle un nombre semántico sin importar si depende o no de otro componente.
Todo componente debe tener un nombre en PascalCase. Opcionalmente, separado por un guion -
puede tener de prefijo un namespace
en lowercase.
.twt-Button { /* ... */ }
Los sub-componentes deben estar escritos en camelCase deben tener de prefijo a su componente padre separado por un guion.
.Card-title { /* ... */ }
A su vez, los componentes pueden tener modificadores, descritos en camelCase y separados por dos guiones.
.Card--dark { /* ... */ }
Un ejemplo de todos esto utilizado a la vez sería el siguiente:
.twt-Card-title--bold { /* ... */ }
Estados
Sintaxis: <stateName>
Nota: Solo utilizar bajo el contexto de un componente (y por tanto, dependiente de este).
Adicionalmente, los componentes pueden tener estados como un .alert
con .is-danger
para notificar un error, o una card con .is-loading
cuando su contenido esta cargando.
Estas deben estar descritas en camelCase.
.Commentary.is-expanded { /* ... */ }
Variables
Sintaxis: --ComponentName[-descendant|--modifier][-onState]-(cssProperty|variableName)
A su vez, SUIT CSS nos da un lineamiento de como definir nombres de variables. Estas se agrupan en dos tipos: Variables de componente y variables de tema.
Variables de Componente (Component Variables)
SUIT CSS bajo la premisa de que las propiedades son globales y los componentes no deben exponer su estructura interna, define que las variables de componente deben tener una estructura plana después de su namespace.
:root {
--ComponentName-backgroundColor
--ComponentName-descendant-backgroundColor
--ComponentName--modifier-backgroundColor
--ComponentName-onHover-backgroundColor
--ComponentName-descendant-onHover-backgroundColor
}
En mi opinión, el uso de variables de componente debe mantenerse al mínimo (o idealmente no usarse). Las variables en CSS pretenden ser una guía de estilos general. Requerir variables de componente puede ser que sea un síntoma de que nuestro diseño no es coherente.
Variables de Tema (Theme Variables)
Las variables que no son componentes deben escribirse en camelCase. Para uso compartido, deben crearse en un archivo theme.css
.
:root {
--fontSize: 16px;
--fontFamily: sans-serif;
--lineHeight: 1.4;
--spaceSmall: 10px;
--spaceMedium: 15px;
--spaceLarge: 20px;
}
Title CSS
Title CSS nace con una premisa que se puede resumir en: BEM es útil, pero tiene nombres largos. Resumamoslo.
Para ello define tres conceptos: Title
(lo mantendremos en ingles, puesto que le da el nombre a la convención), descendientes y modificadores.
Title
Sintaxis: <TitleName>
Los titles (o títulos) son lo que en BEM conocemos como bloques. Deben ser descritos en PascalCase
.Title { /* ... */ }
Modificadores
Los modificadores, al igual que en BEM, son clases que modifican el estilo de un componente o descendiente. Deben ser descritos en camelCase. De ser necesario que el modificador solo afecte a cierto tipo de componente o descendiente, simplemente se anida como se hace nativamente en CSS.
.Title { /* ... */ }
.Title.isModified { /* ... */ }
Descendientes
Los descendientes como su nombre lo dice son hijos de un Title, y por tanto dependen de este. Deben ser descritos en camelCase y anidados en CSS.
.Title { /* ... */ }
.Title .descendant { /* ... */ }
Problemas y soluciones
Dos problemas que se nos vienen a la mente al usar esta metodología es: ¿Como distingo una modificación de un descendiente? y ¿Que pasa si tengo un modificador o descendiente anidado con el mismo nombre?
1. ¿Como distingo una modificación de un descendiente?
La respuesta es simple: Por el nombre que escojas. Esta metodología nos fuerza a escoger buenos nombres. Es fácil identificar cual es el modificador y cual es el descendiente entre estas dos opciones: .isDark
y .title
. El nombre debe ser descriptivo y no dar lugar a dudas.
2. ¿Que pasa si tengo un modificador o descendiente anidado con el mismo nombre?
Un ejemplo respecto a este problema es el siguiente HTML.
<div class="Container">
<header class="header"></header>
<main class="body">
<section class="Title">
<div class="header"></div>
<div class="body"></div>
</section>
<section class="Title">
<div class="header"></div>
<div class="body"></div>
</section>
</main>
</div>
Pareciera que hay colisiones de nombre, pero si usamos CSS de la forma natural nos encontraríamos con algo como esto:
.Container {}
.Container > .header {}
.Container > .body {}
Por tanto .header
y .body
solo afectarían al descendiente directo y por tanto, ya no tenemos colisiones de nombre.
Conclusiones
Estas tres convenciones de nombre nos ayudan a tener un mayor dominio de nuestro código. Algunos de los beneficios que podemos encontrar en estas notaciones son:
- Facilita la distinción de componentes, elementos y modificadores de forma clara (posiblemente, Title CSS un poco menos que otros).
- Mantiene baja la especificidad de los selectores (Nuevamente, Title CSS un poco menos que otros).
- Ayuda a desacoplar la semántica de presentación de la semántica de documentos (al hacer uso de clases con nombres coherentes y explicativos).
BEM tiene sus beneficios, y a mi parecer, es la mas conocida de todas. Si bien no describe el uso de utility classes
se puede hacer uso de estas con ayuda de un prefijo u-
o como yo lo prefiero, con dos guiones --
--float-left { float: left; }
Sin embargo, aun cuando el uso de PascalCase o camelCase me choco en un primer momento. Me decanto por SUIT CSS, es a mi parecer la mas completa, y si bien estoy totalmente de acuerdo con Title CSS respecto a lo "molesto" que puede ser clases tan extensas, creo que lo vale. Sobre todo si tienes un editor de código bien configurado que te auto completa, es una maravilla escribir Card--
y ver todas los modificadores que tiene Card.
Por lo demás es decision de cada equipo definir que notación usar, ya sea alguna de estas, alguna otra o una definida por el mismo equipo. Siempre y cuando se sea consistente, todo irá bien.
Top comments (0)