DÍA 17 / 2014

Patternizando

La importancia de construir un lenguaje particular para cada proyecto; una serie de pautas que le dan coherencia al sistema en su conjunto. Aquí algunos pequeños pasajes, ejemplos y scripts...


Estamos en un momento muy importante. La web nos permite hacer cosas que 20 años atrás eran impensables. Muchos avances en términos tecnológicos y muchísima información abierta que hace crecer la comunidad de desarrollo muy velozmente.

Mas concretamente, son cada vez menos los limites que encontramos en la implementación de un proyecto web; podemos jugar con canvas, svg, animaciones o transiciones css, etc y llegar a resultados que hace varios años solo imaginábamos posibles con AS2.

Encarando el proyecto como un 'sistema', es recomendable que nos creemos entonces ciertos 'limites', que le demos un marco, una estructura.

Aunque esto parezca restrictivo, con el pasar del tiempo realizaremos que estos limites abren caminos y posibilidades. Nos daremos cuenta que, nuevos elementos o componentes, secciones o ideas, surgirán justamente gracias a estas guías que encuadran el plan general.


Y aquí llegan los patrones :: modelos, reglas, estructuras ejemplares que se repetirán coherentemente a lo largo del trabajo.

Hace un tiempo que grandes y conocidos sitios empezaron a publicar sus Guías de Estilos o Pattern Libraries. Entre otros MailChimp, Lonely Planet, GitHub, CodePen.

La idea de compartir estas librerías abiertamente me fascina.
Son publicaciones que, básicamente, nos muestran las lineas guías de la arquitectura de cada proyecto. Cada una con niveles de detalle diverso, en algunos casos con mas elementos visuales, en otros, de forma mas abstracta o descriptiva del código.

El objetivo principal entonces, es crear un sistema coherente que sirva de guía para la construcción de un proyecto: desde el elemento más pequeño hasta secciones completas o cosas más genéricas.

No creo que haya recetas o formulas respecto a dónde o cómo comenzar y creo que lo mejor es que cada uno pruebe y conozca el camino que mejor le sienta.

En adelante, compartiré solo algunos detalles de mi experiencia personal en la creación de esta pequeña librería.


Hemos comenzado con sketchs gráficos que pautaron el estilo y ciertos detalles a tener en cuenta para el desarrollo de un ‘lenguaje’ de proyecto.
En paralelo íbamos pensando la lógica de nomenclatura que se utilizara. Este proyecto no es estrictamente BEMico, pero tiene en cuenta el método y lo hemos aplicado a nuestra manera. De hecho, insisto con que cada uno tiene que experimentar su propia elección en función de diversos factores, como la dimensión del proyecto, la amplitud del team de desarrollo, las perspectivas futuras de mantenimiento, etc. Recomiendo la lectura de este artículo salidito hace bien poco por este mismo canal

Con la base grafica pudimos comenzar a crear una serie de elementos base del sistema como la grilla y las tipografías y los colores. Aqui el primer detalle.

Aclaración: la mayoría de los detalles compartidos son generados en Sass.

colorize @mixin

Aquí tenemos la definición de los colores del proyecto como \$variables (en este caso, solo una reducción), una \$lista con el nombre que deseamos utilizar en las clases modificadoras (index 1) y la referencia a la variable del color (index 1). Notese que en este caso los indexes se llaman igual pero podría no ser así.

Por ultimo, el @mixin para generar los colores modificadores en los atributos css que deseemos.

Los colores

$orange:#F17635;
$blue:#547DAA;
$green:#25BAA5;
$red:#e74c3c;
$yellow:#f1c40f;

La lista

$colors:
"orange" $orange,
"blue" $blue,
"green" $green,
"red" $red,
"yellow" $yellow;

El mixin

@mixin coloring($list, $prefix:'', $parent:true){      
    @each $color in $list {
        @if not $parent {
            @at-root {
                #{$prefix}#{nth($color,1)} {
                  $color : nth($color,2) !global;
                  @content;
                }
              }
        } @else {
          &.#{$prefix}#{nth($color,1)} {
            $color : nth($color,2) !global;
            @content;
          }
        }
    } // @each
} // @mixin

Aplicación

.btn {
  display:block; /* atributo generico del .btn */
  @include coloring($colors,btn-, false) {
    color:darken($color,25);
    background-color:$color;
    &:before {
      border:1px solid $color;
    }
    &:after {
        box-shadow: 2px 2px 0 rgba($color,.25);
    }
  }
}

Basicamente el @mixin coloring acepta tres parámetros:

  1. la referencia a la \$lista en la que va a realizar el loop
  2. un \$prefijo opcional en caso de querer agregarlo a las clases generadas con los nombres de los colores (ej. btn- o elem-)
  3. una variable booleana (\$parent) que por default es true, en el caso de querer aplicar el @mixin en la root, osea fuera de un modulo o elemento en particular.

Dentro del @mixin se realiza el loop en la lista y por cada iteración retorna un selector con como nombre, el prefijo pasado como parámetro (que si es vacío no agrega nada) y el nombre del color de la lista relativo a esa iteración. Ahí dentro incluye una variable !global y el @content.
Si la variable \$parent es false, vuelca el resultado en la root (@at-root), caso contrario, dentro del elemento donde se esta aplicando el @mixin.

Aquí un gist con el codigo en funcionamiento con el que poder jugar/investigar.

De esta manera hemos aplicado las clases modificadoras de colores a nivel general y para elementos específicos.


Dado que el ejemplo anterior hablaba de botones aprovecho a mostrar un caso particular: varios botones de social-network dentro de un solo botón.

botón-share

.btn-share{
     position: relative;
     .xtra-content {
        position: absolute;
        left: 100%;
        top: 50%;
        transform:translateY(-50%);
        display: inline-block;
        max-height: 0;
        overflow: hidden;
        transition:max-height 0.3s;
        z-index: 999;
    }
    &:hover .xtra-content {
    max-height: 500px;
    }
    .btn {
        font-size: 1em;
        span { display: inline; }
    }
}

En primer lugar asignamos relative la posición del botón contenedor para poder posicionar absolutamente el contenido interno a la derecha (por fuera del contenedor) con left:100% y perfectamente centrado. No conociendo la altura de este contenido (ya que los botones pueden ser dos, tres o mas), lo hacemos con top:50% y con la transformación en el eje Y en -50%. Luego escondemos el contenido con overflow:hidden y max-height:0. A este ultimo atributo le agregamos una transición para cuando lo haremos aparecer on :hover del parent con max-height: 500px. El valor 500px debe ser siempre mayor del hipotético contenido que incluiremos.

Aquí el ejemplo en uso de este botón.


En varias secciones se necesitarían sliders o carousels 😉 por lo cual generamos un @mixin que crea las animaciones y los parámetros pertinentes para un slider solo en css.

@mixin photo-slider($slides,$slide_time,$name:'photo-slider',$slide_height:340px,$bg-anim:false){
    // el código completo del @mixin
    }
@include photo-slider(4, 6s, 'photo-slider-demo');

El @mixin acepta cinco parámetros:

  1. la cantidad de \$slides
  2. la cantidad de tiempo para cada slide \$slide_time
  3. el \$name del slider (como default pasa 'photo-slider')
  4. el \$height del slide (como default pasa 340px)
  5. una variable booleana _\$bg-anim en el caso que se desee el background animato (el default false porque utiliza muchos recursos con las transformaciones en css)

Basicamente genera en @at-root, los keyframes necesarios para el slider específico:

@keyframes #{$name}-opacity {
    #{100%/($slides)+100%/($slides*$slides*2)}, 100% { opacity: 0; visibility: hidden;  }
    #{100%/($slides*$slides)}, #{100%/$slides}  { opacity: 1; visibility: visible; }
}

y otros @keyframes para el texto dentro del slide y el background animado.

Luego le da estilo al slider propiamente dicho:

.#{$name} {
    width: 100%;
    height: $slide_height;
    position: relative;
    overflow: hidden;
    &:hover .photo-slide, &:hover .stext {
        animation-play-state: paused; }
    .photo-slide {
         width: 100%;
         height: 100%;
         position: absolute;
         opacity: 0;
         visibility: hidden;
         animation: #{$name}-opacity $total_time linear infinite;
         animation-play-state: running;
    }
    .slide-image { ... }
    .slide-text { ... }
    .slide-text-left { ... }
    .slide-text-right { ... }

    @for $i from 1 through $slides{
      .photo-slide:nth-child(#{$i}) {
        animation-delay: $slide_time*$i - $slide_time;
          .slide-text .stext {
            animation-delay: $slide_time*$i - $slide_time;
          }
        }
    }
}
  • Controla la animación de los slides cuando el mouse pasa por encima de la foto o del texto con animation-play-state
  • Esconde .photo-slide, la clase genérica para cada slide con opacity:0 y visibility:hidden y aplica la animación especifica para ese slider.
  • luego da estilo a la imagen y los textos controlables si entran de la derecha o de la izquierda
  • y asigna animation-delay a cada slide para que se componga finalmente el slider.
  • (...)

Aquí el gist con el código completo y aquí la versión en uso.

Insistiré solo con una cosa: no hay formulas para crear el workflow de cada proyecto. Cada uno se crea su propia receta, en función de la etapa personal a nivel profesional y el proyecto especifico que esta desarrollando.

Es un buen ejercicio buscar y probar entre las tantas y diversas técnicas que existen para trabajar en el desarrollo front-end. Ir desarrollando piano piano una sensibilidad particular para ir entendiendo automáticamente qué cosa necesita uno mismo y qué cosa necesita el proyecto.

Lo importante en la web es hacer. Hagamos!

B-link-ing


W3C será comprado por Twitter