Atualizando o SASS do Computaria
Após o Manipulando query string para melhor permitir compartilhar uma página carregada dinamicamente acabei atualizando no meu sistema a gem com o SASS. E isso teve um efeito um tanto quanto inesperado: o SASS começou a disparar novos warnings.
Primeiro warning: darken
A primeira reclamação que me subiu fortemente foi em relação ao darken
. Ele
sugeria usar outra alternativa, simplesmente trocar por color.adjust
:
$grey-color-dark: darken($grey-color, 15%); // original
$grey-color-dark: color.adjust($color, $lightness: -15%); // sugestão
Mas ao usar ele dava um erro:
Error: There is no module with the namespace "color".
╷
40 │ $grey-color-dark: color.adjust($grey-color, $lightness: -25%);
Mas então, o que seria isso?
Bem, descobri que é porque agora o SASS está indo para um caminho mais modular.
E eu não chamei o módulo color
. Como faço pra usar o módulo? Chamo com
@use
! Como é um módulo bem padrão, ele é prefixado com sass:
, então vamos
chamar o módulo color
do sass
?
@use "sass:color";
$grey-color-dark: color.adjust($grey-color, $lightness: -25%);
Perfeito, aparentemente funcionou! Efetivamente o SASS reclamou a mesma coisa
pro lighten
, então tal qual foi pro darken
, só fazer um ajuste de
lighteness
da cor. Como é para ficar mais clara, o ajuste é positivo, já que
o ajuste para dicar mais escuro era negativo:
@use "sass:color";
$grey-color-dark: color.adjust($grey-color, $lightness: -25%);
$grey-color-light: color.adjust($grey-color, $lightness: 40%);
Ok, como vemos se tá dando certo? Abrindo o _site/css/main.css
! Sim, eu
valido o artefato final e profit!
No começo eu realmente fiz isso, ao ponto de comparar com o artefato do blog
disponível na web em
https://computaria.gitlab.io/blog/css/main.css
(inclusive tinha mudanças que o diff
não estava pegando direito, então fiz na
mão o meu diferencial).
Mas tem um jeito muito melhor! Posso usar o comando @debug
!
Então, vamos verificar se a cor está de acordo com o que eu tinha no blog já compilado! Pegar um trecho aqui do SCSS:
blockquote {
color: $grey-color;
border-left: 4px solid $grey-color-light;
/* ... */
}
/* da web */
blockquote {
color: #828282;
border-left: 4px solid #e8e8e8;
/* .. */
}
/* gerado local */
blockquote {
color: #828282;
border-left: 4px solid #e8e8e8;
/* .. */
}
Muito bem, o lighten
foi dominado. E para o darken
?
.site-header {
border-top: 5px solid c.$grey-color-dark;
/* .. */
}
/* original */
.site-header {
border-top: 5px solid #424242;
/* .. */
}
/* gerado local */
.site-header {
border-top: 5px solid rgb(66.25, 66.25, 66.25);
/* .. */
}
Ok, não foi o resultado que eu queria. O $lightness: -15%
resultou em um
número quebrado. Qual diferença um 0.25
faria em um olho humano em um
intervalo que vai de [0, 255)
? Nenhuma. Mas eu queria resolver isso. E já que
eu vou ajeitar pro darken
por conta de uma coincidência de valores, vou
aproveitar e fazer pro lighten
também! Vamos começar a testar hipóteses com
@debug
?
Vamos lá, e se eu arredondar o valor? Eu tenho o módulo math
e após declarar
que vou usá-lo tenho acesso a math.round
. Mas pra isso vou precisar acessar
o vermelho, o verde e o vermelho da cor… e, bem? temos color.channel
!
Aqui, o color.channel
você passa a cor e de que canal quer tirar a
propriedade. Como eu quero tirar o vermelho de $grey-color-dark
:
@debug color.channel($grey-color-dark, "red");
E isso imprimiu Debug: 66.25
. Ok, progresso. Arredondar esse valor:
@debug math.round(color.channel($grey-color-dark, "red"));
Arredondado bonitinho: Debug: 66
. Qual o próximo passo? Criar uma nova cor!
Mas como faço isso? Bem, vou tentar colocar o vermelho, o verde e o azul dentro
da função rgb
e ver no que dá… criei uma variável $grey-j
só para ficar
mais fácil manipular e eu conseguir ler o que estou imprimindo:
@use "sass:math";
/* ... */
$grey-j: rgb(
math.round(color.channel($grey-color-dark, "red")),
math.round(color.channel($grey-color-dark, "green")),
math.round(color.channel($grey-color-dark, "blue"))
);
@debug $grey-j;
E o resultado foi um decepcionante Debug: rgb(66, 66, 66)
. Não obtive o que
eu deseja, que era o equivalente #424242
. E se… e se eu usar a função
color.change
para criar uma nova cor?
Vou continuar usar o $grey-j
para os testes, mas vou por o valor original
criado pelo ajuste de escurecimento em uma variável raw
, digamos assim.
$grey-color-dark-raw
:
$grey-color: #828282;
$grey-color-dark-raw: color.adjust($grey-color, $lightness: -25%);
$grey-j: color.change($grey-color-dark-raw,
$red: math.round(color.channel($grey-color-dark-raw, "red")),
$green: math.round(color.channel($grey-color-dark-raw, "green")),
$blue: math.round(color.channel($grey-color-dark-raw, "blue"))
);
@debug $grey-j;
E com isso obtive Debug: #424242
! Uhulll!!!
A versão sem o código de debug ficou assim:
$grey-color: #828282;
$grey-color-light-raw: color.adjust($grey-color, $lightness: 40%);
$grey-color-dark-raw: color.adjust($grey-color, $lightness: -25%);
$grey-color-dark: color.change($grey-color-dark-raw,
$red: math.round(color.channel($grey-color-dark-raw, "red")),
$green: math.round(color.channel($grey-color-dark-raw, "green")),
$blue: math.round(color.channel($grey-color-dark-raw, "blue"))
);
$grey-color-light: color.change($grey-color-light-raw,
$red: math.round(color.channel($grey-color-light-raw, "red")),
$green: math.round(color.channel($grey-color-light-raw, "green")),
$blue: math.round(color.channel($grey-color-light-raw, "blue"))
);
Segundo warning: @import
Bem, o SASS reclamou também do @import
. Não devo usá-lo porque o SASS começou
o processo de remoção disso. Antes eu tinha o arquivo main.scss
assim:
@charset "utf-8";
@use "sass:color"; // para lidar com o escurecer de cores
@use "sass:math"; // para usar o round
// Our variables
$base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
$base-font-size: 16px;
/** outras variáveis */
@mixin media-query($device) {
@media screen and (max-width: $device) {
@content;
}
}
// Import partials from `sass_dir` (defaults to `_sass`)
@import
"base",
"layout",
"syntax-highlighting"
;
A propósito, a crítica ao @import
você pode encontrar na documentação
aqui. Como o @import
funcionava na prática?
Bem, na prática era como se os arquivos _base.scss
, _layout.scss
e
_syntax-highlighting.scss
fossem, nessa exata ordem porque é a ordem que
aparecem no @import
, fossem concatenados no final do main.scss
. Então todas
as declarações feitas em main.scss
estão disponíveis para os arquivos
importados.
Então precisamos usar o @use
no lugar, né? Bem, não. Para começar, cada
@use
é próprio, não posso colocar como no @import
lá em cima que eram todos
juntos separados por vírgula, isso dá erro:
@use
"base",
"layout",
"syntax-highlighting"
;
Então façamos para cada um desses individualmente? Ficaria assim mais ou menos:
@charset "utf-8";
@use "sass:color"; // para lidar com o escurecer de cores
@use "sass:math"; // para usar o round
// Our variables
$base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
$base-font-size: 16px;
/** outras variáveis */
@mixin media-query($device) {
@media screen and (max-width: $device) {
@content;
}
}
// Import partials from `sass_dir` (defaults to `_sass`)
@use "base";
@use "layout";
@use "syntax-highlighting";
Só que isso também dá pane!
Error: @use rules must be written before any other rules.
╷
52 │ @use "syntax-highlighting";
Hmmm, então vou precisar mudar as coisas de canto. Os @use
vão precisar
surgir antes das outras coisas…
Bem, se eu vou por o @use
antes de declarar as variáveis, hora de refatorar
e colocar minhas variáveis em um novo lugar, né?
Refatorando: variáveis em lugar comum
Primeira coisa que eu fiz foi mudar o main.scss
para ficar assim:
@charset "utf-8";
// Import partials from `sass_dir` (defaults to `_sass`)
@use "base";
@use "layout";
@use "syntax-highlighting";
E o miolo dele eu coloquei em um arquivo _common.scss
. Sem nenhum segredo
aqui.
Mas isso implicou algumas coisas… por exemplo, como usar essas variáveis em
outros lugares. Começando pelo _base.scss
:
a {
color: $brand-color;
text-decoration: none;
&:visited {
color: color.adjust($brand-color, $lightness: -15%);
}
&:hover {
color: $text-color;
text-decoration: underline;
}
}
Aqui ele reclama pois não conhece nenhuma dessas variáveis. Ao simplesmente
chamar @use "common"
também não funciona, pois o módulo está em outro
namespace. Como eu resolveria isso? Bem, a primeira opção seria usar o nome do
módulo, que nem foi feito para color
:
@use "sass:color";
@use "common";
// ...
a {
color: common.$brand-color;
text-decoration: none;
&:visited {
color: color.adjust(common.$brand-color, $lightness: -15%);
}
&:hover {
color: common.$text-color;
text-decoration: underline;
}
}
Mas, sinceramente? Ficou feio. Se eu pudesse importar o módulo como c
… E,
bem, eu posso sim fazer isso:
@use "sass:color";
@use "common" as c;
// ...
a {
color: c.$brand-color;
text-decoration: none;
&:visited {
color: color.adjust(c.$brand-color, $lightness: -15%);
}
&:hover {
color: c.$text-color;
text-decoration: underline;
}
}
E eu também posso importar no escopo local, que não necessitaria de mais mudanças:
@use "sass:color";
@use "common" as *;
// ...
a {
color: $brand-color;
text-decoration: none;
&:visited {
color: color.adjust($brand-color, $lightness: -15%);
}
&:hover {
color: $text-color;
text-decoration: underline;
}
}
Ok, preciso adequar também outros cantos de uso, como os media-query
. Por
exemplo:
.wrapper {
max-width: -webkit-calc(#{c.$content-width} - (#{c.$spacing-unit} * 2));
max-width: calc(#{c.$content-width} - (#{c.$spacing-unit} * 2));
margin-right: auto;
margin-left: auto;
padding-right: c.$spacing-unit;
padding-left: c.$spacing-unit;
@extend %clearfix;
// perceba a alteração do media-query, agora é um elemento de `common.scss`
@include c.media-query(c.$on-laptop) {
max-width: -webkit-calc(#{c.$content-width} - (#{c.$spacing-unit}));
max-width: calc(#{c.$content-width} - (#{c.$spacing-unit}));
padding-right: calc(c.$spacing-unit / 2);
padding-left: calc(c.$spacing-unit / 2);
}
}
Estender algo que não existe?
Ok, tá vendo o @extend %clearfix
? O %clearfix
é o que o SASS chama de
“seletor placeholder”. O que isso significa? Bem, a classe .wrapper
acima
compila para algo assim no blog (vai ser alterado após as alterações deste
post):
.footer-col-wrapper:after, .wrapper:after {
content: "";
display: table;
clear: both;
}
Em _layout.scss
tenho a classe .footer-col-wrapper
que também faz
@extend %clearfix
. E em _base.scss
tenho a declaração desse seletor:
/**
* Clearfix
*/
%clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
E, bem. Agora o %clearfix
reside dentro do _base.scss
. E como não está
sendo usado o @import
que faz um append dos arquivos, o %clearfix
não está
mais prontamente disponível. Qual minha primeira reação? “VAMOS REFATORAR!”
E eu coloco o seletor placeholder em _common.scss
. Só que…
Error: The target selector was not found.
Use "@extend %clearfix !optional" to avoid this error.
╷
171 │ @extend %clearfix;
Ok, posso fazer isso. Eu coloco o !optional
, mas a que custo? Eu descobri que
colocar o !optional
resolve o problema de compilação, mas será que o
resultado é mesmo o esperado? Não sei, e fiquei com medo. Preferi contornar!
Eu não consegui de jeito nenhum com importação de módulo nomeado.
Tentei @extend c.%clearfix
para o SASS reclamar de mim. Tentei algumas
variações na posiçãdo do %
, mas nada deu certo…
E… se lembra que tem a importação de mesmo escopo? Então… tentei fazer
@use "common" as *
agora só pra ver se ele pega o seletor placeholder. E qual
não foi minha surpresa quando isso funcionou!
Mas, não. Não quero isso. Parece demais com cheiro de gambiarra! E se no lugar
disso eu não tentasse usar como um mixin
? Eu já tinha o exemplo do
media-query
, e ele funcionava bem. Então transformei o clearfix
, de um
seletor placeholder, em um mixin
:
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
E para usar, só chamar com @include
do mixin, não o @extend
do seletor.
.wrapper {
max-width: -webkit-calc(#{c.$content-width} - (#{c.$spacing-unit} * 2));
max-width: calc(#{c.$content-width} - (#{c.$spacing-unit} * 2));
margin-right: auto;
margin-left: auto;
padding-right: c.$spacing-unit;
padding-left: c.$spacing-unit;
@include c.clearfix;
@include c.media-query(c.$on-laptop) {
max-width: -webkit-calc(#{c.$content-width} - (#{c.$spacing-unit}));
max-width: calc(#{c.$content-width} - (#{c.$spacing-unit}));
padding-right: calc(c.$spacing-unit / 2);
padding-left: calc(c.$spacing-unit / 2);
}
}
Obtive um resultado distinto? Sim, obtive. O que antes ele soltava assim
.footer-col-wrapper:after, .wrapper:after {
content: "";
display: table;
clear: both;
}
Agora ele solta assim:
.wrapper:after {
content: "";
display: table;
clear: both;
}
/* ... */
/* muito distante */
/* ... */
.footer-col-wrapper:after {
content: "";
display: table;
clear: both;
}
Tinha outro seletor placeholder, %vertical-rhythm
, que também mudou algumas
coisas. Antes era assim:
/**
* Set `margin-bottom` to maintain vertical rhythm
*/
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure,
%vertical-rhythm {
margin-bottom: calc($spacing-unit / 2);
}
E no _syntax_highlighting.scss
o vertical-rhythm
também era usado:
.highlight {
background: #fff;
@extend %vertical-rhythm;
// ...
}
Antes o resultado era assim:
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure,
.highlight {
margin-bottom: 15px;
}
/* ... */
.highlight {
background: #fff;
}
Ao alterar para tornar o %vertical-rhythm
para um mixin ficou assim:
// common.scss
@mixin vertical-rhythm {
margin-bottom: calc($spacing-unit / 2);
}
// base.scss
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure {
@include c.vertical-rhythm;
// note aqui a inversão dos valores, antes era aqui que declarava
// vertical-rhythm, agora aqui apenas usa o vertical-rhythm, a fonte de
// verdade dele está em outro lugar
}
// syntax-highlighting.scss
.highlight {
background: #fff;
@include c.vertical-rhythm;
// ...
}
Agora o resultado gerou assim:
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure {
margin-bottom: 15px;
}
/* ... */
.highlight {
background: #fff;
margin-bottom: 15px;
}
Pequeno ajuste no h1
Ok, eu só descobri essa recomendação enquanto escrevia esse trecho específico:
Apesar do padrão do HTM permitir usar múltiplos
<h1>
na mesma página, isso não é considerado uma boa prática. Uma página deve em geral ter apenas um único elemento<h1>
que descreva o seu conteúdo
Extraído da MozDev e traduzido por mim.
Original:
While using multiple
<h1>
elements on one page is allowed by the HTML standard (as long as they are not nested), this is not considered a best practice. A page should generally have a single<h1>
element that describes the content of the page (similar to the document’s<title>
element).
Mas eu espalhei o uso indiscriminado de <h1>
ao usar um único #
para
representar títulos de seção.
Enfim, algo que sempre me incomodava era que o título das seções mais
importantes acabavem ficando menor do que <h2>
. Aproveitei que estava
mexendo no _layout.scss
e notei que estava faltando o <h1>
. Então resolvi
consertar o meu incômodo. O trecho que me chamou atenção foi esse:
.post-content {
margin-bottom: c.$spacing-unit;
h2 {
font-size: 32px;
@include c.media-query(c.$on-laptop) {
font-size: 28px;
}
}
h3 {
font-size: 26px;
@include c.media-query(c.$on-laptop) {
font-size: 22px;
}
}
h4 {
font-size: 20px;
@include c.media-query(c.$on-laptop) {
font-size: 18px;
}
}
}
Olha que interessante! Todo aumento do nível o font-size
diminui em 6 pontos.
Então, se eu vou diminuir um nível para um nível mais básico… eu aumento 6
pontos? Bem, vamos ver no que dá:
.post-content {
margin-bottom: c.$spacing-unit;
h1 {
font-size: 38px;
@include c.media-query(c.$on-laptop) {
font-size: 34px;
}
}
h2 {
font-size: 32px;
@include c.media-query(c.$on-laptop) {
font-size: 28px;
}
}
h3 {
font-size: 26px;
@include c.media-query(c.$on-laptop) {
font-size: 22px;
}
}
h4 {
font-size: 20px;
@include c.media-query(c.$on-laptop) {
font-size: 18px;
}
}
}
E sinceramente? Nem pareceu tão ruim assim, melhorou significativamente em
relação a o que se tinha antes. A próxima alteração vai ser para remover os
<h1>
excessivos. Inclusive isso vai ajudar na hora de portar um conteúdo para
o dev.to. E isso foi um dos pontos que eu comentei no
Computaria no dev.to.