Arquitectura OOCSS / BEM / SMACSS

8

He estado trabajando en este artículo para organizar mi código front-end. Hace referencia a artículos sobre BEM / SMACSS, que a su vez hacen referencia a otros artículos.

Realmente estoy tratando de entender cuáles son las mejores prácticas ... Tengo unos días para establecer este "estándar", y luego tengo que pasar por un proyecto de línea de tiempo de alta prioridad / alta visibilidad / limitado. Como tal, me gustaría asegurarme de que estoy comenzando con una base que escalará como lo hace mi aplicación.

Dado un componente llamado segment... Estoy creando páginas que tendrán ~ 10 segmentspor página. Cada uno segmentcompartirá la misma clase base. Sin embargo, algunos segmentstendrán modificadores (diferentes colores de fondo). Además, los elementos dentro de cada bloque (en el enfoque BEM) también tendrán modificadores. Para demostrar, aquí hay una implementación simple (con un solo elemento arrow, mientras que mi sitio completo tendrá 4-5 elementos en cada uno segment):

.segment__arrow {
    position: absolute;
    bottom: -24px;
    left: 50%;
    margin-left: -11px;
    background-position: center no-repeat;
    height: 21px;
    width: 21px;
    z-index: 2;
}
.segment__arrow--orange {
    @extend .segment__arrow;
    background-image: url('/images/arrow_orange.png');
}
.segment__arrow--white {
    @extend .segment__arrow;
    background-image: url('/images/arrow_white.png');
}

Entonces este es el enfoque de clase única:

<div class="segment__arrow--white"> ... </div>

Alternativamente, podría ir con el enfoque de múltiples clases:

.segment__arrow {
    position: absolute;
    bottom: -24px;
    left: 50%;
    margin-left: -11px;
    background-position: center no-repeat;
    height: 21px;
    width: 21px;
    z-index: 2;
}
.segment__arrow--orange {
    background-image: url('/images/arrow_orange.png');
}
.segment__arrow--white {
    background-image: url('/images/arrow_white.png');
}

Donde estaría mi marcado:

<div class="segment__arrow segment__arrow--white"> ... </div>

En tercer lugar, podría hacer:

.segment__arrow {
    position: absolute;
    bottom: -24px;
    left: 50%;
    margin-left: -11px;
    background-position: center no-repeat;
    height: 21px;
    width: 21px;
    z-index: 2;
}
.segment__arrow.orange {
    background-image: url('/images/arrow_orange.png');
}
.segment__arrow.white {
    background-image: url('/images/arrow_white.png');
}

Y entonces mi clase def sería

<div class="segment__arrow orange"> ... </div>

Quizás incluso el espacio de nombres naranja con algo como sa_orangeevitar selectores sueltos.

El resultado final que estoy buscando es menos código / más fácil de mantener (lo que probablemente descarta el enfoque de clase única (opción 1), como se describe en este gran artículo sobre arquitectura escalable. El enfoque de varias clases (opción 2) da como resultado mucha verbosidad (especialmente en mi HTML), pero es extremadamente explícito. El tercero usa un enfoque de varias clases, pero no usa modificadores de espacio de nombres (como .segment__arrow), por lo que es un poco menos detallado (pero también menos explícito y más alto) potencial de colisiones).

¿Alguien con experiencia en el mundo real con estas cosas tiene algún comentario sobre la mejor manera de abordar esto?

Scott Silvi
fuente
Desacoplar los modificadores de los elementos va en contra de estos principios, ¿verdad? .orangeno tiene significado solo como modificador. No veo un gran problema al usarlo .segment__arrow--orangejunto con su enfoque multiclase. Por supuesto, en proyectos más grandes, su HTML podría estar un poco fuera de control (muchas clases).
kleinfreund
Lejos de vacaciones. Gracias por la respuesta. Sí, por eso he estado sorteando la tercera opción. Estás en lo cierto, va en contra de estos principios, pero a medida que un proyecto escala, me imagino una clase = "segmento__arrow segmento__arrow - naranja segmento__arrow - es visible segmento__arrow - algo más" ... y eso simplemente comienza a tener un código de bits maloliente para mí ...
Scott Silvi
Cierto. No se debe conducir todo este bus BEM demasiado lejos. No todo necesita ser BEMificado.
kleinfreund

Respuestas:

8

Durante mucho tiempo he estado usando y recomendando el enfoque explícito de varias clases (el segundo ejemplo), ya que es el más universal, sostenible y coherente. Aquí intentaré respaldar esta afirmación.

Clase individual

Este enfoque tiene un gran problema cuando hay dos o más categorías de modificadores. Por ejemplo, un botón con modificadores pequeño , grande , enorme para el tamaño y primario , éxito , información y advertencia de "color". Además de las 7 clases habituales (= 3 + 4), también se deben crear las 12 combinaciones:

.button--small--primary
.button--small--success
.button--small--info

Hasta ahora un poco incómodo pero no un desastre.

Otra molestia, una más grande, es que debe usarse el orden correcto "tamaño primero, color segundo" y, por lo tanto, debe recordarse (y estar bien documentado).

Lo peor es cuando JavaScript está involucrado. ¿Quiere cambiar el "color" de este botón pero mantener el tamaño actual? Analizar el atributo de clase! ¿Desea simplemente eliminar el modificador de éxito ? Analizar el atributo de clase!

Cuente que, por ejemplo, Bootstrap tiene 7 "colores", 4 tamaños y estados activo / deshabilitado; ¡para las cuales 119 (= 13 + [7 * 4 + 7 * 2 + 4 * 2] + 7 * 4 * 2) deben declararse para mantener el enfoque de una sola clase! Ese es el gran problema.

Las clases múltiples explícitas requerirían solo 13 clases (una para cada modificador). La orden sería arbitraria. Por último, agregar, eliminar y cambiar uno mientras se preservan otros en jQuery se vería así:

$('#login-button').removeClass('button--primary').addClass('button--success');

Atajo multiclase

En primer lugar, como mencionó, existe la posibilidad de colisiones, algo malo en sí mismo.

En segundo lugar, lo que también significa es que .segment__arrow.orangetiene una especificidad más alta y no se puede sobrescribir con un solo selector de clase. Esto suele estar en problemas cuando un elemento es, por ejemplo, no solo un botón grande, sino también, por ejemplo, un botón de inicio de sesión . Su código se vería así:

<a href="#" class="button large primary login__button">Log in</a>

Es posible que desee tener un relleno más grande a la izquierda y a la derecha en el botón de inicio de sesión, pero conservar la altura de grande . Esto daría como resultado selectores cada vez más específicos que nos llevarían al infierno de la especificidad , un lugar del que OOCSS debería salvarnos.

Es evidente que esto no sucedería en el enfoque explícito de múltiples clases .

Multi-clase explícita

El único problema (hasta donde yo sé) de esto es que hay algunas clases a veces bastante largas en el marcado. Admito esto.

Permítanme señalar que esto es solo una cuestión de gusto del desarrollador, ya que tiene un efecto insignificante (o ningún efecto) en el rendimiento. La compresión estándar se encargará de esto.

Dicho esto, usar un buen IDE ayudará a escribir esto (sí, lo sé, aún se verá un poco ridículo).

Por un lado, diría, ver clases tan largas obliga a uno a pensar más sobre la estructura; por ejemplo, si no sería mejor introducir un nuevo componente (reutilizable) en lugar de anidarlo en otra cosa.

Robin Pokorny
fuente
0

Estoy debatiendo con mis compañeros de equipo sobre estos problemas de clase única / múltiple en este momento

Estas son algunas de mis opiniones personales basadas en las mejores prácticas.

La mejor práctica

  • html declara elementos
  • Controles CSS render

Single Class siempre sigue las mejores prácticas

con beneficios adicionales de mantenimiento, con buenos nombres que puede lograr

  • el cambio de estilo no requiere actualización html * (ver demostración)

  • estilo de bloqueo en html (tendrá el estilo correcto o nada)

Manifestación

@mixin segment__arrow {
    position: absolute;
    bottom: -24px;
    left: 50%;
    margin-left: -11px;
    background-position: center no-repeat;
    height: 21px;
    width: 21px;
    z-index: 2;
}

.segment__arrow--type1 {
    @include segment__arrow;
    background-image: url('/images/arrow_orange.png');
}
.segment__arrow--type2 {
    @include segment__arrow;
    background-image: url('/images/arrow_white.png');
}

@mixin include es mejor que @extend

  1. tener el control del orden del código en css final
  2. tamaño más pequeño en versión gzip

e igual que @extend, se puede reutilizar y puede reemplazar varias clases en HTML

con @mixin, obtendrá flexibilidad adicional

@mixin segment__arrow--type1 {
    @include segment__arrow;
    background-image: url('/images/arrow_orange.png');
}
@mixin segment__arrow--type2 {
    @include segment__arrow;
    background-image: url('/images/arrow_white.png');
}
.segment__margic-arrow {
    @include screen(mobile) {
       @include segment__arrow--type1
    }
    @include screen(desktop) {
       @include segment__arrow--type2
    }
}

Para uso de javascript

reglas estatales de smacss

Desventaja de una sola clase

uno y solo:

mayor tamaño de archivos CSS, PERO siempre puede optimizar fácilmente CSS en función de las secciones o componentes del sitio web en la página

Liang
fuente