Seguimos escribiendo CSS mantenible. Parte 2.

En mi charla del año pasado en el Codemotion expliqué algunos conceptos que utilizamos en Sweetspot y que nos han ayudado a sentar los cimientos de una base de código CSS más extensible y mantenible. Principalmente, la charla se centró en introducir la idea de orientar tu código CSS a componentes y utilizar metodologías de trabajo que te ayuden a reducir pain points del lenguaje como la especificidad o la propia cascada.

Por ajustar la ponencia al tiempo marcado por la organización (45 minutos) y porque no quería exponer demasiados conceptos a la vez, se me quedaron en el tintero otras herramientas que forman parte de mi cinturón de trabajo habitual y que me ayudan a escribir un código CSS más sencillo, dando solución a algunos problemas habituales al trabajar con BEM o CSS orientado a objetos.

Clases de utilidad.

Un punto negativo que se le suele achacar a BEM es su excesiva verbosidad. Al final, esta metodología de trabajo nos ofrece sólo 3 piezas con las que tendremos que construir nuestros componentes: bloques, elementos y modificadores. Por lo que nuestra expresividad con el lenguaje se reduce a cómo de bien seamos capaces de combinarlas.

En mi experiencia, es habitual terminar con una explosión de modificadores que cubren diferentes estados del componente pero que, realmente, no tienen una entidad suficiente como para formar parte de su especificación y terminan generando ruido y un código más complejo de entender.

Para minimizar estas situaciones, las clases de utilidad pueden ser de gran ayuda ya que nos van a permitir añadir pequeñas reglas que decoran los componentes que estamos utilizando para añadir pequeños bits de funcionalidad bajo determinadas circunstancias.

Una clase de utilidad es simplemente un selector que aporta una única propiedad y, además, lo hace con la máxima especificidad (aquí tenemos un caso de uso en el que !important está perfectamente justificado).

En mi caso, por ejemplo, es muy habitual tener un estado en los componentes que represente que está oculto. Sin las clases de utilidad, tendría que crear un modificador para cada componente que implemente esta misma funcionalidad, mientras que con las clases de utilidad, puedo reutilizar esa funcionalidad directamente.

.u-hidden { visibility: hidden !important; }

Las clases de utilidad no son un concepto para nada novedoso y, de hecho, existen metodologías y frameworks de CSS que se basan totalmente en ellas (ver Functional CSS o tachyons) para favorecer la composición y reutilización de pequeñas unidades de CSS.

En un primer momento, puede parecer que muchos modificadores (o incluso bloques y elementos) pueden pasar a ser clases de utilidad. Para mi, la línea que separa una opción de la otra, es el valor que aporta al componente el uso del modificador. Por ejemplo, en un supuesto botón con dos estados: primario y secundario, el uso de los modificadores para añadir propiedades para cada estado, nos ayuda a entender la especificación del componente y alcanzar esa misma funcionalidad mediante la composición de clases de utilidad, nos haría perder información sobre su propia definición.

No todo son componentes. Módulos y Páginas.

Uno de los errores que cometí al principio, visto en perspectiva, es asumir que en una interfaz de usuario todo puede ser considerado un componente.

Esta afirmación, me llevó a menudo a cometer dos tipos de errores:

  • Generar abstracciones para elementos que NO son componentes y que por tanto no son reutilizables.
  • Tener que añadir a la propia especificación del componente su manera de relacionarse con otros elementos de la interfaz (lo que en ocasiones derivó en limitar su reusabilidad).
Un componente es una pieza de interfaz de usuario que representa un concepto bien definido (un botón) y que es reutilizado en diferentes partes de la propia interfaz.

Por ello, es necesario hablar de un nuevo tipo de abstracción que nos permita definir las relaciones entre componentes en una pantalla o recoger aquellas reglas que no tienen cabida dentro de ningún componente pero que son necesarias para estilar una parte concreta de la interfaz. Pero, si estamos utilizando BEM, ¿cómo podemos representar este nuevo tipo de abstracción? Respuesta: como un bloque más, aunque con una serie se consideraciones 🙂

Para los que sigáis el trabajo de Harry Roberts, el concepto de namespaces no os debería de sonar extraño. Con un par de caracteres extra al inicio de los selectores podemos empezar a utilizar diferentes tipos de abstracciones en función de nuestras necesidades. Vamos a verlo con un ejemplo:

Por un lado, las clases de utilidad pueden ser prefijadas con su propio namespace (como ya hemos hecho anteriormente). En este caso, es habitual utilizar el prefijo .u.

Para los componentes, Harry Roberts propone utilizar .c. Personalmente, evito utilizar namespaces en componentes. Los entiendo como la pieza fundamental de mi aplicación y me ayuda a reducir el boilerplate.

Y, por último, podemos utilizar namespaces para prefijar aquellas abstracciones destinadas a poner las reglas específicas de una pantalla utilizando .m (si queremos referirnos a esto como módulos) o .p (si preferimos llamarlo páginas).

<section class="m-login">
<!-- some implementation details... -->
<div class="m-login__footer">
<button class="m-login__button button button--is-primary">
Log in
</button>
<button class="m-login__button button button--is-secondary">
Sign up
</button>
</div>
</section>

En un markup como el del ejemplo anterior, las reglas específicas sobre la colocación de los botones en esta pantalla o cómo se relacionan ambos entre ellos (en cuanto a posicionamiento, por ejemplo) se pueden encapsular dentro del propio módulo de .m-login, dejando libre al componente de gestionar comportamientos que, potencialmente, no serán reutilizables en otras partes de la interfaz.

Referencias

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.