Cómo manejar objetos diferidos en DoCSSa -

PorMatthieu Larcher es

Este artículo de Matthieu Larcher también está disponible en francés.

Índice de contenidos
  1. Introducción
  2. ¿Qué es un objeto CSS?
  3. From OOCSS to DoCSSa
  4. BEM is your friend
    1. Acerca de Matthieu Larcher

Introducción

DoCSSa es una arquitectura y metodología basada en Sass. Puede leer sobre esto endocssa.info y obtener el código fuente de esa documentación en la página de GitHub. El código fuente hace uso de los conceptos, por lo que es un buen punto de partida. En este artículo, nos centraremos en los objetos diferidos de los que DoCSSa toma su nombre: ¿qué queremos decir con eso y cómo usarlos?

¿Qué es un objeto CSS?

Un objeto, en el mundo CSS, es básicamente un conjunto de reglas a aplicar, un patrón visual que se repite. OOCSS, por ejemplo, define un objeto “medios”. Representa algunas reglas aplicadas a la imagen y al texto dentro de un bloque para crear una apariencia específica. Luego, esa apariencia se puede aplicar fácilmente en cualquier contexto. El punto es permanecerSECO para que podamos facilitar el mantenimiento del código en lugar de reescribir las mismas reglas una y otra vez, en todas partes.

Si bien OOCSS es bueno y aportó algunos principios sólidos al mundo CSS, también adolece de algunos problemas. En particular, permite la fuga de CSS y combina presentación con contenido.

Una fuga de CSS es un efecto secundario no deseado de una regla de CSS. Por ejemplo, si tiene un formato HTML similar a este:

sección h3Mi título/h3 palgunos contenidos/p/sección

Puede establecer una regla similar a esta:

.sección .título { margen superior: 20px;}

Pero si en algún momento agregas algún contenido y terminas con el siguiente marcado:

sección h3Mi título/h3 palgunos contenidos/p div h5Mi contenido anidado título/h5 palgunos otros contenidos/p /div/sección

Ahora eres víctima de una fuga de CSS: el título de tu contenido anidado ahora tiene un margen superior de 20 píxeles. Puede que eso no sea lo que tenías en mente cuando lo escribiste. Este es un ejemplo de algo artificial, pero en el mundo real, con un marcado más complejo, esto tiende a suceder muy fácilmente. Con suerte, algunos tipos inteligentes de Yandex se dieron cuenta. y asesorando el sistema BEM. Una de sus partes clave es una convención de nomenclatura que nos haría reescribir nuestro ejemplo de esta manera:

sección h3Mi título/h3 palgunos contenidos/p div h5Mi contenido anidado título/h5 palgunos otros contenidos/p /div/sección
.section_title { margen superior: 20px;}

¡No más fugas de CSS!

BEM significa Modificador de elemento de bloque. Entonces, esa convención de nomenclatura de clases va de la mano con una forma de pensar su marcado como componentes (Bloques y Elementos). Podríamos decir que un “Bloque” es un objeto al que se le deben aplicar algunas reglas CSS. Los Elementos que constituyen el Bloque deben tener un conjunto de reglas que coincidan con las dadas al Bloque para formar un componente.

Another important aspect to handle is theSingle Responsibility Principle (SRP). SRP is a wide spread concept that states that everything should do one and only one thing, and do it well. There are many possible interpretations to this, one of which is the following: HTML’s responsibility is to provide content while CSS provides appearance (and JS provides behavior). If at some point your HTML markup is saying

div

you are in for a hell lot of maintenance problems. What if you want to remove the round corners on that div ? Do you dig into the RTE database to remove all the unwanted roundCorners classes ? What if you want to change the color ? Do you change your CSS to say “.redBackground {color: blue;}” ? Those helpers are very helpful indeed, but we really need to dissociate them from the markup (content). That’s the only way we can respect the SRP and preserve our future coworkers’ mental health. Hopefully, it is totally possible to keep your HTML class names semantic and bind some DRY components to it, and DoCSSa is here to demonstrate it.

From OOCSS to DoCSSa

Let’s take a basic example. It has a top menu and contains a form with a “submit” and a “back” button.

As you can see, all the buttons look the same. But that doesn’t mean you have to change your markup (i.e. “content”) if you want to style your “back” buttons differently than your “submit” buttons. They have different meaning, so they should bear different classes reflecting their respective roles. Only CSS is concerned about how they look.Let’s look at what the HTML markup may look like in a traditional way:

ul    li        a href="#part-1"part 1/a    /li    li        a href="#part-2"part 2/a    /li    li        a href="#part-3"part 3/a    /li/ulform action="#"    div        div            label for="input-firstName"First name/label            input type="text" name="firstName"        /div        div            label for="input-lastName"Last name/label            input type="text" name="lastName"        /div        div            label for="input-address"Address/label            input type="text" name="address"        /div        div            buttonBack/button            button type="submit"Submit/button        /div    /div/form

And the CSS associated with it:

.button {    box-sizing: border-box;    display: inline-block;    padding: 10px;    border-radius: 5px;    background: #449888;     background: linear-gradient(to bottom,  #449888 0%,#a8d5cd 50%,#449888 51%,#5cbcaa 100%);     border: 2px solid #449888;    color: #000;    text-decoration: none;    cursor: pointer;    font-weight: bold;    color: #fff;    text-shadow: 0 -1px 0 #449888;}.button:hover {    background: #5cbcaa;    background: linear-gradient(to bottom,  #5cbcaa 0%,#a8d5cd 50%,#5cbcaa 51%,#5cbcaa 100%);}

As you can see, this example uses the class “button” in the HTML everywhere we want to display a button. Doing this, we are exposing ourselves to the various problems we talked about earlier. Now Let’s see how we would rewrite it according to DoCSSa.

The markup itself won’t change much. We will just use classes reflecting the intent of the element instead of the classes reflecting its appearance. Here’s how it could look like:

ul    li        a href="#part-1"part 1/a    /li    li        a href="#part-2"part 2/a    /li    li        a href="#part-3"part 3/a    /li/ulform action="#"    div        div            label for="input-firstName"First name/label            input type="text" name="firstName"        /div        div            label for="input-lastName"Last name/label            input type="text" name="lastName"        /div        div            label for="input-address"Address/label            input type="text" name="address"        /div        div            buttonBack/button            button type="submit"Submit/button        /div    /div/form

Then we will create our “button” component:

// in components/buttons/_button.scss

/* **** BUTTON COMPONENT **** */// define component placeholders for component contents (no selector here)@include define('button') {  %button {    box-sizing: border-box;    display: inline-block;    padding: 10px;    cursor: pointer;  }}// map the placeholders content to some selectors through a mixin@mixin example($selector, $defaultSkin: true) {  #{$selector} {    @extend %button;  }}/* **** BUTTON COMPONENT SKIN **** */// define component placeholders for component skin (no selector here)@include define('button_skin_default') {  %button-skin-default {        border-radius: 5px;    background: #449888;     background: linear-gradient(to bottom,  #449888 0%,#a8d5cd 50%,#449888 51%,#5cbcaa 100%);     border: 2px solid #449888;    text-decoration: none;    font-weight: bold;    color: #fff;    text-shadow: 0 -1px 0 #449888;  }  %button-skin-default__altState {    background: #5cbcaa;    background: linear-gradient(to bottom,  #5cbcaa 0%,#a8d5cd 50%,#5cbcaa 51%,#5cbcaa 100%);  }}// provide a default skin for the component// only visual changes that don't affect the component layout should be in here@mixin button-skin-default($selector) {    #{$selector} {      @extend %button-skin-default;    }    #{$selector}:hover {      @extend %button-skin-default__altState;    }}

Granted, it is a bit more verbose than the traditionnal version. But it also goes a long way when it comes to site maintenance or regression avoidance. Plus you don’t have to define new components everyday. Once you have them you can use them (or not) any time you like. You can even re-use the components in any other project, as the skin is decoupled from the structure (ui-components libraries anyone?).

Once you have defined your components, using them is as easy as it comes, and you avoid a lot of the CSS pitfalls. Here’s how we’d apply the “button” behaviour to our elements:

// in specifics/_someSpecificFile.scss

@include button('.navMenu_link');@include button('.backBtn');@include button('.submitBtn');

See how easy that is ? We have the same look as before, but now changing the style of any of the items can be done on the SCSS side only. It can be done in a matter of seconds, without any change to the HTML markup.

BEM is your friend

In order to bind components to class names, we need some class names to hook onto. Those classes should represent the role of the elements holding them, along with the minimum required info about their context (the “Block” they relate to). For example, if an Unordered List represents a navigation menu, it most probably holds some List Items that are by definition items of that menu. There is also very likely a link in each item that is a link of the navigation menu. Thanks to BEM, we already have a convention describing a way to make that relation explicit in the markup. Here is how we would represent the menu we just described in HTML:

ul    li        a href="#part-1"part 1/a    /li    li        a href="#part-2"part 2/a    /li    li        a href="#part-3"part 3/a    /li/ul

As you can see, we define a “navMenu” element, its items and its links in a straightforward way.

Note that a common mistake when beginning with BEM is to try to reflect all the HTML nesting in the class names. In that logic, “navMenu_link” would have been named “navMenu_item_link”. This is totally unnecessary and would clutter the markup, making it less flexible. Our class names are already longer than before, and a bit verbose sometimes. There is no need to make it worse when it doesn’t bring anything to the table.

Once you get the hang of it, you will place css “hooks” on every class that may need styling. As long as those classes represent the role of the element, you won’t run out of ideas on how to name it. Once you’ve done that, you’ll be free to bind any DoCSSa component to them.Of course, the component will need to be fit for the Block you want to apply it to. Using a “button” component on our “navMenu” probably won’t generate a useful CSS. But applying it to the “navMenu_link” will.

As an exercise, you can try to apply the same kind of naming to the form example used above. The more you do it, the more you’ll find the correct balance between generic roles and specific blocks. The classes should stay as semantic and flexible as possible.

DoCSSa is all about providing an architecture and methodology front-end web developers can build upon. It should bend to your own specific needs. It should get enriched by your own experience. And most of all it should help you keep your sites maintainable and fast to develop. We’re looking forward for your feedback. What do you plan to do with DoCSSa ?

Acerca de Matthieu Larcher

Matthieu Larcher es un desarrollador web que vive en París, Francia. Tiene más de diez años de experiencia tanto en backend como en frontend. Él cree firmemente que las mejores prácticas, la arquitectura del código y la anticipación de requisitos son clave para una base de código mantenible, lo que a su vez mejora las ganancias junto con la satisfacción de los usuarios/clientes.

www.ringabell.org larchermatthieu Publicaciones

Te podría interesar...

Deja una respuesta

Subir