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 .grid
classe:
$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.
A grid-template-columns
propriedade é 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!
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 .grid
snippet, também segmentamos todos os filhos da grade e definimos seu grid-column-end
valor 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-gap
propriedade:
.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).
A grid-gap
propriedade é usada para definir o espaço entre os itens da grade.
Para concluir o sistema básico de grade, devemos definir as .col
classes:
@for $i from 1 through $grid-columns {
.col-#{$i} { grid-column-end: span #{$i}; }
}
Usamos o loop SASS @for para gerar as .col
classes de acordo com o número de colunas especificado na $grid-columns
variá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-cols
classe 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 à .grid
classe, exceto que não definimos um número de colunas. auto-fit
substitui os 12 da .grid
classe. 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 .grid
classe) 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.
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 ()).
🔥 Com as classes de utilitário .grid-auto ( .grid-auto-cols
e .grid-auto-{size}
), você pode criar layouts responsivos sem a necessidade de usar .col
classes nos itens da grade. Na verdade, você não deve usar .col
classes, 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}
e .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-1
para col-start-12
, enquanto as classes .col-end vão de .col-end-2
para .col-end-13
.
Use-os se desejar que um item da grade se estenda entre uma linha inicial e final específica.
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; }
}