Tutorial. Cambiar grid de Bootstrap

06/02/2016

Hoy explicare como modificar el sistema grid de Bootstrap 4.0.0 alpha 2 para optimizarlo según el tipo de grid que tengamos pensado realizar. Para ello os dejare un entorno de trabajo preconfigurado para explicar de forma sencilla como es el procedimiento de customizarlo. Es una carpeta de nombre Boostrap con sus ficheros Gruntfile.js y package.json ya configurados, tan solo debéis ejecutar npm install dentro de ella como ya explique en mi anterior tutorial de Grunt.

Entorno de trabajo

package.json. Necesitaremos Grunt junto a los plugins grunt-sass (para compilar Bootstrap), grunt-contrib-watch (para ahorrarnos compilar cada vez que modifiquemos un *.scss) y load-grunt-tasks (para no perder tiempo en registrar los plugins que utilicemos).

{
    "name": "bootstrap",
    "devDependencies": {
        "grunt": "~0.4.5",
        "grunt-contrib-watch": "*",
        "grunt-sass": "*",
        "load-grunt-tasks": "*"
    }
}

Gruntfile.js. Este fichero de configuración puede ser un poco mas complicado de entender, he dejado comentarios para evitar cualquier tipo de duda al respecto.

module.exports = function (grunt) {
    /* Variable global path_css para indicar la ruta de nuestros *.css */
    var globalConfig = {
        path_css: "css"
    };

    grunt.initConfig({
        /* Renombramos. En config.path_css estara el valor */
        config: globalConfig,
        /* Podemos pasar la variable name de package.json leyendo
        el fichero */
        pkg: grunt.file.readJSON('package.json'),
        /* Proceso encargado de compilar a css:
            bootstrap-grid.css <<<<- bootstrap-grid.scss.
        */
        sass: {
            grid: {
                files: {
                    "<%= config.path_css %>/<%= pkg.name %>-grid.css": "scss/<%= pkg.name %>-grid.scss"
                }
            }
        },
        /* Si ejecutamos grunt watch y modificamos algun
        fichero *.scss en la carpeta scss lanzara sass:grid */
        watch: {
            default: {
                files: ['scss/**/*.scss'],
                tasks: ['sass:grid'],
            }
        }
    });

    require('load-grunt-tasks')(grunt, {
        scope: 'devDependencies'
    });
    grunt.registerTask('bootstrap-grid', ['sass:grid']);

};

Lanzamos el siguiente comando para que cualquier modificación que realicemos en la carpeta scss nos de como resultado un bonito bootstrap-grid.css en nuestra carpeta css del proyecto:

grunt watch

Podemos abrir el index.html con cualquier navegador. En el extremo inferior izquierda tenemos un indicador que nos informa en que dispositivo nos encontramos segun la anchura de nuestra ventana. xs (telefono diminuto), sm (smartphone), md (tablets), lg (escritorio normal) y xl (escritorio enorme), estas son las nomenclaturas que emplearemos en el nuevo Bootstrap 4.0.

Si os habéis cansado de trastear pasamos a ver el codigo de index.html. Dentro del container comprobareis que hay 3 elementos con sus clases col-* (columnas), Bootstrap divide los container en columnas hasta un maximo de 12. Ahora quedémonos con una de estas clases para explicar como funciona este sistema, por ejemplo col-md-4, la nomenclatura md nos indica que afecta a las tablets y el numero 4 nos alerta de que su anchura en ese tipo de dispositivos es de un ratio de 4/12 ocupando un 33.33% del container.

Customizar el grid

El bootstrap-grid.css que tenemos es el que viene por defecto pero... ¿podemos optimizarlo a nuestro antojo? ¿se puede customizar? si, siempre y cuando tengamos cuidado con las modificaciones que hagamos en la carpeta scss. Antes de comenzar debo recalcar que los ficheros *.scss que pasare a listar han sido modificados con comentarios en español para facilitar la comprensión de los mismos.

scss/bootstrap-grid.scss. En este fichero se encuentran las variables mas importantes para crear nuestro grid:

/* listado con los limites preestablecidos*/ $grid-breakpoints: ( // Moviles pequeños xs: 0, // Smartphone sm:
    544px, // Tablets md: 768px, // Escritorio normal lg: 992px, // Escritorio enorme xl: 1200px ) !default;
    $container-max-widths: ( sm: 576px, md: 720px, lg: 940px, xl: 1140px ) !default; $grid-columns: 12 !default;
    $grid-gutter-width: 1.875rem !default; // 30px @import "variables"; @import "mixins/clearfix"; @import
    "mixins/breakpoints"; @import "mixins/grid-framework"; @import "mixins/grid"; @import "grid";

OK, nos toca modificar este fichero en función del contenido del index.html que visteis anteriormente. Lo primero que haremos es comentar la vista xl debido a que no la usamos en el index.html que os pase así que podéis eliminarla. Ahora el ancho máximo de los escritorios enormes dependerán del valor de lg en $container-max-widths, lo cambiamos por 820px. La cosa quedaría de esta forma:

$grid-breakpoints: ( // Moviles pequeños xs: 0, // Smartphone sm: 544px, // Tablets md: 768px, // Escritorio normal
    lg: 992px ) !default; $container-max-widths: ( sm: 576px, md: 720px, lg: 820px ) !default;

¿Que pasa con $grid-columns? buena pregunta... tenemos que descubrir el valor idóneo según nuestro index.html con una regla muy sencilla:

$grid-columns = (nº max divisiones par)*(nº max divisiones impar)

En la vista Tablet veréis que se divide en 3 columnas, mientras que la división par máxima que encontrareis sera un simple 2, multiplicamos 2x3 y obtendréis el 6 como valor óptimo. Reemplazamos:

<code class="language-scss">$grid-columns: 6 !default;

Se me ha olvidado comentar que modificar $grid-columns implica cambiar nuestro index.html, aquí viene nuestra 2º regla. Para pasar de 12 a 6 hemos tenido que dividir por 2, pues bien, todo col-X-(num) pasara a col-X-(num/2) y con eso seria suficiente para subsanar el desaguisado.

scss/mixins/_grid-framework.scss. La columna vertebral que genera los estilos fundamentales para nuestro grid con Bootstrap 4:

@mixin make-grid-columns(
$columns: $grid-columns, 
$gutter: $grid-gutter-width, 
$breakpoints: $grid-breakpoints) {
  /* Plantilla de las columnas, aqui podremos introducir 
  los estilos que nos interese usar */
  %grid-column {
    position: relative;
    min-height: 1px;
    /* Mis estilos */
    padding: 1em 0;
    background-color: 	#0084b4;
    outline: 1px solid #fff;
    text-align: center;
    color: #fff;
    font-size: 32px;
    /* Fin de mis estilos */
    // bug??
    //padding-left: ($gutter / 2);
    //padding-right: ($gutter / 2);
  }
  @each $breakpoint in map-keys($breakpoints) {
  
    /* Importancia nula */
    @for $i from 1 through $columns {
      .col-#{$breakpoint}-#{$i} {
        @extend %grid-column;
      }
    }
    
    /* Bastante simple, igual te interesa que las columnas 
    floten a la izquierda pero nada mas */
    @include media-breakpoint-up($breakpoint) {
      %grid-column-float-#{$breakpoint} {
        float: left;
      }
      
      /* Importancia nula */
      @for $i from 1 through $columns {
        .col-#{$breakpoint}-#{$i} {
          @if not $enable-flex {
            @extend %grid-column-float-#{$breakpoint};
          }
          @include make-col-span($i, $columns);
        }
      }
      
      /* Podemos eliminar todo esto si no tenemos pensado 
      usar offset, push y pull */
      @each $modifier in (pull, push, offset) {
        @for $i from 0 through $columns {
          .col-#{$breakpoint}-#{$modifier}-#{$i} {
            @include make-col-modifier($modifier, $i, $columns)
          }
        }
      } 
      
    }
  }
}

En este fichero reemplazaremos los ".col-" que veis en verde por un "." y en nuestro index.html sustituiremos todas las clases col-(X)-(num) por (X)-(num), es decir, col-md-4 a md-4 y así con todos.

scss/mixins/_grid.scss. De este archivo solo me centrare en la función encargada de encapsular los anchos máximos del container en los diferentes dispositivos:

@mixin make-container-max-widths($max-widths: $container-max-widths) {
    @each $breakpoint,
    $container-max-width in $max-widths {
        @include media-breakpoint-up($breakpoint) {
            max-width: $container-max-width;
        }
    }
}

Imaginar que os pido que el container en los escritorios normales no tenga margen por la izquierda, pues...

@mixin make-container-max-widths($max-widths: $container-max-widths) {
    @each $breakpoint,
    $container-max-width in $max-widths {
        @include media-breakpoint-up($breakpoint) {
            max-width: $container-max-width;
            /* Si estamos en un escritorio normal... */
            @if ($breakpoint == "lg") 
            {
                /* ...lo pegamos a la izquierda */
                margin-left: 0px;                
            }
            
        }
    }
}

Y aquí finalizo el tutorial de hoy, os dejo un link del entorno de trabajo con todas las modificaciones que he realizado y comprobéis el resultado final.