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

dougsource

doug-source

Posted on July 18, 2024

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

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 **/
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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>
);
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

: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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
dougsource
doug-source

Posted on July 18, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related