Escrevendo Lógica em CSS

doug-source - Aug 5 - - Dev Community

Nota: apenas traduzi o texto abaixo e postei aqui. As referências estão no fim deste artigo.

CSS é uma linguagem de programação altamente especializada com foco em style systems. Por causa desse caso de uso único e sua natureza declarativa, às vezes é difícil de entender. Algumas pessoas até negam que seja uma linguagem de programação. Vamos provar que estão errados programando um style system inteligente e flexível.

Estruturas de controle

Linguagens mais tradicionais e de uso geral (como JavaScript) nos dão ferramentas como "Conditions" (if/then), "Loops" (for, while), "Logical Gates" (===, &&, etc.) e "Variables". Essas estruturas são nomeadas de forma diferente em CSS, sua sintaxe é muito diferente para acomodar melhor o caso de uso específico de estilizar um document, e algumas delas simplesmente não estavam disponíveis em CSS até alguns anos atrás.

Variables

Variables ​​são as mais diretas. Elas são chamadas de Custom properties em CSS (embora todos as chamem de variáveis ​​de qualquer maneira, até mesmo sua própria sintaxe).

:root {
    --color: red;
}
span {
    color: var(--color, blue);
}
Enter fullscreen mode Exit fullscreen mode

O traço duplo declara uma variable e atribui um valor. Isso tem que acontecer em um escopo porque fazer isso fora de um selector quebraria a sintaxe CSS. Observe o selector :root, que funciona como um escopo global.

Conditions

As Conditions podem ser escritas de várias maneiras, dependendo de onde você deseja usar elas. Os selectors têm escopo para seus elements, as media queries têm escopo global e precisam de seus próprios selectors.

Attribute Selectors:

[data-attr='true'] {
    /* if */
}
[data-attr='false'] {
    /* elseif */
}
:not([data-attr]) {
    /* else */
}
Enter fullscreen mode Exit fullscreen mode

Pseudo classes

:checked {
    /* if */
}
:not(:checked) {
    /* else */
}
Enter fullscreen mode Exit fullscreen mode

Media Queries:

:root {
    color: red; /* else */
}
@media (min-width > 600px) {
    :root {
        color: blue; /* if */
    }
}
Enter fullscreen mode Exit fullscreen mode

Loops

Counters são a forma mais direta de loops em CSS, mas também a que tem o caso de uso mais restrito. Você só pode usar counters na content property, exibindo ela como texto. Você pode ajustar seu "increment", seu "starting point" e seu "value" em qualquer ponto dado, mas o output é sempre limitado a texto.

main {
    counter-reset: section;
}

section {
    counter-increment: section;
    counter-reset: section;
}

section > h2::before {
    content: 'Headline ' counter(section) ': ';
}
Enter fullscreen mode Exit fullscreen mode

Mas e se você quisesse usar um loop para definir um layout pattern recorrente? Esse tipo de loop é um pouco mais obscuro: é a auto-fill property dos grids.

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
Enter fullscreen mode Exit fullscreen mode

Isso preenche o grid com tantos elementos quantos ele puder encaixar, enquanto dimensiona eles para preencher o espaço disponível, mas quebra eles em várias linhas quando necessário. Ele se repete enquanto encontrar grid itens e limita eles a uma width mínima de 300px e uma width máxima de uma fração do tamanho do grid container deles. Provavelmente é mais fácil ver do que explicar:

codepen

E, finalmente, há "looped selectors". Eles pegam um argumento, que pode ser uma fórmula para selecionar com muita precisão.

section:nth-child(2n) {
    /* seleciona todos os elementos pares */
}

section:nth-child(4n + 2) {
    /* seleciona a cada quarto items, iniciando a partir do segundo */
}
Enter fullscreen mode Exit fullscreen mode

Para casos realmente especiais, você pode combinar :nth-child() com :not(), como:

section:nth-child(3n):not(:nth-child(6)) {
    /* seleciona a cada 3 elementos, mas não o sexto elemento */
}
Enter fullscreen mode Exit fullscreen mode

codepen

Você pode substituir :nth-child() por :nth-of-type() e :nth-last-of-type() para alterar o escopo desses últimos exemplos.

Logic Gates

Ana Tudor escreveu um artigo sobre CSS Logic Gates. Login Gates trabalham com a ideia de combinar variáveis ​​com calc. Ela então continua modelando e animando 3D objects com isso. Parece mágica arcana, fica muito mais insano conforme o artigo avança e é geralmente uma das melhores explicações de por que CSS é de fato uma linguagem de programação.

Técnicas

O Owl Selector

* + * {
    margin-top: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

O Owl Selector seleciona cada item que segue um item. Aplicar um margin-top a isso efetivamente adiciona um gap entre os itens, como o grid-gap faz, mas sem o grid system. Isso também significa que é mais customizável. Você pode sobrescrever sua margin-top e adaptar para qualquer tipo de conteúdo. Quer ter 1rem de espaço entre cada item, mas 3rem antes de um título? Isso é mais fácil de fazer com um owl selector do que em um grid.

Kevin Pennekamp tem um artigo aprofundado sobre isso que até explica seu algoritmo em pseudocódigo.

Conditional Styling

Podemos criar toggles em nosso código css que ligam e desligam certas regras com variables ​​e calc. Isso nos dá condições muito versáteis.

.box {
    padding: 1rem 1rem 1rem calc(1rem + var(--s) * 4rem);
    color: hsl(0, calc(var(--s, 0) * 100%), 80%);
    background-color: hsl(0, calc(var(--s, 0) * 100%), 15%);
    border: calc(var(--s, 0) * 1px) solid hsl(0, calc(var(--s, 0) * 100%), 80%);
}

.icon {
    opacity: calc(var(--s) * 100%);
    transform: scale(calc(var(--s) * 100%));
}
Enter fullscreen mode Exit fullscreen mode

codepen

Dependendo do valor de --s, .box habilitará ou desabilitará seus alert styles.

Automatic contrast colors

Vamos levar a mesma lógica um passo adiante e criar uma color variable que depende do seu contraste com a background color:

:root {
    --theme-hue: 210deg;
    --theme-sat: 30%;
    --theme-lit: 20%;
    --theme-font-threshold: 51%;

    --background-color: hsl(var(--theme-hue), var(--theme-sat), var(--theme-lit));

    --font-color: hsl(
        var(--theme-hue),
        var(--theme-sat),
        clamp(10%, calc(100% - (var(--theme-lit) - var(theme-font-threshold)) * 1000), 95%)
    );
}
Enter fullscreen mode Exit fullscreen mode

Este snippet calcula um background color a partir de valores HSL e uma font color black ou white, invertendo o valor de lightness (luminosidade) do background. Isso por si só pode resultar em baixo contraste de cor (uma fonte cinza de 40% em um background cinza de 60% é praticamente ilegível), então subtrairei um valor threshold (o ponto em que a cor muda de white para black), multiplicarei por um valor insanamente alto como 1000 e farei clamp nele entre 10% e 95%, para obter uma porcentagem de lightness válida no final. Tudo é controlável editando as quatro variáveis ​​no início do snippet.

codepen

Este método também pode ser usado para escrever lógica de cores intrincada e themes automáticos, com base apenas em valores HSL.

Limpando as stylesheets

Vamos combinar o que temos até agora para limpar a stylesheet. Ordenando tudo por viewports parece um pouco espaguete, mas ordenar isso por componente não parece nada melhor. Com variables, podemos ter o melhor dos dois mundos:

/* define variables */
:root {
    --paragraph-width: 90ch;
    --sidebar-width: 30ch;
    --layout-s: "header header" "sidebar sidebar" "main main" "footer footer";
    --layout-l: "header header" "main sidebar" "footer footer";
    --template-s: auto auto minmax(100%, 1fr) auto /
        minmax(70%, var(--paragraph-width)) minmax(30%, var(--sidebar-width));
    --template-l: auto minmax(100%, 1fr) auto /
        minmax(70%, var(--paragraph-width)) minmax(30%, var(--sidebar-width));
    --layout: var(--layout-s);
    --template: var(--template-s);
    --gap-width: 1rem;
}

/* manipula variables por viewport */
@media (min-width: 48rem) {
    :root {
        --layout: var(--layout-l);
        --template: var(--template-l);
    }
}

/* realiza o bind no DOM */
body {
    display: grid;
    grid-template: var(--template);
    grid-template-areas: var(--layout);
    grid-gap: var(--gap-width);
    justify-content: center;
    min-height: 100vh;
    max-width: calc(
        var(--paragraph-width) + var(--sidebar-width) + var(--gap-width)
    );
    padding: 0 var(--gap-width);
}
Enter fullscreen mode Exit fullscreen mode

codepen

Todas as global variables são definidas no topo e ordenadas por viewport. Essa seção efetivamente se torna a Definition of Behavior, esclarecendo questões como:

  • Quais aspectos globais da stylesheet temos? Estou pensando em coisas como font size, colors, medidas repetidas, etc.
  • Quais aspectos que mudam frequentemente nós temos? Container widths, Grid layouts e similares vêm à mente.
  • Como os valores devem mudar entre as viewports? Quais global styles se aplicam a qual viewport?

Abaixo estão as definições de regras, ordenadas por componente. As Media Queries não são mais necessárias aqui, porque elas já estão definidas no topo e colocadas em variables. Podemos simplesmente codificar em nossas stylesheets sem interrupções neste ponto.

Leando o hash parameter

Um caso especial de pseudo classes é o :target selector, que pode ler o hash fragment da URL. Aqui está uma demonstração que usa essa mecânica para simular uma experiência semelhante a SPA:

codepen

Eu escrevi um post sobre isso. Só esteja ciente de que isso tem algumas implicações sérias de acessibilidade e precisa de alguma mecânica JavaScript para realmente ser livre de barreiras. Não faça isso em um live environment.

Definindo Variables ​​em JavaScript

Manipular CSS variables se tornou uma ferramenta muito poderosa agora. Também podemos aproveitar isso em JavaScript:

    // configura --s em :root
    document.documentElement.style.setProperty('--s', e.target.value);

    // configura --s scoped para #myID
    const el = document.querySelector('#myID');
    el.style.setProperty('--s', e.target.value);

    // lê variables de um element
    const switch = getComputedStyle(el).getPropertyValue('--s');
Enter fullscreen mode Exit fullscreen mode

Os exemplos de codepen acima funcionam exatamente assim.

Resumo

CSS é muito capaz de definir layout systems inteligentes e reativos. Suas estruturas de controle e algoritmos podem ser um pouco estranhos em comparação com outras linguagens, mas eles estão lá e estão à altura da tarefa. Vamos parar de apenas descrever alguns styles e começar a fazer eles funcionar.

Fonte

Artigo escrito por Daniel Schulz

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player