Como criar um tema escuro (darkmode) apenas com CSS

Dica rápida de CSS. Criando e selecionando tema escuro a partir da preferência do dispositivo do usuário com CSS puro.

Ilustração Darkmode com CSS Puro, logo do Roger Albino metade preto com fundo branco, e outra metade branco com fundo preto.

Eu sou suspeito para falar pois eu gosto muito de usar tema escuro nas minhas IDEs, editores de código, Terminal, Sistema Operacional e não seria diferente com sites, sistemas e aplicativos.

Vamos começar preparando o nosso HTML. Fiz um exemplo simples com um título e um SVG incorporado. Estou importando vários arquivos CSS somente para fins de exemplo, mas poderia ser apenas um arquivo.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Darkmode CSS</title>
<link rel="stylesheet" href="css/default-theme.css">
<link rel="stylesheet" href="css/light-mode.css">
<link rel="stylesheet" href="css/using-theme.css">
</head>
<body>
<main>
<h1>Darkmode only CSS</h1>
<svg viewBox="0 0 49 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="logo">
<title>roger_albino_FINAL_verde_SVG</title>
<g id="Welcome" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Mobile-Portrait" transform="translate(-20.000000, -25.000000)" fill="transparent" fill-rule="nonzero">
<g id="roger_albino_FINAL_verde_SVG" transform="translate(21.000000, 26.000000)">
<rect id="Rectangle" stroke="currentColor" x="11" y="3" width="7" height="7"></rect>
<path d="M29,10 C32.6586069,8.14949459 36.8927142,6.39120411 41,5.7155524 L40.9740592,0 C36.407526,0.198616776 31.9188151,2.11917007 29.0269015,4.08583082 L29,10 Z" id="Path" stroke="currentColor"></path>
<path d="M46.9624995,16.2689303 C46.9409338,15.3656851 46.8509206,14.4876803 46.7355912,13.7169471 C46.4993066,12.1358173 46.1711336,11 46.1711336,11 C46.2048885,12.0294471 46.1148753,12.9254808 45.9376619,13.7169471 C45.3760171,16.2301683 43.8917372,17.6292067 42.3193193,18.398137 C41.1744641,18.9579327 40.0005421,19.1832933 39.0938468,19.2716346 L39.0872834,19.2725361 L31.9706158,19.3185096 C27.7803145,19.3644832 26.2388387,18.8091947 25.0349123,15.6604567 L23.5,15.6604567 L21.9650877,15.6604567 C20.7611613,18.8091947 19.2196855,19.3644832 15.0293842,19.3185096 L7.91271664,19.2725361 L7.90615318,19.2716346 C6.99945786,19.1832933 5.82459826,18.9579327 4.68068068,18.398137 C3.10826284,17.6292067 1.62398291,16.2301683 1.06233814,13.7169471 C0.885124679,12.9254808 0.79604913,12.0285457 0.828866438,11 C0.828866438,11 0.501631001,12.1358173 0.264408751,13.7169471 C0.149079356,14.4885817 0.0590661706,15.3656851 0.0375005115,16.2689303 L0.0356252368,16.2653245 C0.0356252368,16.2653245 -0.0515750371,18.3584736 0.046876885,19.3933293 C0.046876885,19.3951322 0.046876885,19.3960337 0.0478145223,19.3978365 C0.0815694671,20.0198317 0.157518093,20.6382212 0.292537872,21.226863 C0.292537872,21.2277644 0.293475509,21.2286659 0.293475509,21.2295673 C1.11297056,23.7013221 2.95542795,25.2950721 5.62956969,25.8341346 C6.2399716,25.9576322 6.86443808,26 7.48890456,26 L8.4640474,26 L8.94318009,26 L17.4072325,26 C20.7771011,25.7674279 22.0307223,24.5703125 23.5,22.0697115 C24.9702154,24.5703125 26.2228989,25.7674279 29.5927675,26 L38.0568199,26 L38.5359526,26 L39.5110954,26 C40.1346243,26 40.7600284,25.9567308 41.3704303,25.8341346 C44.0436344,25.2950721 45.8860918,23.7013221 46.7065245,21.2295673 C46.7065245,21.2286659 46.7074621,21.2277644 46.7074621,21.226863 C46.8424819,20.6382212 46.9184305,20.0207332 46.9521855,19.3978365 C46.9521855,19.3960337 46.9521855,19.3951322 46.9531231,19.3933293 C47.051575,18.3584736 46.9643748,16.2653245 46.9643748,16.2653245 L46.9624995,16.2689303 Z" id="Path" stroke="currentColor"></path>
</g>
</g>
</g>
</svg>
</main>
</body>
</html>

Agora vamos criar algumas variáveis no CSS para o tema padrão, caso o usuário não tenha selecionado nem o tema claro e nem o escuro, ou se o device ou browser do usuário não suporte esse tipo de personalização. Aqui você pode decidir, se o padrão do seu site vai ser o tema claro ou o tema escuro, eu optei pelo tema escuro.

:root {
--text-color: #fff;
--bg-color: #000;
--logo-color: #00ff90;
}

Para identificar se o usuário optou pelo tema de cores clara ou escura, vamos utilizar uma media query com a condição prefers-color-scheme. Os valores que podemos usar são: light, dark ou no-preference. Sendo dark para o tema escuro, light para o tema claro, e no-preference caso o usuário não tenha selecionado um tema no sistema.

Como o meu tema padrão já é o escuro, vou fazer apenas um CSS para o tema claro como no exemplo.

@media (prefers-color-scheme: light) {
:root {
--text-color: #000;
--bg-color: #fff;
--logo-color: #000;
}
}

Agora que temos tanto o tema claro quanto o tema escuro criado, basta usarmos as variáveis no nosso CSS como no exemplo.

body {
color: var(--text-color);
background-color: var(--bg-color);
display: flex;
align-items: center;
justify-content: center;
}

.logo {
color: var(--logo-color);
fill: var(--logo-color);
width: 150px;
}

Resumindo, usamos o recurso de variáveis do css para definir cores para o nosso tema, usamos o recurso de media query para alterar os valores dessas variáveis conforme o esquema de cores selecionado pelo sistema do usuário, e assim conseguimos definir tema claro e escuro de uma forma simples e fácil.

Tenho aqui um repositório no meu github com o código completo do exemplo funcionando: https://github.com/rogeralbinoi/darkmode-css

E um link com o exemplo funcionando: https://rogeralbinoi.github.io/darkmode-css/

Obrigado, e bons estudos!