DEV Community

Ignacio Cuadra
Ignacio Cuadra

Posted on

CSS - Convenciones de nombres: BEM, SUIT CSS y Title CSS

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; }
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode

Bien

.card__title { color: #111; }
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode

Bien

.card--dark { background-color: #111; }
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode
.card__sub_title { color: #111; }
Enter fullscreen mode Exit fullscreen mode

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 { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode

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 { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

Los sub-componentes deben estar escritos en camelCase deben tener de prefijo a su componente padre separado por un guion.

.Card-title { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

A su vez, los componentes pueden tener modificadores, descritos en camelCase y separados por dos guiones.

.Card--dark { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

Un ejemplo de todos esto utilizado a la vez sería el siguiente:

.twt-Card-title--bold { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

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 { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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 { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

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 { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

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 { /* ... */ }
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 {}
Enter fullscreen mode Exit fullscreen mode

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; }
Enter fullscreen mode Exit fullscreen mode

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.

Referencias

Top comments (0)