Taller de maquetación

día 2: estrategia y buenas prácticas

Qué vamos a hacer hoy

  1. Evolución en la construcción de CSS
    Basado en un post de Adam Wathan autor de Tailwild CSS
  2. Pautas antes de comenzar a maquetar
  3. Ejercicio
<div>
  <img src="..." alt="">
  <div>
    <h2>Adam Wathan</h2>
    <p>
      Adam is a rad dude who likes TDD, 
      Active Record, and garlic bread
      with cheese.
    </p>
  </div>
</div>
.author-bio {
  background-color: white;
  border: 1px solid hsl(0,0%,85%);
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  overflow: hidden;
}

.author-bio img {
  display: block;
  width: 100%;
  height: auto;
}

.author-bio div {
  padding: 1rem;
}

.author-bio div h2 {
  font-size: 1.25rem;
  color: rgba(0,0,0,0.8);
}

.author-bio div p {
  font-size: 1rem;
  color: rgba(0,0,0,0.75);
  line-height: 1.5;
}

Etapa 1: CSS "semático"

<div class="author-bio">
  <img src="..." alt="">
  <div>
    <h2>Adam Wathan</h2>
    <p>
      Adam is a rad dude who likes TDD, 
      Active Record, and garlic bread
      with cheese.
    </p>
  </div>
</div>

Etapa 2: Desacoplar estilos de estructura

<div class="author-bio">
  <img 
    class="author-bio__image" 
    src="..." 
    alt=""
  >

  <div class="author-bio__content">
    <h2 class="author-bio__name">
      Adam Wathan
    </h2>
    <p class="author-bio__body">
      Adam is a rad dude who likes TDD, 
      Active Record, and garlic bread 
      with cheese.
    </p>
  </div>
</div>
.author-bio {
  background-color: white;
  border: 1px solid hsl(0,0%,85%);
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  overflow: hidden;
}

.author-bio__image {
  display: block;
  width: 100%;
  height: auto;
}

.author-bio__content {
  padding: 1rem;
}

.author-bio__name {
  font-size: 1.25rem;
  color: rgba(0,0,0,0.8);
}

.author-bio__body {
  font-size: 1rem;
  color: rgba(0,0,0,0.75);
  line-height: 1.5;
}
<div class="author-bio">
  <img src="..." alt="">
  <div>
    <h2>Adam Wathan</h2>
    <p>
      Adam is a rad dude who likes TDD, 
      Active Record, and garlic bread
      with cheese.
    </p>
  </div>
</div>
.author-bio {
  background-color: white;
  border: 1px solid hsl(0,0%,85%);
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  overflow: hidden;
}

.author-bio img {
  display: block;
  width: 100%;
  height: auto;
}

.author-bio div {
  padding: 1rem;
}

.author-bio div h2 {
  font-size: 1.25rem;
  color: rgba(0,0,0,0.8);
}

.author-bio div p {
  font-size: 1rem;
  color: rgba(0,0,0,0.75);
  line-height: 1.5;
}

ANTES

DESPUÉS

Tratar con componentes similares

Tratar con componentes similares

<div class="article-preview">
  <img 
    class="article-preview__image" 
    src="..." 
    alt=""
  >
  <div class="article-preview__content">
    <h2 class="article-preview__title">
      Stubbing Eloquent Relations for 
      Faster Tests
    </h2>
    <p class="article-preview__body">
      In this quick blog post and 
      screencast, I share a trick I 
      use to speed up tests that 
      use Eloquent relationships but 
      don't really depend on database 
      functionality.
    </p>
  </div>
</div>

Tratar con componentes similares

.article-preview {
  background-color: white;
  border: 1px solid hsl(0,0%,85%);
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  overflow: hidden;
}

.article-preview__image {
  display: block;
  width: 100%;
  height: auto;
}

.article-preview__content {
  padding: 1rem;
}

.article-preview__title {
  font-size: 1.25rem;
  color: rgba(0,0,0,0.8);
}

.article-preview__body {
  font-size: 1rem;
  color: rgba(0,0,0,0.75);
  line-height: 1.5;
}
.article-preview {
  @extend .author-bio;
}

.article-preview__image {
  @extend .author-bio__image;
}

.article-preview__content {
  @extend .author-bio__content;
}

.article-preview__title {
  @extend .author-bio__name;
}

.article-preview__body {
  @extend .author-bio__body;
}

Opción 1: Duplicar estilos

Opción 2: @extend el componente author bio

Tratar con componentes similares

.media-card {
  background-color: white;
  border: 1px solid hsl(0,0%,85%);
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  overflow: hidden;
}

.media-card__image {
  display: block;
  width: 100%;
  height: auto;
}

.media-card__content {
  padding: 1rem;
}

.media-card__title {
  font-size: 1.25rem;
  color: rgba(0,0,0,0.8);
}

.media-card__body {
  font-size: 1rem;
  color: rgba(0,0,0,0.75);
  line-height: 1.5;
}

Opción 3: Crear a un componente agnóstico al contenido

<div class="media-card">
  <img class="media-card__image" src="...">
  <div class="media-card__content">
    <h2 class="media-card__title">
     Adam Wathan
    </h2>
    <p class="media-card__body">
      Adam is a rad dude who likes TDD, 
      Active Record, and garlic bread 
      with cheese.
    </p>
  </div>
</div>
<div class="media-card">
  <img 
    class="media-card__image" 
    src="..."
  >
  <div class="media-card__content">
    <h2 class="media-card__title">
      Stubbing Eloquent Relations for Faster Tests
    </h2>
    <p class="media-card__body">
      In this quick blog post and screencast, 
      I share a trick I use to speed up tests that 
      use Eloquent relationships but don't really 
      depend on database functionality.
    </p>
  </div>
</div>

HTML de la biografía de autor

HTML del preview del artículo

¿CSS semántico y "separation of concerns"?

Hay 2 maneras de escribir HTML y CSS

"separation of concerns"

que el CSS que dependa del HTML

"mixing concerns"

que el HTML que dependa del CSS

o

En lugar de pensar en "separation of concerns", piensa acerca de la dirección de la dependencia

Etapa 3: Componentes agnósticos del contenido

Evitar crear clases basadas en el contenido e intentar nombrar todo para que sea lo más reutilizable posible

.card
.btn, .btn--primary, .btn--secondary
.badge
.card-list, .card-list-item
.img--round
.modal-form, .modal-form-section

Cuanto más haga un componente o cuanto más específico sea, más difícil será su reutilización

Ejemplos:

<form class="stacked-form" action="#">
  <div class="stacked-form__section">
    <!-- ... -->
  </div>
  <div class="stacked-form__section">
    <!-- ... -->
  </div>
  <div class="stacked-form__section">
    <button class="stacked-form__button">Submit</button>
  </div>
</form>

Nos piden añadir otro botón en el site que tiene el mismo aspecto que el botón submit y que no es parte de un formulario. Ambos son acciones primarias, ¿qué hacemos?

  <form class="stacked-form" action="#">
    <!-- ... -->
    <div class="stacked-form__section">
-     <button class="stacked-form__button">Submit</button>
+     <button class="btn btn--primary">Submit</button>
    </div>
  </form>

Ejemplo:

Etapa 3: Componentes agnósticos del contenido

<form class="stacked-form" action="#">
  <!-- ... -->
  <div class="stacked-form__section">
    <button class="btn btn--secondary">Cancel</button>
    <!-- Need some space in here -->
    <button class="btn btn--primary">Submit</button>
  </div>
</form>

Ahora nos piden agregar una acción secundaria a la parte inferior y tienen que estar separados:

  <form class="stacked-form" action="#">
    <!-- ... -->
-   <div class="stacked-form__section">
+   <div class="stacked-form__section stacked-form__footer">
-     <button class="btn btn--secondary">Cancel</button>
-     <button class="btn btn--primary">Submit</button>
+     <button class="stacked-form__footer-item btn btn--secondary">Cancel</button>
+     <button class="stacked-form__footer-item btn btn--primary">Submit</button>
    </div>
  </form>
.stacked-form__footer {
  text-align: right;
}
.stacked-form__footer-item {
  margin-right: 1rem;
  &:last-child {
    margin-right: 0;
  }
}

Posible solución:

Etapa 3: Componentes agnósticos del contenido

Ahora nos piden que, en la botonera de ".header-bar" hagamos lo mismo. 

  <form class="stacked-form" action="#">
    <!-- ... -->
   <div class="stacked-form__section stacked-form__footer">
     <button class="btn btn--secondary">Cancel</button>
     <button class="btn btn--primary">Submit</button>
     <button class="stacked-form__footer-item btn btn--secondary">Cancel</button>
     <button class="stacked-form__footer-item btn btn--primary">Submit</button>
    </div>
  </form>
<header class="header-bar">
  <h2 class="header-bar__title">
    New Product
  </h2>
  <div class="header-bar__actions">
    <button class="header-bar__action btn btn--secondary">
      Cancel
    </button>
    <button class="header-bar__action btn btn--primary">
      Save
    </button>
  </div>
</header>
<header class="header-bar">
  <h2 class="header-bar__title">
    New Product
  </h2>
  <button class="btn btn--secondary">
    Cancel
  </button>
  <button class="btn btn--primary">
    Save
  </button>
</header>

Acabamos con código CSS duplicado y no reutilizable :(

Etapa 3: Componentes agnósticos del contenido

¡Solución! Hacemos un componente ".action-list"

<!-- Stacked form -->
<form class="stacked-form" action="#">
  <!-- ... -->
  <div class="stacked-form__section">
    <div class="actions-list">
      <button class="actions-list__item btn btn--secondary">
        Cancel
      </button>
      <button class="actions-list__item btn btn--primary">
        Submit
      </button>
    </div>
  </div>
</form>

<!-- Header bar -->
<header class="header-bar">
  <h2 class="header-bar__title">New Product</h2>
  <div class="actions-list">
    <button class="actions-list__item btn btn--secondary">
        Cancel
    </button>
    <button class="actions-list__item btn btn--primary">
        Save
    </button>
  </div>
</header>
.actions-list {
  text-align: right;
}

.actions-list__item {
  margin-right: 1rem;

  &:last-child {
    margin-right: 0;
  }
}

Etapa 3: Componentes agnósticos del contenido

Ahora nos piden que una de las listas de acciones esté justificada a la izquierda y la otra a la derecha...

.actions-list--right {
  text-align: right;
}

.actions-list--left {
  text-align: left;
}
.actions-list {
  text-align: right;
}

.actions-list__item {
  margin-right: 1rem;

  &:last-child {
    margin-right: 0;
  }
}

Etapa 3: Componentes agnósticos del contenido

Etapa 4: componentes agnósticos de contenido + clases de utilidad

.align-left {
  text-align: left;
}

.align-right {
  text-align: right;
}
<form class="stacked-form" action="#">
  <!-- ... -->
  <div class="stacked-form__section">
    <div class="actions-list align-left">
      <button class="actions-list__item btn btn--secondary">Cancel</button>
      <button class="actions-list__item btn btn--primary">Submit</button>
    </div>
  </div>
</form>
<header class="header-bar">
  <h2 class="header-bar__title">New Product</h2>
  <div class="actions-list align-right">
    <button class="actions-list__item btn btn--secondary">Cancel</button>
    <button class="actions-list__item btn btn--primary">Save</button>
  </div>
</header>

Es preferible la composición a la duplicación

Etapa 4: componentes agnósticos de contenido + clases de utilidad

- .actions-list {
-   text-align: right;
- }

  .actions-list__item {
    margin-right: 1rem;
    &:last-child {
      margin-right: 0;
    }
  }

Vamos a eliminar abstracciones inútiles

- .actions-list__item {
-   margin-right: 1rem;
-   &:last-child {
-     margin-right: 0;
-   }
- }

+ .margin-right-small {
+   margin-right: 1rem;
+ }
<!-- Stacked form -->
<form class="stacked-form" action="#">
  <!-- ... -->
  <div class="stacked-form__section align-left">
    <button class="btn btn--secondary margin-right-small">Cancel</button>
    <button class="btn btn--primary">Submit</button>
  </div>
</form>

<!-- Header bar -->
<header class="header-bar">
  <h2 class="header-bar__title">New Product</h2>
  <div class="align-right">
    <button class="btn btn--secondary margin-right-small">Cancel</button>
    <button class="btn btn--primary">Save</button>
  </div>
</header>

Etapa 5: Clases de utilidad primero (utility first)

<div class="card rounded shadow">
    <a href="..." class="block">
        <img class="block fit" src="...">
    </a>
    <div class="padding-y-3 padding-x-4 border-bottom 
                border-dark-soft flex-spaced align-center">
        <div class="text-ellipsis margin-right-4">
            <a href="..." class="text-large text-bold">
                Test-Driven Laravel
            </a>
        </div>
        <a href="..." class="link-softer">
            @icon('link')
        </a>
    </div>
    <div class="flex text-large text-dark">
        <div class="padding-y-2 padding-x-4 border-right border-dark-soft">
            @icon('currency-dollar', 'icon-small text-dark-softest margin-right-4')
            <span>$3,475</span>
        </div>
        <div class="padding-y-2 padding-x-4">
            @icon('user', 'icon-small text-dark-softest mr-4')
            <span>25</span>
        </div>
    </div>
</div>

Etapa 5: Clases de utilidad primero (utility first)

  • Aún debemos crear componentes para extraer las repeticiones de patrones a medida que surgen
     
  • Comienza usando clases de utilidad primero
     
  • Evita abstracciones prematuras
     
  • Consistencia forzada
     
  • Es más sencillo gestionar la complejidad en el HTML que en el CSS

Antes de empezar a maquetar,
¿qué hay que tener claro?

  • Línea base del grid
  • Paleta de colores
  • Breakpoints
  • Tamaños de texto con velocidad de crecimiento
  • Escala de espacios

¡Ejercicio!

Características del diseño del ejercicio

Tamaño del grid: 8px y para tipografía e iconografía 4px
Familia de la fuente de texto: "Open Sans", sans-serif;

Escala de márgenes:
  - tiny: 4px
  - mini: 8px
  - small: 12px
  - regular: 16px
  - medium: 24px
  - large: 48px

bordes redondeados:
  - small: 8px
  - large: 20px

Escala de fuentes:
  - h3: 20px / 24px
  - base: 14px / 20px
  - small: 12px / 16px;

Paleta de colores:
  - black: #333;
  - gray: #ccc;

shadows:
  - level1: 0 1px 4px 0 rgba(0, 0, 0, 0.37);

iconos:
  - tiny: 12x12
  - small: 16x16
  - large: 32x32

¡Ejercicio!

¡Coding Time!

Paso 1: identificar los átomos y moléculas

Paso 2: construir los elementos comenzando por los más simples

¡Bonus pack 1!

Crear un grid con flex y sin media queries

Normas:

  • El contenedor del grid debe ocupar únicamente el espacio de sus elementos
  • Una card nunca debe ocupar menos de 25 rems o más de 35 rems.
  • La separación horizontal y vertical entre ellos es de 1.5 rem

¡Bonus pack 2!

Texto responsive

A partir de 800px de anchura los nuevos tamaños son:

  • h3: 24px/28px
  • small: 14px/20px

¡Bonus pack 3!

  • No usar variables de SASS
  • No tener números mágicos en las clases
  • No usar píxeles

Biko - Taller de maquetación: día 2

By rubenbp

Biko - Taller de maquetación: día 2

  • 243