Original article: SVG Toggle Button Tutorial – How to Handle Dark Mode with CSS and JavaScript
¿Cómo se puede detectar el modo oscuro en CSS y JavaScript? ¿Cómo puedes anularlo manualmente con un botón de alternancia? ¿Y cómo se puede crear un ícono de sol y luna con SVG?
En este tutorial, aprenderá cómo detectar el modo oscuro en CSS y JavaScript, y creará un botón de alternancia con SVG para anular el comportamiento predeterminado. Utilizará HTML, CSS y JavaScript sin formato, por lo que no necesita ningún requisito preliminar antes de comenzar.
También puedes ver este artículo como vídeo en YouTube.
Tabla de contenido
- Cómo manejar el modo oscuro con CSS
- Cómo codificar un icono de sol con SVG
- Cómo detectar el modo oscuro en JavaScript
- Cómo codificar un icono de luna con SVG
- Cómo alternar el modo oscuro con JavaScript
- Próximos pasos
Cómo manejar el modo oscuro con CSS
Supongamos que tiene un sitio web sencillo con algo de texto. De forma predeterminada, configura el color del texto en negro y el color de fondo en blanco. Implementar el modo oscuro para este sitio con CSS es muy sencillo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Dark Mode</title>
<link rel="stylesheet" href="index.css" />
<script src="index.js" defer></script>
</head>
<body>
<p>
How to detect dark mode in CSS and in JavaScript? How can we override it
manually with a toggle button? In this quick tutorial, we look into
detecting dark mode in CSS and JavaScript, and then we create a toggle
button with SVG to override the default behavior.
</p>
</body>
</html>
Todo lo que necesitas hacer es agregar una consulta de medios y establecer una condición. Con esta condición, configura las siguientes declaraciones CSS para que solo sean válidas si el esquema de color preferido es oscuro.
Dentro de esta consulta de medios, puede definir los colores para el modo oscuro. En este caso, inviertes los colores y estableces el color del texto en blanco y el color de fondo en negro:
body {
font-family: Montserrat;
margin: 50px;
max-width: 500px;
}
@media (prefers-color-scheme: dark) {
body {
background-color: black;
color: white;
}
}
Esto tomará la configuración de su sistema operativo o configuración del navegador. De forma predeterminada, proviene del sistema operativo, pero el navegador puede decidir anularlo. En Google Chrome, puede encontrar esta configuración en "Apariencia". De forma predeterminada, sigue la configuración del dispositivo.
Lo bueno de la solución CSS es que si cambia esta configuración mientras visita el sitio web, el estilo se actualizará automáticamente.
De esta manera, puede establecer un estilo personalizado para el elemento del cuerpo y también para cualquier otro elemento.
Sin embargo, en un caso no funciona. No puedes diseñar lo que hay dentro de un elemento HTML Canvas con CSS. Si creaste un juego completamente desde JavaScript usando Canvas API o Three.js, también debes configurar los colores para el modo oscuro en JavaScript.
En los próximos pasos, cubriremos esto y veremos cómo crear un botón de alternancia SVG para cambiar entre los modos claro y oscuro.
Cómo codificar un icono de sol con SVG
Antes de aprender a manejar el modo oscuro en JavaScript, hagamos un desvío rápido y veamos cómo codificar un botón de alternancia del modo oscuro con SVG. Detectar el modo oscuro es una cosa, pero debes permitir al usuario alternar manualmente entre los modos claro y oscuro.
Consulte mi tutorial anterior si necesita una introducción rápida a la codificación de iconos SVG . Contiene muchos ejemplos excelentes, desde niveles principiantes hasta avanzados. Y si eres nuevo en los SVG, no te preocupes. Estos son ejemplos muy simples.
Entonces, comencemos con el svg
elemento. Esto servirá como contenedor para todos los elementos de la imagen. Establezca su tamaño en 30 por 30:
Luego, agrega un círculo. Para un circle
elemento, debes establecer las coordenadas centrales del círculo y su radio. Las coordenadas centrales son 15 y el radio es 6. Luego, establece un color con la fill
propiedad:
<svg width="30" height="30">
<circle cx="15" cy="15" r="6" fill="currentColor" />
</svg>
Para establecer el color, puede utilizar la currentColor
propiedad que asume la color
configuración actual de CSS. Esto será útil más adelante cuando alterne los modos oscuro y claro. El icono cambiará de color automáticamente.
Luego, agrega los rayos del sol. Debe usar el line
elemento para esto, donde debe establecer las coordenadas inicial y final. También puede establecer el color del trazo con la stroke
propiedad stroke-width
para agregar grosor y la stroke-linecap
propiedad para redondear los extremos de las líneas:
<svg width="30" height="30">
<circle cx="15" cy="15" r="6" fill="currentColor" />
<line
id="ray"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
x1="15"
y1="1"
x2="15"
y2="4"
></line>
</svg>
Ahora, una vez que tengas un rayo, puedes reutilizar el mismo rayo para dibujar los demás.
Puedes darle a este rayo id
y reutilizarlo con el use
elemento. Para los elementos reutilizados, puede establecer una rotación. Establezca el ángulo de rotación y el centro de rotación. Quieres rotar los rayos alrededor del centro del sol, así que configúralo en 15,15
. Luego, incrementa la rotación en 45 grados para cada rayo:
<svg width="30" height="30">
<circle cx="15" cy="15" r="6" fill="currentColor" />
<line
id="ray"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
x1="15"
y1="1"
x2="15"
y2="4"
></line>
<use href="#ray" transform="rotate(45 15 15)" />
<use href="#ray" transform="rotate(90 15 15)" />
<use href="#ray" transform="rotate(135 15 15)" />
<use href="#ray" transform="rotate(180 15 15)" />
<use href="#ray" transform="rotate(225 15 15)" />
<use href="#ray" transform="rotate(270 15 15)" />
<use href="#ray" transform="rotate(315 15 15)" />
</svg>
Cómo detectar el modo oscuro en JavaScript
Antes de llegar al ícono de la luna, veamos cómo detectar el modo oscuro en JavaScript. Esto puede ser útil al crear un juego, como lo hicimos hace un par de semanas en el tutorial del juego Gorilas JavaScript .
En ese juego, estábamos dibujando en un elemento HTML Canvas con JavaScript. Configuramos todos los colores con JavaScript. Si queremos admitir el modo oscuro, podemos configurar los colores en función de una darkMode
variable. Pero ¿cómo detectamos si estamos en modo oscuro? ¿Cómo establecemos el valor de esta variable?
El siguiente código es un fragmento de ejemplo del tutorial del juego anterior. Aquí configuramos el color de relleno antes de dibujar un rectángulo en el lienzo.
Detectar el modo oscuro en JavaScript también es muy sencillo. Curiosamente, esta solución también depende de los selectores de consultas CSS que usaste antes.
Puedes crear un matchMedia
objeto con la misma condición que usamos en CSS. Este método puede comprobar si el documento coincide con una consulta de medios. Pasar prefers-color-scheme: dark
como argumento:
const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
let darkMode = darkModeMediaQuery.matches;
. . .
function drawBuildings() {
state.buildings.forEach((building) => {
ctx.fillStyle = darkMode ? "#254D7E" : "#947285";
ctx.fillRect(building.x, 0, building.width, building.height);
});
}
Luego, puede verificar la matches
propiedad de este objeto. Si es cierto, entonces estás en modo oscuro. Puede guardar esto en una variable y, luego, puede usar esta variable para decidir qué colores debe usar al pintar en el elemento del lienzo.
Esta variable, sin embargo, no se actualiza automáticamente cuando cambia entre el modo claro y el modo oscuro. Debe agregar un detector de eventos que detecte si la configuración cambia.
Aquí, definimos una función que verifica la matches
propiedad del objeto entrante para decidir si acaba de cambiar al modo brillante u oscuro:
const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
let darkMode = darkModeMediaQuery.matches;
darkModeMediaQuery.addEventListener("change", (e) => {
if (e.matches) {
darkMode = true;
} else {
darkMode = false;
}
});
. . .
function drawBuildings() {
state.buildings.forEach((building) => {
ctx.fillStyle = darkMode ? "#254D7E" : "#947285";
ctx.fillRect(building.x, 0, building.width, building.height);
});
}
Ahora, si configuras los colores según esta darkMode
variable, deberías ver que la apariencia del juego cambia una vez que cambias entre el modo claro y oscuro en la configuración del sistema operativo. Mira esta demostración para verlo en acción.
Cómo codificar un icono de luna con SVG
Antes de discutir la anulación de la configuración predeterminada del sistema operativo con un botón de alternancia, examinemos la otra mitad de nuestro ícono de alternancia: Dibujemos una luna.
Comience con un svg
elemento del mismo tamaño y defina una ruta dentro de él. Puede definir un path
elemento estableciendo su d
atributo. En este atributo, construyes una ruta a partir de una serie de comandos:
Comienza con el comando mover a para ir a la posición inicial. Este comando consta de la letra M
y la coordenada inicial:
Luego, usa un comando de arco para dibujar el arco exterior de la luna. Este comando puede dar un poco de miedo porque tiene varias propiedades. Veamos que tenemos:
Un comando siempre continúa el comando anterior, por lo que este arco dibujará el arco a partir de las coordenadas del comando de desplazamiento. Los comandos también terminan con las coordenadas del punto final.
Aquí estableces dónde termina el arco. El resto de las propiedades tratan sobre cómo dibujar un arco desde el punto inicial hasta el punto final:
Las dos primeras propiedades son el radio horizontal y vertical de nuestro arco. En nuestro caso, queremos tener el arco de un círculo, por lo que establecemos el mismo valor para ambos. Con el tercer argumento, puedes establecer una rotación. Cuando ambos radios son iguales, esta propiedad no hace diferencia. Puedes dejarlo en cero:
Luego, tenemos la propiedad de bandera de arco grande. Con esto, podrás decidir si ir por el camino largo o corto hasta nuestra coordenada final. Puedes ver que puedes llegar al punto final de múltiples maneras, incluso con los mismos radios.
Hay dos arcos: en el caso del primero, irás por el camino largo y en el caso del segundo, irás por el camino corto. Esta es una bandera, por lo que el valor aquí puede ser 0 o 1:
Finalmente, está la bandera de barrido. Básicamente, esto establece si debes dibujar el arco en el sentido de las agujas del reloj o en el sentido contrario a las agujas del reloj. Las dos opciones se reflejan entre sí. En el primer caso, lo configuras en cero; en el segundo, lo configuras en uno:
Ahora que tienes un arco, configuras el otro. Aquí, establece el punto final al principio. A las mismas coordenadas que utilizó para el comando de desplazamiento.
Luego puedes usar los mismos radios, pero tienes que cambiar la bandera de arco grande y la bandera de barrido para terminar con una luna:
<svg width="30" height="30">
<path
fill="currentColor"
d="
M 23, 5
A 12 12 0 1 0 23, 25
A 12 12 0 0 1 23, 5"
/>
</svg>
¿Cómo puedes usar estos dos íconos en un botón para alternar el modo claro y el modo oscuro en JavaScript?
Cómo alternar el modo oscuro con JavaScript
Si desea anular la configuración del sistema o del navegador para el modo oscuro con un cambio manual, ya no puede confiar en la consulta de medios CSS. Esto funciona para representar la interfaz de usuario según la configuración, pero no puede anularla desde JavaScript.
En su lugar, puede definir una dark-mode
clase y alternarla desde JavaScript.
En CSS, defina una clase que cambiará la misma configuración que hizo antes la consulta de medios. Luego, en JavaScript, puedes usar la misma lógica que tenías antes para obtener la configuración predeterminada y luego agregar o eliminar esta clase.
Puede configurar esta clase en la carga de nuestra página inicial y alternarla si hace clic en un botón:
body {
font-family: Montserrat;
margin: 50px;
max-width: 500px;
}
.dark-mode {
background-color: black;
color: white;
}
Ahora, ¿cómo se alterna esto con un botón? En su archivo HTML, agregue un elemento de botón con un controlador de eventos. Luego, mueva ambos SVG dentro de este elemento de botón y asígneles ID. Alternará la visibilidad de estos íconos desde JavaScript:
También puede desarmar la apariencia predeterminada del elemento del botón en CSS, excepto la propiedad del cursor. Deberías tener eso como puntero:
. . .
button {
all: unset;
cursor: pointer;
}
. . .
Ahora, implementemos el controlador de eventos en JavaScript. Primero necesitas acceder a los íconos SVG por ID:
const lightIcon = document.getElementById("light-icon");
const darkIcon = document.getElementById("dark-icon");
. . .
Luego, agregue la dark-mode
clase al body
elemento en caso de que esté en modo oscuro y oculte uno de los íconos SVG según la darkMode
variable. Detectas el modo oscuro como lo hiciste antes:
. . .
// Check if dark mode is preferred
const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
let darkMode = darkModeMediaQuery.matches;
// Set dark-mode class on body if darkMode is true and pick icon
if (darkMode) {
document.body.classList.add("dark-mode");
darkIcon.setAttribute("display", "none");
} else {
lightIcon.setAttribute("display", "none");
}
. . .
Y finalmente, podemos implementar la función que invierte la darkMode
propiedad. Esta función alterna la dark-mode
clase en el elemento del cuerpo y alterna los íconos SVG:
. . .
// Toggle dark mode on button click
function toggleDarkMode() {
// Toggle darkMode variable
darkMode = !darkMode;
// Toggle dark-mode class on body
document.body.classList.toggle("dark-mode");
// Toggle light and dark icons
if (darkMode) {
lightIcon.setAttribute("display", "block");
darkIcon.setAttribute("display", "none");
} else {
lightIcon.setAttribute("display", "none");
darkIcon.setAttribute("display", "block");
}
}
Ahora, esto funciona: de forma predeterminada, todavía tienes la configuración del sistema operativo o del navegador. Pero una vez que haga clic en este botón, lo anulará manualmente.
Próximos pasos
Con todo esto en su lugar, tiene una funcionalidad que toma la configuración del modo oscuro del navegador o del sistema operativo de forma predeterminada, y puede anularla con un atractivo botón de alternancia. En la versión de YouTube de este tutorial , también puede aprender cómo localStorage
guardar esta configuración para la próxima sesión.
Si desea obtener más información sobre los SVG, consulte SVG-tutorial.com , donde puede obtener más información sobre los SVG desde niveles principiantes hasta avanzados con muchos ejemplos excelentes.
Si desea utilizar este comportamiento en un juego, consulta el tutorial del juego Gorillas JavaScript , donde creamos el juego completo desde cero. Es un enorme tutorial de dos horas que cubre el dibujo en un elemento Canvas con JavaScript y toda la lógica del juego con JavaScript simple.