Ativando o Dark Mode em React.js com SCSS Modules 🌙



This content originally appeared on DEV Community and was authored by doug-source

Nota: apenas traduzi o texto abaixo e postei aqui. Atualizei um pouco apenas os códigos. As referências estão no fim deste artigo.

Em um de meus projetos recentes, precisei adicionar suporte para Dark Mode a uma Single Page Application (SPA) React.js. Como estávamos usando SCSS Modules para estilizar nossos elements, vamos explorar como implementar o Dark Mode em um projeto React.js com SCSS Modules.

Alternando entre Color Schemes

Com amplo suporte do navegador para variáveis ​​CSS, não vejo nenhuma alternativa ao uso da abordagem de body css class + variáveis ​​CSS. Isso significa que quando um usuário habilita o Dark Mode em sua application, uma css class .dark é adicionada à tag body e as variáveis ​​são substituídas com base na presença ou ausência desta css class.

Variáveis ​​CSS

Se você ainda não conhece, variáveis ​​CSS (custom properties) são entities em CSS que permitem armazenar valores e usá-los em seus styles. Por exemplo:

body {
    --text-color: #ccc; /** define uma variável CSS **/
}

h1 {
    color: var(--text-color); /** obtêm o valor de uma variável **/
}

p {
    color: var(--text-color); /** obtêm o valor de uma variável **/
}

Os nomes das variáveis ​​devem sempre começar com um dois hífen (--), e você acessa uma variável usando a function var().

A function var() tentará encontrar a variável --text-color dentro de seu escopo ou do escopo de seus parents. No nosso caso, esse é o body. No entanto, você pode reset esta variável para que, por exemplo, os elements h1 e p dentro das sections tenham uma color diferente:

section {
    --text-color: #ddd
}

No nosso caso, esse truque ajudará a override as variáveis ​​do dark mode.

Caso real

Primeiro, declare todas as variáveis ​​que seus designers usam em layouts na pseudoclasse :root e adicione-as a um arquivo global.scss em seu projeto:

:root {
    --black: #000;
    --gray: #ccc;
    --white: #fff;
    --blue: #0085f2;
}

Nesse caso, sugiro não vincular nomes de variáveis ​​às entidades onde você planeja usá-las. Por exemplo, não nomeie elas como --text-primary-color: #ccc, porque definiremos isso no nível dos React component styles. Por exemplo, você tem um component:

import classNames from "classnames";
import { ComponentPropsWithoutRef } from "react";
import styles from "./Text.module.scss";

type TextProps = ComponentPropsWithoutRef<'p'> && {
    type?: "primary" | "secondary";
}

export const Text = ({ type = "primary", children, ...remain }: TextProps) => (
    <p
        {...remain}
        className={
            classNames(styles.root, styles[`${type}Type`])
        }
    >{children}</p>
);

Como você pode ver, este é um React component simples que pode ter um de dois types, que pretendemos tratar no arquivo de style.

O arquivo de style (Text.module.scss) para este component ficará assim:

.primaryType {
    --text-color: var(--blue);

    color: var(--text-color);
}

.secondaryType {
    --text-color: var(--black);

    color: var(--text-color);
}

Aqui, para cada text type, defini minha própria variável cujo valor é retirado da pseudoclasse :root.

Agora, para ativar o dark mode para text, precisamos usar a css class body.dark. Podemos fazer isso da seguinte maneira:

.primaryType {
    --text-color: var(--blue);

    color: var(--text-color);
}

.secondaryType {
    --text-color: var(--black);

    color: var(--text-color);
}

:global(.dark) {
    .primaryType {
        --text-color: var(--gray);
    }

    .secondaryType {
        --text-color: var(--white);
    }
}

:global(.dark) nos permite usar SCSS modules classes globais. Aqui, simplesmente substituímos os valores das variáveis, que, devido ao aninhamento dentro da css class .dark, terão prioridade mais alta do que os declarados acima.

Como estamos usando SCSS, podemos criar um mixin baseado nesta abordagem. Vamos também adicionar uma media query para aplicar o dark mode com base nas configurações do sistema operacional do usuário.

operational system theme screen

Esta será a aparência do mixin:

SCSS Mixin

@mixin dark-mode {
    @media (prefers-color-scheme: dark) {
        @content;
    }

    :global(.dark) {
        @content;
    }
}

E aqui está como você pode usar este mixin:

@use "../styles/mixins";

.primaryType {
    --text-color: var(--blue);

    color: var(--text-color);
}

.secondaryType {
    --text-color: var(--black);

    color: var(--text-color);
}

@include dark-mode {
    .primaryType {
        --text-color: var(--gray);
    }

    .secondaryType {
        --text-color: var(--white);
    }
}

Dessa forma, os styles de dark mode dos seus components serão isolados e convenientemente localizados no final do arquivo, facilitando a navegação por eles. 🌙

Fonte

Artigo escrito por 0ro.


This content originally appeared on DEV Community and was authored by doug-source