Original article: CSS Naming Conventions that Will Save You Hours of Debugging

He escuchado a muchos desarrolladores decir que odian CSS. En mi experiencia, esto es un resultado de no tomarse el tiempo de aprenderlo.

CSS no es el lenguaje más lindo, pero ha impulsado el estilo de la web desde hace más de 20 años. No le fue tan mal, ¿no?

Sin embargo, a medida que escribes más código en CSS, rápidamente notas una gran desventaja.

Es realmente difícil de mantener.

Código en CSS mal escrito se convierte rápidamente en una pesadilla.

Aquí hay algunas convenciones de nomenclatura que te ahorrarán un poco de estrés y un sinfín de horas a la larga.

0Nm4l3DA3bWTbPc6C4ViWDqewokYYootpoqb
Has estado allí antes, ¿verdad?

Usa cadenas delimitadas con guiones

Si escribes mucho en JavaScript, sabes que escribir variables en camel case es algo usual.

var cajaRoja = document.getElementById('...')

Genial, ¿no?

El problema es que esta forma de nomenclatura no le sienta bien a CSS.

No hagas esto:

.cajaRoja {  contorno: 1px rojo;}

Haz esto:

.caja-roja {   contorno: 1px rojo;}

Esta es una convención de nomenclatura de CSS bastante estándar. Es posiblemente más legible.

Además, es consistente con los nombres de propiedades de CSS.

// Correcto
.alguna-clase {   font-weight: 10em}
// Incorrecto
.alguna-clase {   fontWeight: 10em}

La convención de nomenclatura BEM

Los equipos de desarrollo tienen diferentes estrategias para escribir selectores de CSS. Algunos equipos usan delimitadores de guiones, mientras que otros prefieren usar una convención de nomenclatura más estructurada llamada BEM.

Generalmente, hay 3 problemas que las convenciones de nomenclatura de CSS intentan resolver:

  1. Para saber lo que hace un selector, basta con mirar su nombre
  2. Para saber dónde puede usarse un selector, basta con mirarlo
  3. Para conocer las relaciones entre nombres de clases, basta con mirarlos

¿Alguna vez viste nombres de clases escritos así?:

.nav--secundario {  ...}
.nav__encabezado {  ...}

Esa es la convención de nomenclatura BEM.

Explicando BEM a un niño de 5 años

BEM intenta dividir la interfaz del usuario en pequeñas componentes reutilizables.

Considera esta imagen:

pIFVbUmRtKN8x6DvLHEvJeUSM9Oda8ClkY5f
Es una imagen galardonada de un hombre palo :)

No ganaría ningún premio :(

Esta persona representa un componente, como un bloque de diseño.

Debes haber adivinado a esta altura que la B de BEM es de Bloque.

En el mundo real, este 'bloque' podría representar un sitio, encabezado, pie de página, o cualquier otro bloque de diseño.

Luego, un nombre de clase ideal para esta componente sería persona-de-palitos.

La componente debería escribirse así:

.persona-de-palitos {   }

Usamos cadenas delimitadas aquí. ¡Bien!

ThMVqj-sv26pjpzLJU3MIF2TCdn-S4CjlEZk

E de Elemento

La E de ‘BEM’ viene de Elemento.

Por lo general, los bloques de diseño casi nunca viven aislados.

Por ejemplo, esta persona tiene una cabeza, dos hermosos brazos, y pies.

bf2jyOzcZ8wgd95I3qR9IS3Cf6pRlQ2hHuGM

La cabeza, pies y brazos son todos elementos dentro del componente. Pueden ser vistos como componentes hijos, es decir, hijos del componente padre.

Usando la convención de nomenclatura BEM, los nombres de clases de los elementos se derivan agregando dos guiones bajos, seguidos del nombre del elemento.

Por ejemplo:

.persona-de-palitos__cabeza {
}
.persona-de-palitos__brazos {
}
.persona-de-palitos__pies {
}

M de Modificador

La M de ‘BEM’ es de Modificador.

¿Qué pasaría si la persona fuera modificada y pudiéramos tener una persona azul o roja?

Q-aWWnpw1UuoXxp5NGHxsjP5689VQBT0oGdQ

En el mundo real, esto podría ser un botón rojo o azul. Estas son modificaciones del componente en cuestión.

Usando BEM, los nombres de las clases de los modificadores se derivan agregando dos guiones medios seguidos del nombre del elemento.

Por ejemplo:

.persona-de-palitos--azul {
}
.persona-de-palitos--roja {
}

El último ejemplo muestra el componente padre siendo modificado. Esto no es siempre así.

¿Qué pasaría si tuviéramos personas con distintos tamaños de cabeza?

ZK-riYJhmFfBVEof6xO8yGGR3O10g2dW7Xqn

Esta vez el elemento ha sido modificado. Recordemos que el elemento es un componente hijo del bloque que lo contiene.

La .persona-de-palitos representa el Block, .persona-de-palitos__cabeza el elemento.

Como vimos en el ejemplo de arriba, también podemos usar guiones dobles de la siguiente manera:

.persona-de-palitos__cabeza--pequeña {
}
.persona-de-palitos__cabeza--grande {
}

De nuevo, notar el uso de los guiones dobles en el ejemplo de arriba. Esto se usa para denotar un modificador.

Ahora ya lo tienes.

Esta es la idea básica de cómo funciona la convención de nomenlatura de BEM.

Personalmente, tiendo a usar los nombres de clases delimitados con guion para proyectos simples, y BEM para interfaces que involucran más al usuario.

BEM - Bloque Elemento Modificador

¿Por qué usar convenciones de nomenclatura?

There are only two hard problems in Computer Science: cache invalidation and naming things — Phil Karlton

Nombrar cosas es difícil. Intentamos facilitarlo, y ahorrarnos tiempo en el futuro con código más fácil de mantener.

Nombrar cosas correctamente en CSS va a generar que tu código sea más fácil de leer y mantener.

Si eliges usar la convención de nomenclatura de BEM, se volverá más fácil ver la relación entre tus componentes de diseño/bloques con solo mirarlos en el markup.

¿Te sientes confiado?

Nombres de CSS con hooks de JavaScript

Hoy es el primer día de Juan en su trabajo.

Le dieron un código HTML que se ve así:

<div class="siteNavigation">
</div>

John leyó este artículo y se dio cuenta de que esta puede no ser la mejor manera de nombrar cosas en CSS. Entonces, refactoriza la base de códigos así:

<div class="site-navigation">
</div>

Se ve bien, ¿no?

Para la desgracia de Juan, rompió la base de código.

¿Cómo?

En algún lugar del código de JavaScript, había una relación con el nombre de clase anterior, siteNavigation:

// el código de JavaScript
const nav = document.querySelector('.siteNavigation')

Luego, con el cambio en el nombre de la clase, la variable nav se volvió null.

Qué triste.

Para prevenir casos como este, los desarrolladores pensaron una serie de estrategias.

1. Usa nombres de clases js-

Una forma de mitigar estos bugs es usando un nombre de clase js-* denotando una relación con el elemento DOM en cuestión.

Por ejemplo:

<div class="site-navigation js-site-navigation">
</div>

Y en el código en JavaScript:

// el código en JavaScript
const nav = document.querySelector('.js-site-navigation')

Como convención, cualquier que vea el js-site-navigation como nombre de clase va a entender que hay una relación con ese elemento DOM en el código de JavaScript.

2. Usa el atributo rel

Personalmente, no uso esta técnica, pero he visto a algunos hacerlo.

¿Reconoces esto?

<link rel="stylesheet" type="text/css" href="main.css">

Básicamente, el atributo rel define la relación que tiene el recurso linkeado con el documento desde el que se referencia.

En el ejemplo anterior con Juan, partidarios de esta técnica harían esto:

<div class="site-navigation" rel="js-site-navigation">
</div>

Y en el de JavaScript:

const nav = document.querySelector("[rel='js-site-navigation']")

Tengo mis dudas sobre esta técnica, pero es probable que la encuentres en algunas bases de código. Lo que se suele argumentar es, bueno, hay una relación con JavaScript, entonces uso el atributo rel para denotar esto.

La web es un gran lugar con muchos métodos diferentes para resolver el mismo problema.

3. No uses atributos de datos

Algunos desarrolladores usan atributos de datos como hooks de JavaScript. Esto no está bien. Por definición, los atributos de datos se usan para almacenar data personalizada.

08r5ESO6cpzZvcZz-KczJEGXtPBtCLorryI6
Buen uso de los atributos de datos. Como se ve en Twitter

Editar #1: Como algunas personas mencionaron en los comentarios, si la gente usa el atributo 'rel', entonces quizás está bien usar atributos de datos en ciertos casos. Es tu decisión, después de todo.

Consejo extra: Añade más comentarios en CSS

Esto no tiene nada que ver con convenciones de nomenclatura, pero te ahorrará algo de tiempo.

Mientras que muchos desarrolladores web intentan NO comentar en JavaScript o comentar muy poco, yo creo que deberías comentar más en CSS.

Debido a que CSS no es el lenguaje más elegante, los comentarios bien estructurados pueden ahorrar tiempo cuando estás intentando entender tu código.

No hace daño.

Mira lo bien comentado que está este código fuente de Bootstrap.

No necesitas comentar cosas como color:rojo para decir que algo va a dar el color rojo. Pero si estás usando un truco de CSS menos obvio, siéntete libre de comentar.