Taller de maquetación
día 2: estrategia y buenas prácticas
Qué vamos a hacer hoy
- Evolución en la construcción de CSS
Basado en un post de Adam Wathan autor de Tailwild CSS - Pautas antes de comenzar a maquetar
- 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