Iniciamos este artículo dedicado a las funciones en SASS. En principio, puede sonar algo extraño. ¿Funciones en CSS? Si CSS no usa funciones. De acuerdo. Es cierto. CSS no las usa. Pero recuerda que SASS no es CSS. Es una forma alternativa de escribir CSS, con muchas más prestaciones.
En SASS sí disponemos de funciones. El concepto es, exactamente, el mismo que en cualquier lenguaje de programación. Una función es un bloque de código que se define para que lleve a cabo determinadas acciones, cálculos u operaciones, pero no hace nada hasta que es invocada.
En SASS podemos trabajar con dos tipos de funciones: las que forman parte, por defecto del propio SASS (las funciones nativas) y las funciones de usuario, es decir, aquellas que creamos nosotros para hacer lo que necesitemos en cada momento. En este artículo nos vamos a centrar en estas últimas. Aunque usaremos algunas funciones nativas de SASS que necesitaremos para mostrar algunos conceptos, realmente lo que aquí perseguimos es aprender a crear y usar nuestras propias funciones. Vas a ver que es tan facil y tan potente como en cualquier lenguaje de programación.
LAS FUNCIONES DE USUARIO
Cuando trabajamos en SASS con funciones debemos tener en cuenta algunas reglas:
- Las funciones se declaran con la directiva
@function
, seguida del nombre que deseemos darle a la función, y un juego de paréntesis para los parámetros. Puede que necesitemos pasarle parámetros, o no (eso dependerá de lo que tenga que hacer la función y de como la diseñemos), pero los paréntesis deben estar. - Tras la directiva
@function
, se escribe el cuerpo de la función, encerrado entre llaves. Esto es común a la mayoría de lenguajes (Java, JavaScript, PHP, y un largo etcétera). - Una función siempre debe devolver un valor. Para ello se emplea la directiva
@return
, seguida del valor (o variable que lo contiene). - Si declaramos una variable dentro del cuerpo de una función, dicha variable sólo «vive» en el ámbito de la función. Si necesitamos «sacarla» fuera, debemos devolverla con
@return
. - La función se invoca donde la necesitemos, simplemente escribiendo su nombre, con los argumentos si fueran necesarios.
UN EJEMPLO SENCILLO
Como la mejor manera de aprender a hacer algo es haciéndolo, vamos a crear un ejemplo muy simple (y, a los efectos, poco útil) pero con el valor didáctico para tener un punto de arranque. Imagina que en un HTML tienes definido un contenedor:
<div id="container"></div>
Tenemos un archivo llamado funciones_1.scss
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
@charset "UTF-8"; // Declaramos una función que no recibe argumentos. // Lo único que hace es devolver una cadena de texto. @function contenido(){ @return "HOLA"; } // Declaramos las reglas CSS para el contenedor. #container { position: relative; border: 1px solid black; border-radius: 10px; width: 300px; height: 150px; top: 10px; margin: 0 auto; line-height: 150px; font-size: 30pt; font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; text-align: center; // Establecemos un contenido que será el que nos // devuelva la función declarada anteriormente &::before{ content: contenido(); } } |
Observa las líneas resaltadas. En el primer bloque (líneas 5
, 6
, y 7
) se declara la función. Como ves, sólo devuelve una cadena de texto. No hace nada más. En la línea 25
se establece el contenido del contenedor, invocando a la función que hemos creado.
Como sabemos que el navegador no nos va a interpretar código SASS, y que CSS no dispone de funciones, vamos a ver cómo se transpila el listado anterior a funciones_1.css
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@charset "UTF-8"; /* line 10, scss/funciones_1.scss */ #container { position: relative; border: 1px solid black; border-radius: 10px; width: 300px; height: 150px; top: 10px; margin: 0 auto; line-height: 150px; font-size: 30pt; font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; text-align: center; } /* line 24, scss/funciones_1.scss */ #container::before { content: "HOLA"; } |
Observa el bloque resaltado al final. El transpilador ha obtenido el resultado de la función, y lo ha incluido como una regla CSS con la sintaxis correcta para hojas de estilos.
Si aplicas esta hoja de estilos obtienes un resultado en tu contenedor similar al que ves a la derecha. Como puedes observar, el contenido es la cadena que ha devuelto la función.
EL USO DE PARÁMETROS
Lo que acabamos de ver está muy bien, ilustra la operativa de la directiva @function
en SASS pero, como uso práctico no tiene ninguno. Es algo totalmente rígido e inamovible. Lo suyo es que una función reciba uno o más argumentos, haga algún tipo de operación con ellos, y nos devuelva un resultado que podamos usar, y que dependa de los argumentos pasados y de como se hayan procesado en la función. Vamos, hablando claro: lo mínimo que se le puede pedir a las funciones en cualquier lenguaje. Afortunadamente, SASS nos permite llevar a cabo, incluso, operaciones aritméticas. Esa es una prestación que vamos a emplear en este ejemplo.
Lo que vamos a hacer es definir reglas de estilos para una clase que le aplicaremos a distintos contenedores de un documento web. El objetivo es poder establecer la anchura de los contenedores mediante una función de SASS, de modo que podamos indicarle cuantos contenedores vamos a tener, y la función determine el ancho que deben tener para ocupar el 100% de la pantalla. Pero eso no es todo. Los contenedores deben tener unos márgenes a derecha e izquierda, así que la función deberá calcular el ancho de los contenedores en función del número de estos y del margen que le establezcamos (el mismo para todos). Para colmo, la anchura resultante debe ser un porcentaje del ancho total de la pantalla, pero el margen estará establecido en píxeles. Con las funciones de usuario de SASS, su capacidad de cálculo y alguna función nativa, lo resolvemos sin ningún esfuerzo. Mira el listado funciones_2.scss
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
@charset "UTF-8"; // Declaramos una función que calculará la anchura para los contenedores. // Recibe dos argumentos: // - El primero es el número de contenedores que tienen que distribuirse horizontalmente a lo ancho de la pantalla. // - El segundo es el margen lateral (izquierdo y derecho) que debe tener cada contenedor. // La función calcula el ancho que deben tener los contenedores, // y devuelve ese dato. @function calcularAnchura($numeroDeContenedores, $margenLateral){ // Empezamos doblando el margen establecido. Esto se debe a que, // como el margen debe estar a la izquierda y a la derecha del contenedor, // para el cálculo de anchura se deben tener en cuenta ambos márgenes. $margenLateral: $margenLateral * 2; // La anchura de los contenedores se calcula como un porcentaje del // ancho de la pantalla, en base al número de contenedores. // Para ello se emplea la función nativa de SASS percentage. // Inicialmente se calcula "en bruto", es decir, sin incluir los // márgenes laterales que se le aplicarán a los contenedores. $anchuraDeContenedor: percentage(1 / $numeroDeContenedores); // Finalmente, la anchura se establece como un calculo de la anchura // porcentual que hemos calculado "en bruto", menos los márgenes laterales. // Observa la peculiar sintaxis con la que se han indicado las variables // de la función calc(). Esta sintaxis se llama interpolación, y es necesaria // para que SASS las interprete correctamente en este contexto. $anchuraDeContenedor: calc(#{$anchuraDeContenedor} - #{$margenLateral}); @return $anchuraDeContenedor; } // Declaramos las reglas CSS para una clase que le aplicaremos a todos los // contenedores que queramos incluir en una fila a lo ancho. .container { position: absolute; border: 1px solid black; border-radius: 10px; // Establecemos la anchura con la función que hemos declarado, // pasándole los dos argumentos necesarios: el número de contenedores // y el margen lateral (observa que este último se expresa en píxeles, // para que sea fijo, independientemente del número de contenedores o // el ancho del viewport. width: calcularAnchura(6, 4px); height: 150px; top: 10px; } |
Observa el código. Todos los detalles importantes están comentados para que veas como hemos logrado el resultado esperado. Lo único que se sale un poco del tema de este artículo es el uso de la función percentage()
. Esta no la hemos declarado nosotros. Es nativa de SASS. Las funciones nativas de SASS están muy bien documentadas en http://sass-lang.com/documentation/Sass/Script/Functions.html. Este enlace no es un mero complemento. Contiene la documentación de las funciones nativas de SASS (algunas de las cuales usaremos en posteriores artículos), y deberías, al menos, echarle un vistazo general, a fin de que sepas dónde documentarte cuando lo necesites.
La función calc()
no es realmente de SASS. Como sin duda ya sabes, es de CSS. Lo que hay aquí que nos puede llamar la atención es la forma en que se le pasan los valores a esta función. Se trata de una sintaxis específica de SASS que se conoce como interpolación. Este tema lo discutiremos en el próximo artículo. De momento, sólo acepta que es la sintaxis que tenemos que usar en esta situación
Por último, échale un vistazo a la línea resaltada. Es la forma en que usamos la función de desarrollador que hemos creado para darle un valor al parámetro width
. Este valor dependerá, por lo que hemos visto, de los argumentos que incluyamos en esta invocación a la función. Si transpilamos con los valores que tenemos en el ejemplo obtendremos el siguiente listado para funciones_2.css
:
1 2 3 4 5 6 7 8 9 |
/* line 31, scss/funciones_2.scss */ .container { position: absolute; border: 1px solid black; border-radius: 10px; width: calc(16.66667% - 8px); height: 150px; top: 10px; } |
Observa, en la línea resaltada, como se ha transpilado el atributo width
. Prueba a cambiar los valores del original en SASS, para ver los cambios en la transpilación.
Por supuesto, para funcionar en un documento HTML, este CSS necesitaría algunos otros detalles. Por ejemplo, estamos estableciendo el ancho de los contenedores que tengan aplicada la clase container
, pero no estamos estableciendo su posición, u otros detalles. Sin embargo, el objetivo didáctico lo hemos cubierto. En realidad, podríamos mejorar esta función para que nos devolviera las posiciones de todos los elementos con la clase container
pero, para eso, necesitamos conocer aún algunas otras estructuras de SASS, así como ciertos tipos de datos. Son temas de los que hablaremos en posteriores artículos de esta serie.
MÁS SOBRE FUNCIONES EN SASS
Si te paras a observar, la estructura de las funciones en SASS tiene un aspecto que recuerda a los mixins, y su objetivo también es optimizar el código. Comparten con los mixins algunas características importantes:
- Una vez declaradas, pueden ser invocadas en distintos puntos del código.
- Pueden tener o no parámetros.
- Se le pueden crear parámetros con valores por defecto. Aquí no hemos creado ningún ejemplo específico, pero la mecánica es la misma que la de los mixins, por lo que no hay mayor misterio.
- Se pueden (y, en realidad, se deben) declarar las funciones en partials, de modo que no nos dificulten la lectura del código principal.
CONCLUYENDO
En este artículo has aprendido a declarar y usar funciones propias en SASS. Como has visto, resulta una ayuda inestimable, entre otras cosas, el hecho de poder manipular variables con operadores. De hecho, esto le da tanta flexibilidad a SASS que, ahora que ya lo conocemos, lo usaremos en otros artículos. El código de este artículo puedes encontrarlo en este enlace.