Una Introducción a los Mapas Sass: Uso y Ejemplos
Spanish (Español) translation by Jorge Montoya (you can also view the original English article)
Para los frot-ends escalables, los mapas Sass son una bendición. Extraer la configuración de la lógica de un módulo es un gran método para estructurar. Permítame explicarle por qué creo que los Mapas Sass son la mejor característica de Sass 3.3.
Sass 3.3
Sass 3.3 ha estado al alcance de todos durante un tiempo, pero muchas de sus características del mundo real todavía no son familiares para muchos desarrolladores. La nueva versión de Sass nos trajo un nuevo tipo de datos llamado map. Los mapas contienen una colección de pares clave/valor y nos ayudan a crear pequeñas áreas de configuración para una base de código simplificada.
Cómo Utilizar los Mapas Sass
Para estar de acuerdo cubriremos los fundamentos de usar mapas Sass, después más adelante veremos algunos casos de uso.
Generación de un Mapa
He aquí una rápida descripción de la sintaxis de un mapa sassy. Comience con un nombre de variable ($map
en este caso) y luego ingrese algunas claves con valores, separadas por comas, todas dentro de paréntesis:
1 |
$map: ( |
2 |
key: value, |
3 |
nextkey: nextvalue |
4 |
); |
Cómo Obtener un Valor
Habiendo almacenado múltiples pares clave/valor en algún momento necesitará recuperar esa información. Si necesita encontrar el valor de una clave, utilice la función map-get()
. Vamos a pasarle dos parámetros: el nombre del mapa y luego la clave.
1 |
.element:before { |
2 |
content: map-get($map, key); |
3 |
} |
Una vez compilado el resultado será el siguiente:
1 |
.element:before { |
2 |
content: value; |
3 |
} |
Cómo Comprobar si hay una Llave Disponible
Es muy recomendable que utilice una sólida gestión de errores en el proceso de desarrollo de Sass. Para esto Sass nos da la función map-has-key()
. Esta función de ayuda mira si existe una clave, y si no entrega otra salida para advertir al desarrollador.
Eche un vistazo a esta Introducción a la Gestión de Errores en Sass de Hugo Giraudel para una manera impresionante de manejar errores.
1 |
$map: ( |
2 |
key: value, |
3 |
nextkey: nextvalue |
4 |
); |
5 |
|
6 |
.element { |
7 |
@if map-has-key($map, key) { |
8 |
content: ’Map has this key.’; |
9 |
} @else { |
10 |
content: ’Map has not this key.’; |
11 |
} |
12 |
} |
Resultado:
1 |
.element { |
2 |
content: ’Map has this key.’; |
3 |
}
|
Cómo Fusionar Mapas
Tiempo de bonificación: Sass nos permite fusionar dos o más mapas. Usted está comprendiendo esto ahora, así que eche un vistazo a este ejemplo de cómo utilizar la función map-merge()
:
1 |
$colors: ( |
2 |
light: #ccc, |
3 |
dark: #000 |
4 |
); |
5 |
|
6 |
$brand-colors: ( |
7 |
main: red, |
8 |
alternative: blue |
9 |
); |
10 |
|
11 |
// Merge maps |
12 |
$merged: map-merge($colors, $brand-colors); |
13 |
|
14 |
.element { |
15 |
content: map-get($merged, alternative); |
16 |
} |
El resultado:
1 |
.element { |
2 |
content: blue; |
3 |
} |
Casos de Uso en el Mundo Real
Hemos cubierto el cómo, ahora veamos el dónde.
1. Cómo Recorrer un Mapa y Generar Clases
Los mapas también pueden ser útiles sin las funciones que los acompañan. Por ejemplo, puede realizar un bucle a través de su mapa, definir los parámetros con los valores que espera y a continuación, agregar el nombre del mapa Sass. Al hacer esto es posible trabajar con diferentes tipos de valores.
En este ejemplo, estoy imprimiendo clases para mostrar los íconos. Puse el nombre del ícono como la clave, dejando el valor para almacenar el content
real (que luego añadiríamos a través de pseudo elementos).
Nota: En un escenario del mundo real, primero declararíamos algunos estilos básicos, pero eso está más allá del alcance de este tutorial.
1 |
/* Define the Sassy Map called $icons */ |
2 |
$icons: ( |
3 |
checkmark: a, |
4 |
plus: b, |
5 |
minus: c |
6 |
); |
7 |
|
8 |
/* For each key in the map, created an own class */ |
9 |
@each $name, $value in $icons { |
10 |
.icon--#{$name} { |
11 |
content: $value; |
12 |
} |
13 |
} |
La salida habla por sí misma:
1 |
/* For each key in the map, created an own class */ |
2 |
.icon--checkmark { |
3 |
content: "a"; |
4 |
} |
5 |
|
6 |
.icon--plus { |
7 |
content: "b"; |
8 |
} |
9 |
|
10 |
.icon--minus { |
11 |
content: "c"; |
12 |
} |
Esta es una manera realmente eficiente de cargar clases para los íconos. Hay muchos más casos de uso también–veamos algunos.
2. Múltiples Valores para Añadir Fantasía
Siguiendo, es posible dar a una clave más de un valor. Esto se hace usando recortes e ingresando varios valores con un separador de coma. Esto, por ejemplo, podría ser genial para transferir estilos para variantes de un módulo.
Aquí voy a diseñar una serie de botones. El primer valor para cada clave es para el background-color
y el segundo para el font-color
.
Luego hago un bucle a través de las claves con el objeto esperado $colors
. Obtengo el valor de la primera clave en este objeto con nth($colors, 1)
(comienzo con el nombre del objeto y luego la posición del valor buscado). Si necesita el segundo valor, entonces ingrese 2
.
1 |
// _m-buttons.scss |
2 |
$buttons: ( |
3 |
error: (#d82d2d, #666), |
4 |
success: (#52bf4a, #fff), |
5 |
warning: (#c23435, #fff) |
6 |
); |
7 |
|
8 |
.m-button { |
9 |
display: inline-block; |
10 |
padding: .5em; |
11 |
background: #ccc; |
12 |
color: #666; |
13 |
|
14 |
@each $name, $colors in $buttons { |
15 |
$bgcolor: nth($colors, 1); |
16 |
$fontcolor: nth($colors, 2); |
17 |
|
18 |
&--#{$name} { |
19 |
background-color: $bgcolor; |
20 |
color: $fontcolor; |
21 |
} |
22 |
} |
23 |
} |
La salida:
1 |
.m-button { |
2 |
display: inline-block; |
3 |
padding: .5em; |
4 |
background: #ccc; |
5 |
color: #666; |
6 |
} |
7 |
|
8 |
.m-button--error { |
9 |
background-color: #d82d2d; |
10 |
color: #666; |
11 |
} |
12 |
|
13 |
.m-button--success { |
14 |
background-color: #52bf4a; |
15 |
color: #fff; |
16 |
} |
17 |
|
18 |
.m-button--warning { |
19 |
background-color: #c23435; |
20 |
color: #fff; |
21 |
} |
3. Manejo de Capas (z-index)
No conozco a un desarrollador de front-end que no haya luchado con z-index en algún momento. Los problemas suelen surgir de perder una visión general si necesita utilizar z-index
en varios lugares en un proyecto. Los mapas Sass pueden ayudarnos.
Comencemos con $layer
como el mapa. Las claves deben ser nombradas lógicamente de modo que usted sepa qué valor está para qué elemento - quizá offcanvas
, lightbox
, dropdown
etc.
1 |
// _config.scss |
2 |
$layer: ( |
3 |
offcanvas: 1, |
4 |
lightbox: 500, |
5 |
dropdown: 10, |
6 |
tooltip: 15 |
7 |
); |
8 |
|
9 |
// _m-lightboxes.scss |
10 |
@function layer($name) { |
11 |
@if map-has-key($layer, $name) { |
12 |
@return map-get($layer, $name); |
13 |
} |
14 |
|
15 |
@warn "The key #{$name} is not in the map ’$layer’"; |
16 |
@return null; |
17 |
}; |
18 |
|
19 |
.m-lightbox { |
20 |
z-index: layer(lightbox); |
21 |
} |
Aquí escribí una función para obtener el valor de una clave específica, pero ¿por qué hice eso? La respuesta es afortunadamente sencilla: es más rápido que escribir map-get()
cada vez. Otro aspecto positivo es que puede crear un error de manejo y dar al desarrollador un poco de retroalimentación en cuanto a por qué no pasa nada.
Esta es la salida:
1 |
.m-lightbox { |
2 |
z-index: 500; |
3 |
} |
4. Uso de Estilos Base para Fuentes en un Proyecto
Cada proyecto tiene su propio archivo de configuración; conceptos básicos para el uso global. Por ejemplo, en mis proyectos, defino algunos valores para las propiedades de fuente: color de fuente, color de fuente alternativo, familia de fuente o tamaño de fuente. Solía crear una variable para cada propiedad, pero un mapa sería mejor.
He aquí un ejemplo rápido, para comenzar con la vieja solución:
1 |
$base-font-color: #666; |
2 |
$base-font-family: Arial, Helvetica, Sans-Serif; |
3 |
$base-font-size: 16px; |
4 |
$base-line-height: 1.4; |
Luego la nueva solución usando un mapa Sass:
1 |
// _config.scss |
2 |
$font: ( |
3 |
color: #666, |
4 |
family: (Arial, Helvetica), |
5 |
size: 16px, |
6 |
line-height: 1.4 |
7 |
); |
8 |
|
9 |
// _presets.scss |
10 |
body { |
11 |
color: map-get($font, color); |
12 |
font-family: map-get($font, family); |
13 |
font-size: map-get($font, size); |
14 |
line-height: map-get($font, line-height); |
15 |
} |
5. Puntos de Interrupción <3
Me encanta este caso de uso. Es magnífico tener un área para los puntos de interrupción que están en su proyecto entero. Así, al igual que la sección sobre el manejo con z-index, usted tiene una visión general de todos los puntos de interrupción utilizados. Si cambia el valor allí, entonces usted cambia el comportamiento en todo el proyecto. Increíble.
Así que comencemos con un mapa llamado $breakpoints
.
Nuestro objetivo es utilizar puntos de interrupción con nombres implícitos en lugar de valores de píxeles duros en un elemento. Debido a esto necesitamos un mixin que dará salida al valor del nombre indicado. Llamé al mixin respond-to
y paso $breakpoint
como un parámetro. Con $value
obtengo el valor del punto de interrupción esperado y lo pongo más adelante en la media query.
1 |
// Map with much breakpoints |
2 |
$breakpoints: ( |
3 |
small: 320px, |
4 |
medium: 600px, |
5 |
large: 768px |
6 |
); |
7 |
|
8 |
// Respond-To Mixin |
9 |
@mixin respond-to($breakpoint) { |
10 |
@if map-has-key($breakpoints, $breakpoint) { |
11 |
$value: map-get($breakpoints, $breakpoint); |
12 |
|
13 |
@media screen and (min-width: $value) { |
14 |
@content; |
15 |
} |
16 |
} |
17 |
|
18 |
@warn "Unknown `#{$breakpoint}` in $breakpoints"; |
19 |
} |
Ejemplo:
1 |
// Sass |
2 |
.m-tabs { |
3 |
background-color: #f2f2f2; |
4 |
|
5 |
@include respond-to(medium) { |
6 |
background-color: #666; |
7 |
} |
8 |
} |
9 |
|
10 |
// Output |
11 |
.m-tabs { |
12 |
background-color: #f2f2f2; |
13 |
} |
14 |
@media screen and (min-width: 600px) { |
15 |
background-color: #666; |
16 |
} |
¡Este caso de uso es uno de mis favoritos!
6. Uso Avanzado para los Colores
Las cosas se están poniendo un poco más difíciles ahora. Echemos un vistazo a los mapas anidados–impresionantes para los esquemas de color con una gama de tonos.
Nuestro mapa Sass en este caso obtiene el nombre $colorscheme
y tiene objetos con claves y valores. El proyecto tiene diferentes tonos grises, pero no queremos declarar una variable para cada uno. Así que agregamos un objeto gray
, agregamos recortes y luego las claves con valores.
Comience con un mapa como éste aquí:
1 |
// Scheme of colors |
2 |
$colorscheme: ( |
3 |
gray: ( |
4 |
base: #ccc, |
5 |
light: #f2f2f2, |
6 |
dark: #666 |
7 |
), |
8 |
brown: ( |
9 |
base: #ab906b, |
10 |
light: #ecdac3, |
11 |
dark: #5e421c |
12 |
) |
13 |
); |
Ahora vamos a agregar la función setcolor
para una manera más corta para obtener nuestro color de elección. El primer valor esperado es el objeto del mapa Sass ($scheme
) - en este ejemplo podría ser gray
o brown
. El segundo parámetro es el color que desea ($tone
) - el valor predeterminado para esto es la base
de las claves.
1 |
// Our function for shorter usage of map-get(); |
2 |
@function setcolor($scheme, $tone: base) { |
3 |
@return map-get(map-get($colorscheme, $scheme), $tone); |
4 |
} |
Por último, he aquí un ejemplo de cómo puede usarlo y cómo obtiene los diferentes colores del mapa anidado. ¡Es más fácil de lo que piensa (tal vez)!
1 |
// Sass |
2 |
.element { |
3 |
color: setcolor(brown); |
4 |
} |
5 |
.element--light { |
6 |
color: setcolor(brown, light); |
7 |
} |
8 |
|
9 |
// Output |
10 |
.element { |
11 |
color: #ab906b; |
12 |
} |
13 |
.element--light { |
14 |
color: #ecdac3; |
15 |
} |
Usted ha completado el desafío. Ahora puede crear una paleta sin hinchar el código con demasiadas variables para cada tipo de color.
Para esta técnica me inspiró Tom Davies y le recomiendo que eche un vistazo a su artículo sobre el asunto.
Dando Estilos con Clases
Ahora algo para usuarios avanzados de Sass. En proyectos suele ser un requerimiento crear diferentes tipos de temas con la misma base de código. Así que aquí hay una propuesta para establecer una clase de tema en la parte superior del documento para aplicar una apariencia específica. Necesitamos un objeto donde podamos manejar el nombre de los temas y establecer los diferentes estilos para el módulo.
Defina los temas
Comience con un mapa Sass y defina los temas globalmente para su proyecto. El valor es el nombre y la clase, que debe agregar al elemento <body>
. En este ejemplo he creado el mapa $themes
con dos variantes: theme-light
y theme-dark
.
1 |
// _config.scss |
2 |
$themes: ( |
3 |
theme1: theme-light, |
4 |
theme2: theme-dark |
5 |
); |
Obtener el Valor (Camino Corto)
Ahora necesitamos una función para obtener una forma rápida de obtener valores de los módulos. Es una función de ayuda breve y necesita tres parámetros. Estos son:
-
$map
: Define el nombre del mapa de donde provienen todos los valores. -
$object
: En este caso la clave para el tema. -
$style
: La propiedad para el estilo que se necesita.
1 |
// _functions.scss |
2 |
@function setStyle($map, $object, $style) { |
3 |
@if map-has-key($map, $object) { |
4 |
@return map-get(map-get($map, $object), $style); |
5 |
} |
6 |
@warn "The key ´#{$object} is not available in the map."; |
7 |
@return null; |
8 |
} |
Construir el Módulo
Ahora cree un nuevo mapa Sass llamado $config
. Cada tema recibe un objeto y el nombre debe ser la misma clave que se define en $themes
: si no, obtendrá un error.
1 |
// _m-buttons.scss |
2 |
// 1.Config |
3 |
$config: ( |
4 |
theme1: ( |
5 |
background: #f2f2f2, |
6 |
color: #000 |
7 |
), |
8 |
theme2: ( |
9 |
background: #666, |
10 |
color: #fff |
11 |
) |
12 |
); |
Bucle a Través de los Temas
Finalmente la parte con un poco de magia. Comenzamos con un módulo como .m-button
y luego queremos crear un aspecto diferente en cada tema. Así que utilizamos @each
con $key
y $value
como valores esperados que obtenemos del mapa $themes
. Ahora Sass recorre las claves del mapa y crea algo para cada tema.
Al principio de esta sección mencioné que es necesario que las claves sean las mismas en cada mapa ($themes
y $config
). Por lo tanto, debemos comprobar si el mapa $config tiene la clave del mapa $themes
, así que utilice la función map-has-key()
. Si la clave está disponible, haga lo siguiente, de lo contrario, lance un error para informar al desarrollador.
1 |
// _m-buttons.scss |
2 |
// 2.Base |
3 |
.m-button { |
4 |
@each $key, $value in $themes { |
5 |
@if map-has-key($config, $key) { |
6 |
.#{$value} & { |
7 |
background: setStyle($config, $key, background); |
8 |
color: setStyle($config, $key, color); |
9 |
} |
10 |
} @else { |
11 |
@warn "The key ´#{$key} isn’t defined in the map $config´" |
12 |
} |
13 |
} |
14 |
} |
Después de todo el código escrito, echemos un vistazo al resultado. Es magnífico que el área de configuración esté separada de la lógica del módulo.
1 |
.theme-light .m-button { |
2 |
background: #f2f2f2; |
3 |
color: #000; |
4 |
} |
5 |
.theme-dark .m-button { |
6 |
background: #666; |
7 |
color: #fff; |
8 |
} |
Finalmente es el momento de probarlo por usted mismo. Tal vez esta solución no funcione para usted y usted necesite otra, pero en definitiva espero que le ayudará a mantener su código bien. Puede jugar con este ejemplo en Codepen:
Pensamientos Finales
En mis ojos Sass Maps fue la mejor característica que se introdujo en Sass 3.3. Personalmente, siento que son una gran manera de dar a su código base una mejor estructura y crear pequeñas áreas de configuración. Los mapas Sass facilitan el manejo y el cambio de valores sin afectar la lógica de todo el código base. ¡Comience a usarlos hoy, sus compañeros de trabajo estarán agradecidos!
Si ya está utilizando los mapas Sass, ¡háganos saber cómo los usa en sus proyectos.