BEM para principiantes: por qué necesita BEM

Publicado: 2022-03-10
Resumen rápido ↬ El aislamiento de estilos CSS es el punto de inicio más frecuente del uso de BEM. Pero esto es lo mínimo que BEM te puede dar. BEM aporta un enfoque de sistema en su proyecto y lo mantiene alejado del desorden.

BEM hace que su código sea escalable y reutilizable, aumentando así la productividad y facilitando el trabajo en equipo. Incluso si eres el único miembro del equipo, BEM puede serte útil. Sin embargo, muchos desarrolladores creen que un enfoque de sistema como BEM pone límites adicionales a su proyecto y hace que su proyecto se sobrecargue, sea engorroso y lento.

Recopilaremos todos los aspectos principales de BEM de forma resumida. Este artículo lo ayuda a comprender las ideas básicas de BEM en solo 20 minutos y a rechazar los prejuicios de que el enfoque de sistema es perjudicial para su proyecto.

El Big BEM consta de Metodología , Tecnologías , Bibliotecas y Herramientas . En este artículo, hablaremos más sobre la metodología en sí porque es la experiencia concentrada de una gran cantidad de desarrolladores y aporta un enfoque sistemático a cualquier proyecto.

Para mostrarle algunos casos prácticos de BEM, tocaremos las tecnologías BEM y omitiremos por completo las bibliotecas y herramientas.

De la teoría a la práctica:

  • Las principales razones por las que no usamos ningún selector excepto las clases
  • Los fundamentos de BEM
    • bloques y elementos
    • Modificadores y mezclas
    • Bloques en la estructura de archivos
  • Ventajas no evidentes de la metodología
  • Caso práctico: BEM no es solo para CSS
  • BEM es un sistema personalizable

Entonces, ¿BEM es un héroe o un villano? ¡Tu decides! Pero primero, lee el artículo.

BEM como logotipo de Batman
BEMBatman
¡Más después del salto! Continúe leyendo a continuación ↓

Las principales razones por las que no usamos ningún selector excepto las clases

Una de las reglas básicas de la metodología BEM es utilizar únicamente selectores de clase. En esta sección, explicaremos por qué.

  • ¿Por qué no usamos identificaciones?
  • ¿Por qué no usamos selectores de etiquetas?
  • ¿Por qué no usamos un selector universal?
  • ¿Por qué no usamos el reinicio de CSS?
  • ¿Por qué no usamos selectores anidados?
  • ¿Por qué no combinamos una etiqueta y una clase en un selector?
  • ¿Por qué no usamos selectores combinados?
  • ¿Por qué no usamos selectores de atributos?

No usamos identificaciones (selectores de identificaciones)

El ID proporciona un nombre único para un elemento HTML. Si el nombre es único, no puede reutilizarlo en la interfaz. Esto le impide reutilizar el código.

Conceptos erróneos comunes

  1. Se requieren ID para usar JavaScript.
    Los navegadores modernos pueden trabajar con ID o clases. Cualquier tipo de selector se procesa a la misma velocidad en el navegador.
  2. Los ID se utilizan con la <label> .
    Si coloca <label> dentro de un control, no necesita una identificación. En lugar de <input id="ID"><label for="ID">Text</label> , simplemente use <label><input type="...">Text</label> .

No usamos selectores de etiquetas

El marcado de la página HTML es inestable: un nuevo diseño puede cambiar el anidamiento de las secciones, los niveles de encabezado (por ejemplo, de <h1> a <h3> ) o convertir el párrafo <p> en la etiqueta <div> . Cualquiera de estos cambios romperá los estilos escritos para las etiquetas. Incluso si el diseño no cambia, el conjunto de etiquetas es limitado. Para usar un diseño existente en otro proyecto, debe resolver conflictos entre estilos escritos para las mismas etiquetas.

Un conjunto extendido de etiquetas semánticas tampoco puede satisfacer todas las necesidades de diseño.

Un ejemplo es cuando el encabezado de la página contiene un logotipo. Un clic en el logotipo abre la página principal del sitio ( index ). Puede marcarlo con etiquetas usando la etiqueta <img> para la imagen y la etiqueta <a> para el enlace.

 <header> <a href="/"> <img src="img.logo.png" alt="Logo"> </a> </header>

Para distinguir entre el enlace del logotipo y un enlace normal en el texto, necesita estilos adicionales. Ahora elimine el subrayado y el color azul del enlace del logotipo:

 header a { ... }

El enlace del logotipo no necesita mostrarse en la página principal, así que cambie el marcado de la página de índice:

 <header> <!-- the <a> tag is replaced with <span> --> <span> <img src="img.logo.png" alt="Logo"> </span> </header>

No es necesario que elimine el subrayado y el color azul de la etiqueta <span> . Entonces, establezcamos reglas generales para el enlace del logotipo desde diferentes páginas:

 header a, header span { ... }

A primera vista, este código parece estar bien, pero imagina que el diseñador elimina el logotipo del diseño. Los nombres del selector no lo ayudan a comprender qué estilos deben eliminarse del proyecto con el logotipo. El selector “header a” no muestra la conexión entre el enlace y el logo. Este selector podría pertenecer al enlace del menú de cabecera o, por ejemplo, al enlace al perfil del autor. El selector de "intervalo de encabezado" podría pertenecer a cualquier parte del encabezado.

Para evitar confusiones, solo use el selector de clase de logo para escribir los estilos de logotipo:

 .logo { ... }

No utilizamos el restablecimiento de CSS

El restablecimiento de CSS es un conjunto de reglas CSS globales creadas para toda la página. Estos estilos afectan a todos los nodos de diseño, violan la independencia de los componentes y dificultan su reutilización.

En BEM, "restablecer" y "normalizar" ni siquiera se usan para un solo bloque. El restablecimiento y la normalización cancelan los estilos existentes y los reemplazan con otros estilos, que deberá cambiar y actualizar más adelante en cualquier caso. Como resultado, el desarrollador tiene que escribir estilos que anulen los que se acaban de restablecer.

No usamos el selector universal ( * )

El selector universal indica que el proyecto presenta un estilo que afecta a todos los nodos del diseño. Esto limita la reutilización del diseño en otros proyectos:

  • Además, debe transferir los estilos con un asterisco al proyecto. Pero en este caso, el selector universal podría afectar los estilos en el nuevo proyecto.
  • Los estilos con un asterisco deben agregarse al diseño que está transfiriendo.

Además, un selector universal puede hacer que el código del proyecto sea impredecible. Por ejemplo, puede afectar los estilos de los componentes de la biblioteca universal.

Los estilos comunes no le ahorran tiempo. A menudo, los desarrolladores comienzan restableciendo todos los márgenes de los componentes ( * { margin: 0; padding: 0; } ), pero luego los configuran igual que en el diseño (por ejemplo, margin: 12px; padding: 30px; ).

No usamos selectores anidados

Los selectores anidados aumentan el acoplamiento del código y dificultan la reutilización del código.

La metodología BEM no prohíbe los selectores anidados, pero recomienda no usarlos demasiado. Por ejemplo, el anidamiento es apropiado si necesita cambiar los estilos de los elementos según el estado del bloque o su tema asignado.

 .button_hovered .button__text { text-decoration: underline; } .button_theme_islands .button__text { line-height: 1.5; }

No usamos selectores combinados

Los selectores combinados son más específicos que los selectores únicos, lo que dificulta la redefinición de bloques.

Considere el siguiente código:

 <button class="button button_theme_islands">...</button>

Supongamos que establece reglas CSS en el selector .button.button_theme_islands para escribir menos. Luego agrega el modificador "activo" al bloque:

 <button class="button button_theme_islands button_active">...</button>

El selector .button_active no redefine las propiedades del bloque escritas como .button.button_theme_islands porque .button.button_theme_islands es más específico que .button_active . Para redefinirlo, combine el selector modificador de bloques con el selector .button y declárelo debajo de .button.button_theme_islands porque ambos selectores son igualmente específicos:

 .button.button_theme_islands {} .button.button_active {}

Si usa selectores de clase simples, no tendrá problemas para redefinir los estilos:

 .button_theme_islands {} .button_active {} .button {}

No combinamos una etiqueta y una clase en un selector

Combinar una etiqueta y una clase en el mismo selector (por ejemplo, button.button ) hace que las reglas de CSS sean más específicas, por lo que es más difícil redefinirlas.

Considere el siguiente código:

 <button class="button">...</button>

Supongamos que establece reglas CSS en el selector button.button . Luego agrega el modificador active al bloque:

 <button class="button button_active">...</button>

El selector .button_active no redefine las propiedades del bloque escritas como button.button porque button.button es más específico que .button_active . Para hacerlo más específico, debe combinar el selector de modificador de bloque con la etiqueta button.button_active .

A medida que se desarrolla el proyecto, es posible que termine con bloques con input.button , span.button o a.button . En este caso, todos los modificadores del bloque de button y todos sus elementos anidados requerirán cuatro declaraciones diferentes para cada instancia.

Posibles excepciones

En casos excepcionales, la metodología permite combinar selectores de etiquetas y clases. Por ejemplo, esto se puede usar para configurar el estilo de los comentarios en los sistemas CMS que no pueden generar el diseño correcto.

Puede usar el comentario para escribir un texto, insertar imágenes o agregar marcas. Para que coincidan con el diseño del sitio, el desarrollador puede predefinir estilos para todas las etiquetas disponibles para el usuario y distribuirlos en cascada en los bloques anidados:

 <div class="content"> ... <!-- the user's text --> </div> CSS rules: .content a { ... } .content p { font-family: Arial, sans-serif; text-align: center; }

No utilizamos selectores de atributos

Los selectores de atributos son menos informativos que los selectores de clases. Como prueba, considere un ejemplo con un formulario de búsqueda en el encabezado:

 <header> <form action="/"> <input name="s"> <input type="submit"> </form> </header>

Intente usar atributos de selector para escribir los estilos de formulario:

 header input[type=submit], header input[type=checkbox] { width: auto; margin-right: 20px; } header input[type=checkbox] { margin: 0; }

En este ejemplo, no puede saber con certeza por el nombre del selector que los estilos pertenecen al formulario de búsqueda. El uso de clases lo hace más claro. Las clases no tienen restricciones que te impidan escribir con claridad. Por ejemplo, puedes escribirlo así:

 .form .search { ... }

Ahora el código es menos ambiguo y está claro que los estilos pertenecen al formulario de búsqueda.

Pero los selectores anidados aún hacen que las reglas de CSS sean más específicas y evitan que transfieras el diseño entre proyectos. Para deshacerse de la anidación, utilice los principios BEM.

Resumen : class es el único selector que le permite aislar los estilos de cada componente en el proyecto; aumentar la legibilidad del código y no limitar la reutilización del diseño.

El aislamiento de estilos CSS es el punto de inicio más frecuente del viaje BEM. Pero esto es lo mínimo que BEM te puede dar. Para comprender cómo se organizan los componentes independientes aislados en BEM, debe aprender los conceptos básicos, es decir, bloque, elemento, modificador y mezcla. Hagamos esto en la siguiente sección.

Los fundamentos de BEM

  • bloques y elementos
  • Modificadores y mezclas
  • Bloques en la estructura de archivos

bloque y elementos

La metodología BEM es un conjunto de reglas universales que se pueden aplicar independientemente de las tecnologías utilizadas, como CSS, Sass, HTML, JavaScript o React.

BEM ayuda a resolver las siguientes tareas:

  • Reutilice el diseño;
  • Mueva fragmentos de diseño dentro de un proyecto de forma segura;
  • Mueva el diseño terminado entre proyectos;
  • Crear código estable, predecible y claro;
  • Reducir el tiempo de depuración del proyecto.

En un proyecto BEM, la interfaz consta de bloques que pueden incluir elementos. Los bloques son componentes independientes de la página. Un elemento no puede existir fuera del bloque, así que ten en cuenta que cada elemento puede pertenecer a un solo bloque.

Las dos primeras letras de BEM representan bloques y elementos. El nombre del bloque siempre es único. Establece el espacio de nombres para los elementos y proporciona una conexión visible entre las partes del bloque. Los nombres de los bloques son largos pero claros para mostrar la conexión entre los componentes y evitar perder alguna parte de estos componentes al transferir el diseño.

Para ver todo el poder de la denominación BEM, considere este ejemplo con un formulario. De acuerdo con la metodología BEM, el formulario se implementa utilizando el bloque de form . En HTML, el nombre del bloque se incluye en el atributo de class :

 <form class="form" action="/">

Todas las partes del formulario (el bloque de form ) que no tienen sentido por sí mismas se consideran sus elementos. Entonces, el cuadro de búsqueda ( search ) y el botón ( submit ) son elementos del bloque de form . Las clases también indican que un elemento pertenece al bloque:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

Tenga en cuenta que el nombre del bloque está separado del nombre del elemento con un separador especial. En el esquema de nomenclatura clásico de BEM, se utilizan dos guiones bajos como separador. Cualquier cosa puede funcionar como separador. Existen convenciones de nomenclatura alternativas, y cada desarrollador elige la que más le convenga. Lo importante es que los separadores te permiten distinguir bloques de elementos y modificadores mediante programación.

Los nombres de los selectores dejan en claro que para mover el formulario a otro proyecto, debe copiar todos sus componentes:

 .form__search {} .form__submit {}

El uso de bloques y elementos para los nombres de las clases resuelve un problema importante: nos ayuda a deshacernos de los selectores anidados. Todos los selectores en un proyecto BEM tienen el mismo peso. Eso significa que es mucho más fácil redefinir estilos escritos según BEM. Ahora, para usar el mismo formulario en otro proyecto, simplemente puede copiar su diseño y estilos.

La idea de la denominación de los componentes BEM es que puede definir explícitamente la conexión entre el bloque y sus elementos.

Modificadores y mezclas

Oficialmente, "M" significa M odifier, pero también implica una noción más importante en BEM: "mix". Tanto los modificadores como las mezclas realizan cambios en un bloque y sus elementos. Echemos un vistazo más de cerca a esto.

Modificadores

Un modificador define el aspecto, el estado y el comportamiento de un bloque o un elemento. Agregar modificadores es opcional. Los modificadores le permiten combinar diferentes funciones de bloque, ya que puede usar cualquier número de modificadores. Pero a un bloque oa un elemento no se le pueden asignar diferentes valores del mismo modificador.

Exploremos cómo funcionan los modificadores.

Imagina que el proyecto necesita el mismo formulario de búsqueda que en el ejemplo anterior. Debe tener las mismas funciones pero verse diferente (por ejemplo, los formularios de búsqueda en el encabezado y en el pie de página deben ser diferentes). Lo primero que puede hacer para cambiar la apariencia del formulario es escribir estilos adicionales:

 header .form {} footer .form {}

El selector header .form tiene más peso que el selector de form , lo que significa que una regla anulará a la otra. Pero como hemos discutido, los selectores anidados aumentan el acoplamiento del código y dificultan la reutilización, por lo que este enfoque no funciona para nosotros.

En BEM, puede usar un modificador para agregar nuevos estilos al bloque:

 <!-- Added the form_type_original modifier--> <form class="form form_type_original" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

La línea <form class="form form_type_original"></form> indica que al bloque se le asignó un modificador de type con el valor original . En un esquema clásico, el nombre del modificador se separa del nombre del bloque o elemento con un guión bajo.

El formulario puede tener un color, tamaño, tipo o tema de diseño únicos. Todos estos parámetros se pueden configurar con un modificador:

 <form class="form form_type_original form_size_m form_theme_forest"> <form class="form form_type_original form_size_m form_theme_forest">

La misma forma puede verse diferente pero permanecer del mismo tamaño:

 <form class="form form_type_original form_size_m form_theme_forest"></form> <form class="form form_type_original form_size_m form_theme_sun"></form>

Pero los selectores de cada modificador seguirán teniendo el mismo peso:

 .form_type_original {} .form_size_m {} .form_theme_forest {}

Importante : un modificador contiene solo estilos adicionales que cambian la implementación del bloque original de alguna manera. Esto le permite configurar la apariencia de un bloque universal solo una vez y agregar solo aquellas características que difieren del código de bloque original en los estilos modificadores.

 .form { /* universal block styles */ } .form_type_original { /* added styles */ }

Esta es la razón por la que un modificador siempre debe estar en el mismo nodo DOM con el bloque y el elemento al que está asociado.

 <form class="form form_type_original"></form>

Puede usar modificadores para aplicar componentes universales en casos muy específicos. El código del bloque y del elemento no cambia. La combinación necesaria de modificadores se crea en el nodo DOM.

mezclas

Una combinación le permite aplicar el mismo formato a diferentes elementos HTML y combinar el comportamiento y los estilos de varias entidades evitando la duplicación de código. Pueden reemplazar bloques de envoltura abstractos.

Una combinación significa que aloja varias entidades BEM (bloques, elementos, modificadores) en un solo nodo DOM. Al igual que los modificadores, las mezclas se utilizan para cambiar bloques. Veamos algunos ejemplos de cuándo debes usar una mezcla.

Los bloques pueden diferir no solo visualmente sino también semánticamente. Por ejemplo, un formulario de búsqueda, un formulario de registro y un formulario para pedir pasteles son todos formularios. En el diseño, se implementan con el bloque "formulario" pero no tienen ningún estilo en común. Es imposible manejar tales diferencias con un modificador. Puede definir estilos comunes para dichos bloques, pero no podrá reutilizar el código.

 .form, .search, .register { ... }

Puede usar una combinación para crear bloques semánticamente diferentes para el mismo formulario:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

El selector de clases .form describe todos los estilos que se pueden aplicar a cualquier formulario (pedido, búsqueda o registro):

 .form {}

Ahora puedes hacer un formulario de búsqueda desde el formulario universal. Para hacer esto, cree una clase de search adicional en el proyecto. Esta clase será responsable únicamente de la búsqueda. Para combinar los estilos y el comportamiento de las clases .form y .search , coloque estas clases en un solo nodo DOM:

 <form class="form search" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

En este caso, la clase .search es un bloque separado que define el comportamiento. Este bloque no puede tener modificadores responsables de la forma, temas y tamaños. Estos modificadores ya pertenecen a la forma universal. Una mezcla ayuda a combinar los estilos y el comportamiento de estos bloques.

Tomemos un ejemplo más donde se cambia la semántica del componente. Aquí hay un menú de navegación en el encabezado de la página en el que todas las entradas son enlaces:

 <nav class="menu"> <a class="link" href=""></a> <a class="link" href=""></a> <a class="link" href=""></a> </nav>

La funcionalidad de enlace ya está implementada en el bloque de link , pero los enlaces del menú tienen que diferir visualmente de los enlaces en el texto. Hay varias formas de cambiar los enlaces del menú:

  1. Cree un modificador de entrada de menú que convierta la entrada en un enlace:
     <nav class="menu"> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> </nav>

    En este caso, para implementar el modificador, debe copiar el comportamiento y los estilos del bloque `link`. Esto conducirá a la duplicación de código.
  2. Usa una combinación del bloque universal `link` y el elemento `item` del bloque `menu`:
     <nav class="menu"> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> </nav>

    Con la combinación de las dos entidades BEM, ahora puede implementar la funcionalidad de enlace básica desde el bloque "enlace" y reglas CSS adicionales desde el bloque "menú", y evitar la duplicación de código.

Geometría externa y posicionamiento: Renunciar a los envoltorios HTML abstractos

Las mezclas se utilizan para colocar un bloque en relación con otros bloques o para colocar elementos dentro de un bloque. En BEM, los estilos responsables de la geometría y el posicionamiento se establecen en el bloque principal. Tomemos un bloque de menú universal que debe colocarse en el encabezado. En el diseño, el bloque debe tener una sangría de 20 px del bloque principal.

Esta tarea tiene varias soluciones:

  1. Escriba estilos con sangrías para el bloque de menú:
     .menu { margin-left: 20px; }

    En este caso, el bloque "menú" ya no es universal. Si tiene que colocar el menú en el pie de página, tendrá que editar estilos porque las sangrías probablemente serán diferentes.
  2. Cree el modificador de bloque de menú:
     <div> <ul class="menu menu_type_header"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
     .menu_type_header { margin-left: 20px; } .menu_type_footer { margin-left: 30px; }

    En este caso, el proyecto incluirá dos tipos de menús, aunque no es así. El menú sigue siendo el mismo.
  3. Defina el posicionamiento externo del bloque: anide el bloque `menu` en el contenedor abstracto (por ejemplo, el bloque `wrap`) configurando todas las sangrías:
     <div class="wrap"> <ul class="menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

    Para evitar la tentación de crear modificadores y cambiar los estilos de bloque para colocar el bloque en la página, debe comprender una cosa:

    La sangría de un bloque principal no es una característica del bloque anidado. Es una característica del bloque principal. Tiene que saber que el bloque anidado tiene que estar sangrado desde el borde por un cierto número de píxeles.
  4. Usa una mezcla. La información sobre el posicionamiento del bloque anidado se incluye en los elementos del bloque principal. Luego, el elemento del bloque principal se mezcla con el bloque anidado. En este caso, el bloque anidado no especifica ninguna sangría y se puede reutilizar fácilmente en cualquier lugar.

Sigamos con nuestro ejemplo:

 <div> <ul class="menu header__menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

En este caso, la geometría externa y el posicionamiento del bloque de menu se establecen a través del elemento header__menu . El bloque de menu no especifica ninguna sangría y se puede reutilizar fácilmente.

El elemento del bloque padre (en nuestro caso es header__menu ) realiza la tarea de los bloques contenedores responsables del posicionamiento externo del bloque.

Bloques en la estructura de archivos

Todos los proyectos BEM tienen una estructura de archivos similar. La estructura de archivos familiar facilita a los desarrolladores navegar por el proyecto, cambiar entre proyectos y mover bloques de un proyecto a otro.

La implementación de cada bloque se almacena en una carpeta de proyecto separada. Cada tecnología (CSS, JavaScript, pruebas, plantillas, documentación, imágenes) está en un archivo separado.

Por ejemplo, si la apariencia del bloque de input se configura con CSS, el código se guarda en el archivo input.css .

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript

El código para modificadores y elementos también se almacena en archivos separados del bloque. Este enfoque le permite incluir en la compilación solo aquellos modificadores y elementos que son necesarios para la implementación del bloque.

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript input_theme_sun.css # The "input_theme_sun" modifier implementation input__clear.css # The "input__clear" element implementation with CSS input__clear.js # The "input__clear" element implementation with JavaScript

Para mejorar la navegación del proyecto, combine modificadores de bloque con múltiples valores en directorios.

La estructura de archivos de cualquier proyecto BEM consta de niveles de redefinición (puede obtener más información sobre ellos aquí). Los niveles de redefinición le permiten:

  • Divide el proyecto en plataformas;
  • Actualice fácilmente las bibliotecas de bloques incluidas en el proyecto;
  • Use bloques comunes para desarrollar múltiples proyectos;
  • Cambie los temas de diseño sin afectar la lógica del proyecto;
  • Realizar experimentos en un proyecto en vivo.

El uso de bloques y el almacenamiento de todas las tecnologías de bloques en la misma carpeta facilita el movimiento de bloques entre proyectos. Para mover todos los estilos y el comportamiento del bloque junto con el diseño, simplemente copie la carpeta del bloque al nuevo proyecto.

Ventajas no evidentes de la metodología

La conveniencia del desarrollo paralelo

En BEM, cualquier diseño se divide en bloques. Debido a que los bloques son independientes, varios desarrolladores pueden desarrollarlos en paralelo.

Un desarrollador crea un bloque como un componente universal que se puede reutilizar en cualquier otro proyecto.

Un ejemplo es la biblioteca de bloques bem-components, que contiene bloques universales, como un enlace, un botón y un campo de entrada. Es más fácil crear bloques más complejos a partir de componentes universales. Por ejemplo, un selector o una casilla de verificación.

El uso de bloques en el diseño del proyecto lo ayuda a ahorrar tiempo en la integración de código escrito por varios desarrolladores, garantiza la unicidad de los nombres de los componentes y le permite probar bloques en la etapa de desarrollo.

Probando el diseño

Es problemático probar la funcionalidad de toda la página, especialmente en un proyecto dinámico conectado a una base de datos.

En BEM, cada bloque está cubierto por pruebas. Las pruebas son una tecnología de implementación de bloques, como Javascript o CSS. Los bloques se prueban en la etapa de desarrollo. Es más fácil verificar la corrección de un bloque y luego ensamblar el proyecto a partir de bloques probados. Después de eso, todo lo que tiene que hacer es asegurarse de que la envoltura de bloques funcione correctamente.

Construcción personalizable de un proyecto

Para un desarrollo conveniente, todos los bloques y tecnologías en un proyecto BEM se colocan en carpetas y archivos separados. Para combinar los archivos fuente en un solo archivo (por ejemplo, para colocar todos los archivos CSS en project.css , todos los archivos JS en project.js , etc.), usamos el proceso de compilación.

La compilación realiza las siguientes tareas:

  • Combina archivos de origen que se distribuyen en el sistema de archivos del proyecto;
  • Incluye solo los bloques, elementos y modificadores (entidades BEM) necesarios en el proyecto;
  • Sigue el orden de inclusión de entidades;
  • Procesa el código del archivo fuente durante la compilación (por ejemplo, compila MENOS código en código CSS).

Para incluir solo las entidades BEM necesarias en la compilación, debe crear una lista de bloques, elementos y modificadores utilizados en las páginas. Esta lista se llama declaración .

Dado que los bloques BEM se desarrollan de forma independiente y se colocan en archivos separados en el sistema de archivos, no "saben" nada unos de otros. Para construir bloques basados ​​en otros bloques, especifique las dependencias. Hay una tecnología BEM responsable de esto: los archivos deps.js Los archivos de dependencia permiten que el motor de compilación sepa qué bloques adicionales deben incluirse en el proyecto.

Caso práctico: BEM no es solo para CSS

En las secciones anteriores, todos los ejemplos de código son para CSS. Pero BEM te permite modificar el comportamiento del bloque y su representación en HTML de la misma forma declarativa que en CSS.

Cómo usar plantillas en BEM

En HTML, el marcado del bloque se repite cada vez que aparece el bloque en la página. Si crea el marcado HTML manualmente y luego necesita corregir un error o realizar cambios, deberá modificar el marcado para cada instancia del bloque. Para generar código HTML y aplicar correcciones automáticamente, BEM utiliza plantillas; los bloques son responsables de la forma en que se presentan en HTML.

Las plantillas le permiten:

  • Reduzca el tiempo utilizado para la depuración del proyecto, porque los cambios de plantilla se aplican automáticamente a todos los bloques del proyecto;
  • Modificar el diseño del bloque;
  • Mueva bloques con el diseño actual a otro proyecto.

BEM utiliza el motor de plantillas bem-xjst que presenta dos motores:

  • BEMHTML
    Transforma la descripción BEMJSON de la página a HTML. Las plantillas se describen en archivos .bemhtml.js.
  • BEMTREE
    Transforma datos a BEMJSON. Las plantillas se describen en formato BEMJSON en archivos .bemtree.js.

Si no se escriben plantillas para los bloques, el motor de plantillas establece la etiqueta <div> para los bloques de forma predeterminada.

Compare la declaración de los bloques y la salida HTML:

Declaración:

 { block: 'menu', content: [ { elem: 'item', content: { block: 'link'} }, { elem: 'item', elemMods: { current: true }, // Set the modifier for the menu item content: { block: 'link' } } ] }

HTML:

 <div class="menu"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div>

Para modificar el diseño del bloque de menu , debe escribir plantillas para el bloque:

  1. Cambiemos la etiqueta del bloque de menu :
     block('menu')( tag()('menu') // Set the "menu" tag for the menu block )

    HTML modificado:
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </menu>

    Similar a CSS, la plantilla se aplica a todos los bloques de "menú" en la página.
  2. Agregue un elemento adicional ( menu__inner ) que funciona como un envoltorio interno y es responsable del diseño de los elementos en el bloque de menu . Originalmente, el elemento menu__inner no estaba incluido en la declaración, por lo que debemos agregarlo cuando se construyen las plantillas.

    Las plantillas BEM están escritas en JavaScript, por lo que también puede usar JavaScript para agregar un nuevo elemento a la plantilla:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content }; }) )
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__inner"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div> </menu>
  3. Reemplazar etiquetas para todos los elementos inner y item :
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) )
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <div class="link"></div> </li> <li class="menu__item menu__item_current"> <div class="link"></div> </li> </ul> </menu>
  4. Establezca la etiqueta <a> para todos los enlaces en la página:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) ); block('link')( tag()('a') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <a class="link"></a> </li> <li class="menu__item menu__item_current"> <a class="link"></a> </li> </ul> </menu>
  5. Modificar la plantilla existente. Las reglas en las plantillas se aplican de la misma manera que en CSS: una regla inferior anula una regla superior. Agregue nuevas reglas a la plantilla y cambie la etiqueta del enlace de <a> a <span> :
     block('link')( tag()('a') ); block('link')( tag()('span') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <span class="link"></span> </li> <li class="menu__item menu__item_current"> <span class="link"></span> </li> </ul> </menu>

BEM es un sistema personalizable

La metodología BEM le proporciona reglas estrictas para crear un sistema en su proyecto. Pero al mismo tiempo, se pueden personalizar muchas reglas BEM. La metodología BEM le permite cambiar la convención de nomenclatura, elegir la estructura de archivos más conveniente o agregar cualquier tecnología que desee al bloque.

¡Ahora puedes sintonizar el sistema y crear tu propio superhéroe de BEM!

BEM como logotipo del Capitán América
BEM Capitán América

Cómo sacar más provecho de BEM

Para comenzar a aprender los principios de BEM, visite nuestro sitio web. Si tiene alguna pregunta que le gustaría hacerle al equipo, únase a nuestro canal de Telegram o abra una discusión en nuestro Foro BEM.