aguarde...

11 de janeiro de 2020

Flash Grid: aprenda CSS Grid construindo um sistema de grade

Flash Grid: aprenda CSS Grid construindo um sistema de grade

Ultimamente, tenho experimentado a idéia de construir um sistema de grade leve baseado no CSS Grid.

Nós temos um sistema de grade no CodyFrame , e ele é baseado no Flexbox. No entanto, o CSS Grid tem tantos recursos poderosos não disponíveis no Flexbox, então acabei criando o Flash Grid.

Vou compartilhar todo o processo por trás da criação do Flash Grid. Se você quiser saber mais sobre o CSS Grid, este é um ótimo ponto de partida, pois tocaremos nas principais propriedades do CSS Grid e compartilharemos alguns truques práticos para aproveitar ao máximo esse poderoso sistema de layout.

Caso você prefira pular o tutorial e pegar o código:


Vamos começar! 🙌

O primeiro passo é criar a .gridclasse:

$grid-columns: 12 !default;

.grid {
  --grid-cols: #{$grid-columns};
  display: grid;
  grid-gap: var(--grid-gap, 0); // default grid-gap = 0
  grid-template-columns: repeat(var(--grid-cols), 1fr); // grid of 12 flexible columns

  > * {
    grid-column-end: span var(--grid-cols); // each grid item takes full-width by default
  }
}

Ao definir o número de colunas da grade, usamos o !default sinalizador SCSS no caso de o sistema de grade ser importado como um módulo e queremos que esse valor seja personalizável.

grid-template-columnspropriedade é onde definimos o layout da grade: queremos 12 colunas responsivas. A largura de cada coluna é 1fr. Fr ( unidade de fração ) é uma unidade inteligente, igual a 1 parte do espaço disponível. Como nossa grade é composta por colunas 12x 1fr, cada coluna flexível ocupa 1/12 da largura disponível.

A função repeat () permite passar um único valor de largura (1fr). Outra maneira de definir a mesma grade seria:

.grid {
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; // 🙈
}

… mas, você sabe … não é tão elegante!

Flash Grid: aprenda CSS Grid construindo um sistema de grade

Aqui está uma rápida visão geral da grade que acabamos de criar:

Na captura de tela acima, observe os números entre as colunas (por enquanto, foque apenas nos números positivos na parte superior). Esses números de linha podem ser usados ​​para colocar itens de grade.

No .gridsnippet, também segmentamos todos os filhos da grade e definimos seu grid-column-endvalor igual a span 12.

Por padrão, queremos que cada filho use toda a largura disponível. grid-column-endé usado para especificar a posição final do item de grade. Você pode usar esta propriedade para definir uma linha final (por exemplo, grid-column-end: 3;). Mas se você usar a palavra mágica “span”, definirá quantas colunas devem ser ocupadas pelo item de grade. Por exemplo, grid-column-end: span 12;significa “estender esse elemento por 12 colunas”.

Por que definir um intervalo padrão de 12 colunas para os itens da grade? Estamos trabalhando primeiro em dispositivos móveis. Podemos assumir que, na maioria dos casos, nossos itens de grade ocuparão a largura total (12 colunas) primeiro e, em seguida, uma quantidade menor de colunas em telas maiores. Nosso valor padrão nos impede de especificar em cada item da grade .col-12(intervalo 12) manualmente.

O número de colunas é definido como uma propriedade customizada CSS, caso você queira alterá-lo no nível do componente (ou criando outras classes de utilitários). Por exemplo:

.grid--2 {
  --grid-cols: 2;
}

Em seguida, podemos definir classes de utilitário para a grid-gappropriedade:

.grid-gap-xxxxs { --grid-gap: var(--space-xxxxs, 0.125rem); }
.grid-gap-xxxs  { --grid-gap: var(--space-xxxs, 0.25rem); }
.grid-gap-xxs   { --grid-gap: var(--space-xxs, 0.375rem); }
.grid-gap-xs    { --grid-gap: var(--space-xs, 0.5rem); }
.grid-gap-sm    { --grid-gap: var(--space-sm, 0.75rem); }
.grid-gap-md    { --grid-gap: var(--space-md, 1.25rem); }
.grid-gap-lg    { --grid-gap: var(--space-lg, 2rem); }
.grid-gap-xl    { --grid-gap: var(--space-xl, 3.25rem); }
.grid-gap-xxl   { --grid-gap: var(--space-xxl, 5.25rem); }
.grid-gap-xxxl  { --grid-gap: var(--space-xxxl, 8.5rem); }
.grid-gap-xxxxl { --grid-gap: var(--space-xxxxl, 13.75rem); }

As variáveis ​​de espaçamento fazem parte do CodyFrame . Você pode substituí-los por sua própria escala de espaçamento ou usar os fallbacks especificados em cada variável (o valor após a vírgula ser aplicada se a variável for indefinida).

grid-gappropriedade é usada para definir o espaço entre os itens da grade.

Para concluir o sistema básico de grade, devemos definir as .colclasses:

@for $i from 1 through $grid-columns {
  .col-#{$i}  { grid-column-end: span #{$i}; }
}

Usamos o loop SASS @for para gerar as .colclasses de acordo com o número de colunas especificado na $grid-columnsvariável.

O CSS compilado é:

.col-1  { grid-column-end: span 1; }
.col-2  { grid-column-end: span 2; }
.col-3  { grid-column-end: span 3; }
.col-4  { grid-column-end: span 4; }
.col-5  { grid-column-end: span 5; }
.col-6  { grid-column-end: span 6; }
.col-7  { grid-column-end: span 7; }
.col-8  { grid-column-end: span 8; }
.col-9  { grid-column-end: span 9; }
.col-10 { grid-column-end: span 10; }
.col-11 { grid-column-end: span 11; }
.col-12 { grid-column-end: span 12; }

As classes de coluna especificam o número de colunas ocupadas por um item de grade. Lembre-se de que a palavra “extensão” significa “extensão do elemento entre x colunas”, onde x é o número especificado após a extensão.

Adicione algum tempero de grade CSS

Para recapitular, a versão básica do Flash Grid inclui a definição da grade, a diferença de grade e as classes de utilitário col:

Agora é hora de adicionar um pouco de tempero! 💃

Aqui está a .grid-auto-colsclasse de utilitário:

.grid-auto-cols { // cols = same size
  display: grid;
  grid-gap: var(--grid-gap, 0);
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}

Essa classe é semelhante à .gridclasse, exceto que não definimos um número de colunas. auto-fitsubstitui os 12 da .gridclasse. Isso significa deixar CSS Grid decidir o número de colunas com base no valor da largura das colunas (o segundo valor da função repeat ()).

Mas espere! O valor da largura (1fr na .gridclasse) agora é substituído por uma função minmax (). Literalmente significa que a largura mínima de uma coluna é 0, enquanto o valor máximo é 1fr. Estamos definindo um intervalo de valores para a largura da coluna.

O resultado: você obtém uma grade em que todas as colunas têm a mesma largura, independentemente do conteúdo ou do número de itens da grade.

Flash Grid: aprenda CSS Grid construindo um sistema de grade

Usando uma abordagem semelhante, criamos as .grid-auto-{size}classes de utilitário:

.grid-auto-xs, .grid-auto-sm, .grid-auto-md, .grid-auto-lg, .grid-auto-xl { // auto-sized grid
  display: grid;
  grid-gap: var(--grid-gap, 0);
  grid-template-columns: repeat(auto-fit, minmax(var(--col-min-width), 1fr));
}

.grid-auto-xs { --col-min-width: 8rem; }
.grid-auto-sm { --col-min-width: 10rem; }
.grid-auto-md { --col-min-width: 15rem; }
.grid-auto-lg { --col-min-width: 20rem; }
.grid-auto-xl { --col-min-width: 25rem; }

Diferentemente .grid-auto-cols, essas novas classes têm um valor mínimo de largura igual a --col-min-width. O resultado é uma grade responsiva na qual uma nova coluna é adicionada quando houver espaço suficiente para ela (a largura mínima especificada na função minmax ()).

Flash Grid: aprenda CSS Grid construindo um sistema de grade

🔥 Com as classes de utilitário .grid-auto ( .grid-auto-cols.grid-auto-{size}), você pode criar layouts responsivos sem a necessidade de usar .colclasses nos itens da grade. Na verdade, você não deve usar .colclasses, se quiser que as classes .grid-auto funcionem corretamente.

Finalmente, para tirar proveito dos números das linhas de grade, podemos criar um novo conjunto de classes de utilidade: col-start-{line-number}.col-end-{line-number}.

@for $i from 1 through $grid-columns {
  .col-start-#{$i} { grid-column-start: #{$i}; }
  .col-end-#{$i+1} { grid-column-end: #{$i+1}; }
}

As classes .col-start vão de .col-start-1para col-start-12, enquanto as classes .col-end vão de .col-end-2para .col-end-13.

Use-os se desejar que um item da grade se estenda entre uma linha inicial e final específica.

Flash Grid: aprenda CSS Grid construindo um sistema de grade

Lembre-se de que estes são os números de linha:

Os números negativos na parte inferior são uma maneira alternativa de segmentar as mesmas linhas. Por que eles são úteis: se você deseja segmentar a linha final, independentemente do número de colunas, faça o seguinte:

.col-end { 
  grid-column-end: -1; 
}

As classes .col-start / end permitem criar grades avançadas:

Modificadores de ponto de interrupção de classe

Para tornar nossa grade editável em diferentes pontos de interrupção, podemos adicionar modificadores de classe. No CodyFrame , nossa convenção é adicionar um sufixo @ {breakpoint} às classes (por exemplo, col-4@sm) para direcionar pontos de interrupção.

Aqui está um exemplo dos modificadores de classe no ponto de interrupção x-small:

$breakpoints: (
  xs: 32rem, 
  sm: 48rem,
  md: 64rem,
  lg: 80rem,
  xl: 90rem
) !default;

@mixin breakpoint($breakpoint) {
  @media (min-width: map-get($map: $breakpoints, $key: $breakpoint)) { @content; }
}

@include breakpoint(xs) {
  .grid-auto-xs\@xs { --col-min-width: 8rem; }
  .grid-auto-sm\@xs { --col-min-width: 10rem; }
  .grid-auto-md\@xs { --col-min-width: 15rem; }
  .grid-auto-lg\@xs { --col-min-width: 20rem; }
  .grid-auto-xl\@xs { --col-min-width: 25rem; }

  .grid-auto-cols\@xs { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

  @for $i from 1 through $grid-columns {
    .col-#{$i}\@xs  { grid-column-end: span #{$i}; }
    .col-start-#{$i}\@xs { grid-column-start: #{$i}; }
    .col-end-#{$i+1}\@xs { grid-column-end: #{$i+1}; }
  }

  .col-start-auto\@xs { grid-column-start: auto; }
  .col-end-auto\@xs { grid-column-end: auto; }
}

Versão beta do ⚡️ Flash Grid

A versão beta do Flash Grid está pronta!

Experimente o Codepen:

Código SCSS final:

// ⚡️ Flash Grid
$grid-columns: 12 !default;

.grid, [class*="grid-auto-"] {
  display: grid;
  grid-gap: var(--grid-gap, 0);
}

.grid {
  --grid-cols: #{$grid-columns};
  grid-template-columns: repeat(var(--grid-cols), 1fr);

  > * {
    grid-column-end: span var(--grid-cols);
  }
}

.grid-auto-xs, .grid-auto-sm, .grid-auto-md, .grid-auto-lg, .grid-auto-xl { // auto-sized grid
  grid-template-columns: repeat(auto-fit, minmax(var(--col-min-width), 1fr));
}

.grid-auto-xs { --col-min-width: 8rem; }
.grid-auto-sm { --col-min-width: 10rem; }
.grid-auto-md { --col-min-width: 15rem; }
.grid-auto-lg { --col-min-width: 20rem; }
.grid-auto-xl { --col-min-width: 25rem; }

.grid-auto-cols { // cols = same size
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}

.grid-gap-xxxxs { --grid-gap: var(--space-xxxxs, 0.125rem); }
.grid-gap-xxxs  { --grid-gap: var(--space-xxxs, 0.25rem); }
.grid-gap-xxs   { --grid-gap: var(--space-xxs, 0.375rem); }
.grid-gap-xs    { --grid-gap: var(--space-xs, 0.5rem); }
.grid-gap-sm    { --grid-gap: var(--space-sm, 0.75rem); }
.grid-gap-md    { --grid-gap: var(--space-md, 1.25rem); }
.grid-gap-lg    { --grid-gap: var(--space-lg, 2rem); }
.grid-gap-xl    { --grid-gap: var(--space-xl, 3.25rem); }
.grid-gap-xxl   { --grid-gap: var(--space-xxl, 5.25rem); }
.grid-gap-xxxl  { --grid-gap: var(--space-xxxl, 8.5rem); }
.grid-gap-xxxxl { --grid-gap: var(--space-xxxxl, 13.75rem); }

@for $i from 1 through $grid-columns {
  .col-#{$i}  { grid-column-end: span #{$i}; }
  .col-start-#{$i} { grid-column-start: #{$i}; }
  .col-end-#{$i+1} { grid-column-end: #{$i+1}; }
}

.col-start { grid-column-start: 1; }
.col-end { grid-column-end: -1; }

// breakpoints
$breakpoints: (
  xs: 32rem, 
  sm: 48rem,
  md: 64rem,
  lg: 80rem,
  xl: 90rem
) !default;

@mixin breakpoint($breakpoint) {
  @media (min-width: map-get($map: $breakpoints, $key: $breakpoint)) { @content; }
}

@include breakpoint(xs) {
  .grid-auto-xs\@xs { --col-min-width: 8rem; }
  .grid-auto-sm\@xs { --col-min-width: 10rem; }
  .grid-auto-md\@xs { --col-min-width: 15rem; }
  .grid-auto-lg\@xs { --col-min-width: 20rem; }
  .grid-auto-xl\@xs { --col-min-width: 25rem; }

  .grid-auto-cols\@xs { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

  @for $i from 1 through $grid-columns {
    .col-#{$i}\@xs  { grid-column-end: span #{$i}; }
    .col-start-#{$i}\@xs { grid-column-start: #{$i}; }
    .col-end-#{$i+1}\@xs { grid-column-end: #{$i+1}; }
  }

  .col-start-auto\@xs { grid-column-start: auto; }
  .col-end-auto\@xs { grid-column-end: auto; }
}

@include breakpoint(sm) {
  .grid-auto-xs\@sm { --col-min-width: 8rem; }
  .grid-auto-sm\@sm { --col-min-width: 10rem; }
  .grid-auto-md\@sm { --col-min-width: 15rem; }
  .grid-auto-lg\@sm { --col-min-width: 20rem; }
  .grid-auto-xl\@sm { --col-min-width: 25rem; }

  .grid-auto-cols\@sm { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

  @for $i from 1 through $grid-columns {
    .col-#{$i}\@sm  { grid-column-end: span #{$i}; }
    .col-start-#{$i}\@sm { grid-column-start: #{$i}; }
    .col-end-#{$i+1}\@sm { grid-column-end: #{$i+1}; }
  }

  .col-start-auto\@sm { grid-column-start: auto; }
  .col-end-auto\@sm { grid-column-end: auto; }
}

@include breakpoint(md) {
  .grid-auto-xs\@md { --col-min-width: 8rem; }
  .grid-auto-sm\@md { --col-min-width: 10rem; }
  .grid-auto-md\@md { --col-min-width: 15rem; }
  .grid-auto-lg\@md { --col-min-width: 20rem; }
  .grid-auto-xl\@md { --col-min-width: 25rem; }

  .grid-auto-cols\@md { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

  @for $i from 1 through $grid-columns {
    .col-#{$i}\@md  { grid-column-end: span #{$i}; }
    .col-start-#{$i}\@md { grid-column-start: #{$i}; }
    .col-end-#{$i+1}\@md { grid-column-end: #{$i+1}; }
  }

  .col-start-auto\@md { grid-column-start: auto; }
  .col-end-auto\@md { grid-column-end: auto; }
}

@include breakpoint(lg) {
  .grid-auto-xs\@lg { --col-min-width: 8rem; }
  .grid-auto-sm\@lg { --col-min-width: 10rem; }
  .grid-auto-md\@lg { --col-min-width: 15rem; }
  .grid-auto-lg\@lg { --col-min-width: 20rem; }
  .grid-auto-xl\@lg { --col-min-width: 25rem; }

  .grid-auto-cols\@lg { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

  @for $i from 1 through $grid-columns {
    .col-#{$i}\@lg  { grid-column-end: span #{$i}; }
    .col-start-#{$i}\@lg { grid-column-start: #{$i}; }
    .col-end-#{$i+1}\@lg { grid-column-end: #{$i+1}; }
  }

  .col-start-auto\@lg { grid-column-start: auto; }
  .col-end-auto\@lg { grid-column-end: auto; }
}

@include breakpoint(xl) {
  .grid-auto-xs\@xl { --col-min-width: 8rem; }
  .grid-auto-sm\@xl { --col-min-width: 10rem; }
  .grid-auto-md\@xl { --col-min-width: 15rem; }
  .grid-auto-lg\@xl { --col-min-width: 20rem; }
  .grid-auto-xl\@xl { --col-min-width: 25rem; }

  .grid-auto-cols\@xl { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

  @for $i from 1 through $grid-columns {
    .col-#{$i}\@xl  { grid-column-end: span #{$i}; }
    .col-start-#{$i}\@xl { grid-column-start: #{$i}; }
    .col-end-#{$i+1}\@xl { grid-column-end: #{$i+1}; }
  }

  .col-start-auto\@xl { grid-column-start: auto; }
  .col-end-auto\@xl { grid-column-end: auto; }
}
Posted in Blog
Write a comment