Logo Icon

AllTheCookies

7 minutos de leitura · 2023/08/24

Modo noturno simples e efetivo

Escrito por:

Introdução

Ter um modo escuro na sua página web é essencial para deixar ela mais acessível. Existem muitos métodos para implementá-lo, neste tutorial irei ensinar como fazer isso por meio de CSS, atributos de elementos html e o mínimo possível de JavaScript!

Planejamento

Antes de começar a implementação, precisamos decidir exatamente como queremos que o nosso dark mode funcione. Sabendo disso, podemos delimitar algumas features básicas que são interessantes para nossa implementação ter:

Não haver a necessidade de utilizar classes diferentes para o modo claro e escuro; Armazenamento do modo que o usuário usou na última seção; Se o usuário está visitando a página pela primeira vez, utilizar preferências do Browser se possível; Um botão, obviamente.

Excelente, vamos lá!

Implementação do HTML, Cores e Lógica da Troca de Tema

Comecemos com um html básico, com um botão para fazer a troca de tema e um card para armazenar conteúdo separado do resto do corpo da página:

<button class="theme-toggle">☀️</button>
<div class="card">
  <h1 class="title-text">Coisas importantes</h1>
  <ul class="base-text">
	<li>Coisa importante 1</li>
	<li>Coisa importante 2</li>
	<li>Coisa importante 3</li>
  </ul>
</div>

Utilizar cores aleatoriamente por nosso CSS deixaria nossa interface de usuário uma bagunça. Logo, declaramos variáveis do CSS específicas para cada parte do código com --nome e as utilizaremos depois com var(--nome).

Agora vem a parte principal do nosso código: definir variáveis CSS para cada tema com base no atributo “theme” do elemento <html>. Para acessar o atributo de um elemento HTML, utilizamos a sintaxe html[nomeAtributo=”alguma coisa”].

Vamos definir esse atributo com o valor “light” utilizando o seguinte código JavaScript:

document.firstElementChild.setAttribute("theme", “light”);

O objeto document representa nossa página web e, com o método firstElementChild, estamos acessando o primeiro elemento dele: o <html>! Após isso, criamos o atributo com nosso valor desejado.

Graças a isso, finalmente podemos definir nossas variáveis CSS para cada tema (estarei usando as cores de um tema chamado Catppuccin):

html[theme="light"] {
  --base: #eff1f5;
  --foreground: #dce0e8;
  --text: #4c4f69;
  --text-accent: #8839ef;
}
html[theme="dark"] {
  --base: #303446;
  --foreground: #232634;
  --text: #c6d0f5;
  --text-accent: #ca9ee6;
}

Por enquanto nossa página estará sempre no modo claro, visto que definimos o atributo theme para sempre usar o modo claro sem opção de mudá-lo.

Com nossas cores definidas, vamos melhorar um pouco nossa página! Deixaremos nossa Card mais destacada, aplicamos as cores aos textos e colocaremos nosso botão na direita com posicionamento absoluto:

body {
  background: var(--base);
}

.theme-toggle {
  font-size: 2rem;
  padding: 0.5rem;
  position: absolute;
  right: 2%;
  background: none;
  border: none;
  cursor: pointer;
}

.base-text {
  color: var(--text);
}

.title-text {
  font-size: 1.5rem;
  color: var(--text-accent);
}

.card {
  background: var(--foreground);
  width: fit-content;
  padding: 1.5rem;
  border-radius: .5rem;
}

Ufa, agora finalmente podemos começar a implementar o funcionamento do nosso botão!

Implementação do Funcionamento do Botão

Primeiramente, vamos definir uma variável booleana não constante para guardar o estado atual do nosso tema. Além disso, vamos também usar document.querySelector() para termos acesso ao nosso botão pelo JavaScript:

let darkModeEstaAtivo = false;

const botao = document.querySelector(".theme-toggle");

Agora, implementaremos um procedimento para fazer a troca do tema sempre que necessário. Para isso, ele precisa mudar para o modo escuro se estivermos no modo claro e mudar para o modo claro se estivermos no escuro.

Faremos isso invertendo o valor atual do booleano que criamos e depois o atribuíremos ao nosso atributo “theme”. Além disso, trocaremos o ícone do sol para uma lua e vice-versa se necessário:

// procedimento de troca de tema
const trocaTema = () => {
  darkModeEstaAtivo = !darkModeEstaAtivo;
 
  document.firstElementChild.setAttribute("theme", darkModeEstaAtivo ? "dark" : "light");
  botao.textContent = darkModeEstaAtivo ? "🌚" : "☀️";
}

Agora que temos o procedimento para realizar a troca do tema, podemos criar um Event Listener para executá-lo sempre que o usuário clicar no botão:

botao.addEventListener("click", trocaTema);

Finalmente podemos trocar o tema quando quisermos!

Refletindo as preferências do usuário

O único que falta agora é verificar as preferências do usuário e guardar o modo preferido dele para a próxima seção. Para fazer esse último, precisamos adicionar a seguinte linha de código no final do nosso procedimento trocaTema:

localStorage.theme = darkModeEstaAtivo ? "dark" : "light";

Essa linha de código armazena no navegador uma variável “theme” com o valor “dark” ou “light” dependendo do tema atual. Quando o usuário acessar nossa página novamente, poderemos recuperar esse valor.

Agora criaremos um procedimento chamado “verificaPreferencia”, que irá fazer a recuperação da variável “theme” do armazenamento local do navegador.

Caso o usuário estiver acessando a página pela primeira vez, ele também irá verificar se o método window.matchMedia é acessível e, caso seja, irá olhar as preferências do navegador do usuário para ver se ele prefere o modo escuro.

function verificaPreferencia() {
  const theme = localStorage.getItem("theme");
  if(theme !== null) {
	if(theme === "dark")
  	trocaTema();
    
	return;
  }
 
  if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
	trocaTema();
	return;
  }
}

Código final

Com isso, implementamos um modo escuro funcional e que verifica as preferências do usuário! O código final pode ser visto e executado abaixo:

See the Pen Modo escuro simples e efetivo by Luksb10 (@Luksb10) on CodePen.