BEM en Vue: Estructurando estilos para componentes escalables
BEM sigue siendo relevante en proyectos Vue gracias a su estricta jerarquía de clases, que evita conflictos de estilos en arquitecturas basadas en componentes. Vue se encarga de la reactividad y la lógica, mientras que BEM asegura que los bloques y elementos permanezcan independientes. Esta combinación minimiza el spaghetti CSS a medida que tu app crece.
BEM se basa en tres principios fundamentales:
- Bloque: Una entidad independiente como
.headero.card, sin dependencias externas. - Elemento: Una subparte de un bloque, denotada con doble guión bajo —
.button__icon. - Modificador: Una variante o estado con guión bajo simple —
.button_disabled,.card_theme_dark.
Esta estructura aísla los estilos, facilitando la depuración y refactorización.
Estilos en componentes Vue
En Vue, los estilos van dentro de <style scoped>, limitando su alcance al componente. Scoped evita fugas de estilos, pero cuidado con el anidamiento profundo.
Usa :deep() solo para integrar librerías externas donde scoped no alcanza. Evítalo para hackear tu propia arquitectura — es una señal de alerta de problemas estructurales.
BEM se combina perfectamente con scoped al agrupar lógicamente las clases. El bloque establece el estilo base, los modificadores manejan variaciones y los elementos gestionan la estructura interna.
Ejemplo práctico: Botón con estados
Sin un sistema, las clases se multiplican de forma caótica. Aquí un error típico:
<template>
<button :class="{
'button-basic': isBasic,
'button-href': isHref,
'button-avatar': isAvatar
}">
{{ text }}
</button>
</template>
Problemas:
- Sin jerarquía: las clases no están ligadas a un bloque.
- Escalabilidad: nuevos estados implican más condiciones.
- Legibilidad: la lógica se pierde con el tiempo.
Con BEM, la plantilla se simplifica y se autodocumenta:
<template>
<button :class="[
'button',
{
'button_disabled': disabled,
'button_loading': loading,
},
{
'button_size_xl': size === 'xl',
'button_size_l': size === 'l',
},
{
'button_primary': color === 'primary',
'button_secondary': color === 'secondary',
}
]">
{{ text }}
</button>
</template>
Las clases se agrupan por semántica: bloque base, estados, tamaños, temas. En CSS:
.button {
/* estilos base */
padding: 12px 24px;
border: none;
border-radius: 4px;
}
.button_disabled {
opacity: 0.5;
cursor: not-allowed;
}
.button_loading {
position: relative;
}
.button_primary:not(.button_disabled):hover {
background-color: #0055ff;
}
El selector :not() filtra estados conflictivos sin clases extra.
Escalabilidad y colaboración en equipo
En proyectos grandes, BEM reduce la carga cognitiva: los desarrolladores ven el bloque y sus modificadores directamente en la plantilla. Sin necesidad de buscar en el CSS para entender los estilos.
Beneficios para el equipo:
- Predecibilidad: los nombres de clases reflejan su propósito.
- Aislamiento: los bloques no interfieren entre sí.
- Extensibilidad: agrega nuevos modificadores sin refactorizar.
Ejemplo de un componente complejo — tarjeta de producto con temas y tamaños:
<template>
<div class="card" :class="[
`card_size_${size}`,
`card_theme_${theme}`
]">
<div class="card__image"></div>
<div class="card__title">{{ title }}</div>
<button class="card__button button">Comprar</button>
</div>
</template>
Los elementos dentro del bloque heredan contexto pero permanecen independientes.
Cuándo evitar BEM
BEM es excesivo para prototipos o landing pages: Tailwind o clases utilitarias son más rápidas. Usa BEM en proyectos a largo plazo con equipos y UIs complejas.
Lecciones clave
- BEM complementa Vue con jerarquía estricta, sin choques con estilos scoped.
- Los modificadores agrupan estados y variantes, simplificando plantillas.
:deep()solo para librerías externas, no para hacks internos.- En proyectos grandes, BEM acelera la incorporación y refactorización.
- Pruébalo en un componente real: la legibilidad mejora al instante.
— Editorial Team
Aún no hay comentarios.