Vanilla JS : créer des éléments aux couleurs aléatoires

Créer des éléments HTML en JavaScript natif reste l’un des meilleurs exercices pour comprendre le DOM. Pas besoin de React, Vue ou jQuery pour ajouter des blocs, leur donner du contenu, puis leur appliquer des couleurs aléatoires.

Dans cet exemple, nous allons créer des cartes en Vanilla JS, générer une couleur de fond aléatoire, choisir automatiquement une couleur de texte lisible, puis injecter les éléments dans la page proprement.

L’objectif : produire un code simple, moderne, performant et accessible.

Conception du script simple

J’inclus ici un bouton qui permet de rafraîchir aléatoirement les couleurs de notre bloc:

  • Color 1
  • Color 2
  • Color 3
  • Color 4
  • Color 5
  • Color 6

HTML

Pour la partie HTML, on part sur quelque chose de très simple: une liste à puces tout à fait standard mais vous pouvez bien sûr choisir d’utiliser d’autres types d’éléments:

<ul id="random-colors">
<li>Color 1</li>
<li>Color 2</li>
<li>Color 3</li>
<li>Color 4</li>
<li>Color 5</li>
<li>Color 6</li>
</ul>Langage du code : HTML, XML (xml)

CSS

On affiche une grille CSS de 3 colonnes pour les éléments de notre liste:

* {
  margin: 0;
  padding: 0;
  font-family: Arial, sans-serif;
}
ul#random-colors {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
ul#random-colors li {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed deeppink;
  flex-direction: column;
  height: 100px;
  padding: 0;
  margin: 0;
  list-style-type: none;
}Langage du code : CSS (css)

Vanilla JS

Et voici le coeur du script, la fonction qui choisit un nombre aléatoire pour en dériver une couleur:

const elements = document.querySelectorAll("ul#random-colors li");
[...elements].forEach((element) => {
  element.style.backgroundColor = getRandomColor();
});

function getRandomColor() {
  var color = `#${crypto.getRandomValues(new Uint32Array(1))[0].toString(16).padStart(8, 0).slice(-6)}`
  return color;
}Langage du code : JavaScript (javascript)

Fonctionnement du script

On commence par stocker dans la constante elements tous les éléments de notre liste (qui possède l’identifiant random-colors ).

Ensuite, nous passons la liste de chaque élément en revue avec une boucle forEach et on assigne à chacun une couleur de fond grâce à notre fonction getRandomColor().

La fonction getRandomColor() utilise les fonctions de chiffrement de JavaScript pour obtenir des valeurs avec davantage d’entropie que Math.random().

La méthodeCrypto.getRandomValues() nous donne de solides valeurs aléatoires (cryptograpiquement parlant).

Le tableau Uint32Array nous donne un entier de 32 bits. Nous le transformons avec toString(16) pour obtenir une valeur hexadécimale.

Ensuite, padStart(8, 0) nous permet d’ajouter autant de 0 que nécessaire pour obtenir un entier de 8 caractères et slice(-6) nous permet de garder uniquement les 6 derniers caractères qui formeront notre code couleur.

Au final, nous obtenons une couleur unique pour chaque élément de notre liste.

Vanilla JS : pourquoi créer les éléments sans framework ?

Vanilla JS désigne simplement JavaScript sans bibliothèque externe. On utilise directement les API du navigateur : document.createElement(), classList, textContent, dataset, append() et les événements natifs.

Cette approche convient très bien pour :

  • ajouter quelques éléments dynamiques dans une page ;
  • créer un petit composant interactif ;
  • manipuler le DOM sans dépendance ;
  • comprendre ce que font les frameworks sous le capot ;
  • éviter de charger une bibliothèque pour trois cartes colorées.

Pour un gros état applicatif, un framework peut se justifier. Pour créer des éléments aux couleurs aléatoires, le navigateur sait déjà très bien faire.

Script plus complexe : le HTML de départ

On commence avec une structure minimale : un bouton pour générer les cartes et un conteneur qui recevra les éléments créés.

<section class="random-colours-demo" aria-labelledby="random-colours-title">
	<h2 id="random-colours-title">Couleurs aléatoires</h2>

	<button class="random-colours-demo__button" type="button" data-generate-colours>
		Générer des cartes
	</button>

	<div class="random-colours-demo__grid" data-colour-grid aria-live="polite"></div>
</section>Langage du code : HTML, XML (xml)

Les attributs data-* servent uniquement de crochets JavaScript. C’est plus propre que de cibler une classe CSS utilisée aussi pour le style.

Le CSS pour afficher les cartes

Voici un style simple, responsive et lisible. Les couleurs seront injectées par JavaScript avec des propriétés personnalisées CSS.

.random-colours-demo {
	display: grid;
	gap: 1rem;
}

.random-colours-demo__button {
	width: fit-content;
	cursor: pointer;
}

.random-colours-demo__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
	gap: 1rem;
}

.random-colour-card {
	display: grid;
	gap: 0.35rem;
	min-height: 8rem;
	padding: 1rem;
	border-radius: 0.75rem;
	background: var(--card-background);
	color: var(--card-colour);
	box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}

.random-colour-card__title {
	margin: 0;
	font-size: 1rem;
}

.random-colour-card__value {
	font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
	font-size: 0.925rem;
}Langage du code : CSS (css)

Le JavaScript définira --card-background et --card-colour sur chaque carte. Cela garde le style lisible et évite d’éparpiller trop de CSS inline.

Générer une couleur aléatoire en JavaScript

La méthode classique utilise souvent Math.random(). Pour un simple effet visuel, cela fonctionne. Mais on peut faire mieux avec crypto.getRandomValues(), disponible dans les navigateurs modernes.

function getRandomInteger(maxExclusive) {
	const randomValues = new Uint32Array(1);
	const maxValidValue = Math.floor(0x100000000 / maxExclusive) * maxExclusive;

	do {
		window.crypto.getRandomValues(randomValues);
	} while (randomValues[0] >= maxValidValue);

	return randomValues[0] % maxExclusive;
}

function getRandomColour() {
	const red = getRandomInteger(256);
	const green = getRandomInteger(256);
	const blue = getRandomInteger(256);

	return {
		red,
		green,
		blue,
		hex: rgbToHex(red, green, blue),
	};
}

function rgbToHex(red, green, blue) {
	return `#${[red, green, blue]
		.map((channel) => channel.toString(16).padStart(2, '0'))
		.join('')}`;
}Langage du code : JavaScript (javascript)

Le petit détail important : la fonction getRandomInteger() évite un biais modulo. Pour une démo de couleurs, ce n’est pas vital. Mais autant écrire une fonction propre une fois, puis la réutiliser.

Choisir automatiquement une couleur de texte lisible

Si on applique une couleur aléatoire au fond, il faut choisir une couleur de texte qui reste lisible. Le plus simple consiste à calculer la luminance relative, puis à choisir entre noir et blanc.

function getRelativeLuminance(red, green, blue) {
	const channels = [red, green, blue].map((channel) => {
		const srgb = channel / 255;

		if (srgb <= 0.03928) {
			return srgb / 12.92;
		}

		return Math.pow((srgb + 0.055) / 1.055, 2.4);
	});

	return (0.2126 * channels[0]) + (0.7152 * channels[1]) + (0.0722 * channels[2]);
}

function getReadableTextColour(red, green, blue) {
	const luminance = getRelativeLuminance(red, green, blue);

	return luminance > 0.45 ? '#111111' : '#ffffff';
}Langage du code : JavaScript (javascript)

Cette approche évite les cartes jaune clair avec texte blanc, ou violet foncé avec texte noir. Bref, elle évite le design façon test ophtalmologique.

Créer un élément avec document.createElement()

La méthode document.createElement() crée un élément HTML. Ensuite, on peut ajouter des classes, du texte, des attributs et des styles.

function createColourCard(index) {
	const colour = getRandomColour();
	const textColour = getReadableTextColour(colour.red, colour.green, colour.blue);

	const card = document.createElement('article');
	const title = document.createElement('h3');
	const value = document.createElement('p');

	card.className = 'random-colour-card';
	card.style.setProperty('--card-background', colour.hex);
	card.style.setProperty('--card-colour', textColour);

	title.className = 'random-colour-card__title';
	title.textContent = `Carte ${index}`;

	value.className = 'random-colour-card__value';
	value.textContent = colour.hex.toUpperCase();

	card.append(title, value);

	return card;
}Langage du code : JavaScript (javascript)

On utilise textContent, pas innerHTML. Ici, nous n’avons pas besoin d’injecter du HTML. C’est plus simple, plus sûr et plus rapide à relire.

Insérer plusieurs éléments avec DocumentFragment

Quand on crée plusieurs éléments, il vaut mieux éviter d’écrire dans le DOM à chaque tour de boucle. On prépare les éléments dans un DocumentFragment, puis on l’insère en une seule fois.

function renderColourCards(grid, amount) {
	const fragment = document.createDocumentFragment();

	grid.replaceChildren();

	for (let index = 1; index <= amount; index += 1) {
		fragment.append(createColourCard(index));
	}

	grid.append(fragment);
}Langage du code : JavaScript (javascript)

replaceChildren() vide le conteneur avant d’ajouter les nouvelles cartes. C’est plus clair que innerHTML = '', et cela évite de mélanger génération DOM et injection HTML.

Le JavaScript complet

Voici la version complète. Elle attend que le DOM soit prêt, cible le bouton et génère huit cartes colorées à chaque clic.

(() => {
	'use strict';

	function ready(callback) {
		if (document.readyState === 'loading') {
			document.addEventListener('DOMContentLoaded', callback);
			return;
		}

		callback();
	}

	function getRandomInteger(maxExclusive) {
		const randomValues = new Uint32Array(1);
		const maxValidValue = Math.floor(0x100000000 / maxExclusive) * maxExclusive;

		do {
			window.crypto.getRandomValues(randomValues);
		} while (randomValues[0] >= maxValidValue);

		return randomValues[0] % maxExclusive;
	}

	function rgbToHex(red, green, blue) {
		return `#${[red, green, blue]
			.map((channel) => channel.toString(16).padStart(2, '0'))
			.join('')}`;
	}

	function getRandomColour() {
		const red = getRandomInteger(256);
		const green = getRandomInteger(256);
		const blue = getRandomInteger(256);

		return {
			red,
			green,
			blue,
			hex: rgbToHex(red, green, blue),
		};
	}

	function getRelativeLuminance(red, green, blue) {
		const channels = [red, green, blue].map((channel) => {
			const srgb = channel / 255;

			if (srgb <= 0.03928) {
				return srgb / 12.92;
			}

			return Math.pow((srgb + 0.055) / 1.055, 2.4);
		});

		return (0.2126 * channels[0]) + (0.7152 * channels[1]) + (0.0722 * channels[2]);
	}

	function getReadableTextColour(red, green, blue) {
		const luminance = getRelativeLuminance(red, green, blue);

		return luminance > 0.45 ? '#111111' : '#ffffff';
	}

	function createColourCard(index) {
		const colour = getRandomColour();
		const textColour = getReadableTextColour(colour.red, colour.green, colour.blue);

		const card = document.createElement('article');
		const title = document.createElement('h3');
		const value = document.createElement('p');

		card.className = 'random-colour-card';
		card.style.setProperty('--card-background', colour.hex);
		card.style.setProperty('--card-colour', textColour);

		title.className = 'random-colour-card__title';
		title.textContent = `Carte ${index}`;

		value.className = 'random-colour-card__value';
		value.textContent = colour.hex.toUpperCase();

		card.append(title, value);

		return card;
	}

	function renderColourCards(grid, amount) {
		const fragment = document.createDocumentFragment();

		grid.replaceChildren();

		for (let index = 1; index <= amount; index += 1) {
			fragment.append(createColourCard(index));
		}

		grid.append(fragment);
	}

	function initRandomColoursDemo() {
		const button = document.querySelector('[data-generate-colours]');
		const grid = document.querySelector('[data-colour-grid]');

		if (!button || !grid || !window.crypto || !window.crypto.getRandomValues) {
			return;
		}

		button.addEventListener('click', () => {
			renderColourCards(grid, 8);
		});

		renderColourCards(grid, 8);
	}

	ready(initRandomColoursDemo);
})();Langage du code : JavaScript (javascript)

Ce code reste volontairement lisible. Il découpe chaque responsabilité : génération aléatoire, conversion couleur, contraste, création de carte, rendu et initialisation.

Version compatible avec les navigateurs plus anciens

Si vous voulez éviter les fonctions fléchées, les template literals et quelques syntaxes modernes, voici une version plus compatible. Elle reste utile si votre site reçoit beaucoup de vieux navigateurs intégrés, webviews ou environnements un peu fossiles.

(function () {
	'use strict';

	function ready(callback) {
		if (document.readyState === 'loading') {
			document.addEventListener('DOMContentLoaded', callback);
			return;
		}

		callback();
	}

	function getRandomInteger(maxExclusive) {
		var randomValues = new Uint32Array(1);
		var maxValidValue = Math.floor(4294967296 / maxExclusive) * maxExclusive;

		do {
			window.crypto.getRandomValues(randomValues);
		} while (randomValues[0] >= maxValidValue);

		return randomValues[0] % maxExclusive;
	}

	function channelToHex(channel) {
		var hex = channel.toString(16);

		return hex.length === 1 ? '0' + hex : hex;
	}

	function rgbToHex(red, green, blue) {
		return '#' + channelToHex(red) + channelToHex(green) + channelToHex(blue);
	}

	function getRandomColour() {
		var red = getRandomInteger(256);
		var green = getRandomInteger(256);
		var blue = getRandomInteger(256);

		return {
			red: red,
			green: green,
			blue: blue,
			hex: rgbToHex(red, green, blue)
		};
	}

	function getLinearChannel(channel) {
		var srgb = channel / 255;

		if (srgb <= 0.03928) {
			return srgb / 12.92;
		}

		return Math.pow((srgb + 0.055) / 1.055, 2.4);
	}

	function getRelativeLuminance(red, green, blue) {
		return (0.2126 * getLinearChannel(red)) +
			(0.7152 * getLinearChannel(green)) +
			(0.0722 * getLinearChannel(blue));
	}

	function getReadableTextColour(red, green, blue) {
		return getRelativeLuminance(red, green, blue) > 0.45 ? '#111111' : '#ffffff';
	}

	function createColourCard(index) {
		var colour = getRandomColour();
		var textColour = getReadableTextColour(colour.red, colour.green, colour.blue);
		var card = document.createElement('article');
		var title = document.createElement('h3');
		var value = document.createElement('p');

		card.className = 'random-colour-card';
		card.style.setProperty('--card-background', colour.hex);
		card.style.setProperty('--card-colour', textColour);

		title.className = 'random-colour-card__title';
		title.textContent = 'Carte ' + index;

		value.className = 'random-colour-card__value';
		value.textContent = colour.hex.toUpperCase();

		card.appendChild(title);
		card.appendChild(value);

		return card;
	}

	function renderColourCards(grid, amount) {
		var fragment = document.createDocumentFragment();
		var index;

		while (grid.firstChild) {
			grid.removeChild(grid.firstChild);
		}

		for (index = 1; index <= amount; index += 1) {
			fragment.appendChild(createColourCard(index));
		}

		grid.appendChild(fragment);
	}

	function initRandomColoursDemo() {
		var button = document.querySelector('[data-generate-colours]');
		var grid = document.querySelector('[data-colour-grid]');

		if (!button || !grid || !window.crypto || !window.crypto.getRandomValues) {
			return;
		}

		button.addEventListener('click', function () {
			renderColourCards(grid, 8);
		});

		renderColourCards(grid, 8);
	}

	ready(initRandomColoursDemo);
}());Langage du code : JavaScript (javascript)

Cette version utilise appendChild() au lieu de append(), et évite les syntaxes récentes. Elle est moins élégante, mais très robuste dans un contexte WordPress où des optimiseurs peuvent parfois malmener le JavaScript moderne.

Pourquoi éviter innerHTML ici ?

On pourrait générer chaque carte avec une chaîne HTML et l’injecter avec innerHTML. Mais ce n’est pas nécessaire ici.

Avec createElement(), on gagne plusieurs avantages :

  • on crée de vrais nœuds DOM ;
  • on évite de parser une chaîne HTML ;
  • on réduit les risques d’injection si les données deviennent dynamiques ;
  • on garde un code plus explicite ;
  • on utilise textContent pour le texte.

Pour une démo simple, les deux approches peuvent marcher. Pour un code réutilisable, la création DOM explicite est plus saine.

Math.random() ou crypto.getRandomValues() ?

Math.random() suffit pour beaucoup d’effets visuels. Mais crypto.getRandomValues() fournit des valeurs aléatoires plus fortes et évite certains biais si on l’utilise proprement.

Pour des couleurs aléatoires décoratives, ce n’est pas une question de sécurité critique. Mais utiliser crypto.getRandomValues() donne un exemple plus moderne et plus robuste.

Si vous créez un générateur de mot de passe, de token ou de clé sensible, ne choisissez pas Math.random(). Pour des confettis CSS, pas de panique. Pour un secret, pas de bricolage.

Ajouter un nombre configurable de cartes

On peut améliorer l’exemple avec un champ numérique. L’utilisateur choisit combien de cartes générer.

<section class="random-colours-demo" aria-labelledby="random-colours-title">
	<h2 id="random-colours-title">Couleurs aléatoires</h2>

	<label for="colour-card-count">Nombre de cartes</label>
	<input id="colour-card-count" type="number" min="1" max="48" value="8" data-colour-count>

	<button class="random-colours-demo__button" type="button" data-generate-colours>
		Générer
	</button>

	<div class="random-colours-demo__grid" data-colour-grid aria-live="polite"></div>
</section>Langage du code : JavaScript (javascript)

Puis, dans l’initialisation :

function initRandomColoursDemo() {
	const button = document.querySelector('[data-generate-colours]');
	const grid = document.querySelector('[data-colour-grid]');
	const countInput = document.querySelector('[data-colour-count]');

	if (!button || !grid || !countInput || !window.crypto || !window.crypto.getRandomValues) {
		return;
	}

	button.addEventListener('click', () => {
		const requestedAmount = Number.parseInt(countInput.value, 10);
		const safeAmount = Math.min(Math.max(requestedAmount || 8, 1), 48);

		countInput.value = String(safeAmount);
		renderColourCards(grid, safeAmount);
	});

	renderColourCards(grid, 8);
}Langage du code : JavaScript (javascript)

On limite volontairement le nombre entre 1 et 48. Une démo qui génère 30 000 éléments parce qu’un visiteur tape trop vite, c’est amusant surtout pour le ventilateur.

Copier la couleur au clic

On peut rendre chaque carte utile en copiant le code couleur au clic. Ajoutez un bouton dans la carte plutôt qu’un simple clic sur tout le bloc. C’est plus accessible.

function createColourCard(index) {
	const colour = getRandomColour();
	const textColour = getReadableTextColour(colour.red, colour.green, colour.blue);

	const card = document.createElement('article');
	const title = document.createElement('h3');
	const value = document.createElement('p');
	const copyButton = document.createElement('button');

	card.className = 'random-colour-card';
	card.style.setProperty('--card-background', colour.hex);
	card.style.setProperty('--card-colour', textColour);

	title.className = 'random-colour-card__title';
	title.textContent = `Carte ${index}`;

	value.className = 'random-colour-card__value';
	value.textContent = colour.hex.toUpperCase();

	copyButton.className = 'random-colour-card__copy';
	copyButton.type = 'button';
	copyButton.textContent = 'Copier';
	copyButton.addEventListener('click', async () => {
		await navigator.clipboard.writeText(colour.hex.toUpperCase());
		copyButton.textContent = 'Copié';

		window.setTimeout(() => {
			copyButton.textContent = 'Copier';
		}, 1500);
	});

	card.append(title, value, copyButton);

	return card;
}Langage du code : JavaScript (javascript)

Pour que le bouton reste lisible sur chaque fond, on peut lui donner une couleur neutre indépendante de la carte.

.random-colour-card__copy {
	width: fit-content;
	padding: 0.4rem 0.65rem;
	border: 0;
	border-radius: 0.4rem;
	background: rgba(255, 255, 255, 0.9);
	color: #111111;
	cursor: pointer;
}Langage du code : CSS (css)

Accessibilité : ne jamais compter uniquement sur la couleur

Les couleurs aléatoires sont utiles pour distinguer visuellement des blocs. Mais elles ne doivent pas être la seule information. Ajoutez toujours un texte, un libellé, une valeur ou un état compréhensible sans couleur.

Dans notre exemple, chaque carte affiche son code hexadécimal. C’est mieux qu’un bloc purement coloré, car l’information reste exploitable pour tout le monde.

Autres bons réflexes :

  • garder un contraste suffisant entre texte et fond ;
  • éviter les textes posés sur des couleurs très proches ;
  • ne pas utiliser la couleur comme seul indicateur d’état ;
  • prévoir un focus clavier visible sur les boutons ;
  • annoncer les changements importants avec aria-live si nécessaire.

Performance : éviter les insertions DOM répétées

Manipuler le DOM coûte plus cher que manipuler des objets en mémoire. Pour huit cartes, ce n’est pas dramatique. Pour des centaines d’éléments, cela compte.

Bonnes pratiques simples :

  • préparer les éléments dans un DocumentFragment ;
  • insérer le fragment en une seule fois ;
  • éviter les lectures/écritures de layout dans une boucle ;
  • limiter le nombre d’éléments générés ;
  • ne pas recréer tout le DOM si une simple mise à jour suffit.

Ici, DocumentFragment suffit largement. Pas besoin d’un moteur de rendu complet pour colorier quelques cartes. On garde le bulldozer pour les vraies montagnes.

Version WordPress : shortcode propre

Dans WordPress, évitez de coller du JavaScript complexe directement dans Gutenberg. Pour un site propre, créez plutôt un shortcode via Code Snippets ou un petit plugin dédié.

Voici un exemple de shortcode [sky_random_colours]. Il charge CSS et JS uniquement si le shortcode est présent dans l’article.

<?php
/**
 * SkyMinds random colours shortcode.
 *
 * Adds the [sky_random_colours] shortcode.
 *
 * @package SkyMinds
 */

declare(strict_types=1);

add_shortcode('sky_random_colours', 'sky_random_colours_shortcode');
add_action('wp_enqueue_scripts', 'sky_random_colours_enqueue_assets');

/**
 * Render the random colours demo.
 *
 * @return string Shortcode markup.
 */
function sky_random_colours_shortcode(): string {
	ob_start();
	?>
	<section class="sky-random-colours" aria-labelledby="sky-random-colours-title">
		<h2 id="sky-random-colours-title"><?php echo esc_html__('Couleurs aléatoires', 'skyminds'); ?></h2>

		<label class="sky-random-colours__label" for="sky-random-colours-count">
			<?php echo esc_html__('Nombre de cartes', 'skyminds'); ?>
		</label>

		<input
			id="sky-random-colours-count"
			class="sky-random-colours__input"
			type="number"
			min="1"
			max="48"
			value="8"
			inputmode="numeric"
			data-sky-random-colours-count
		>

		<button class="sky-random-colours__button" type="button" data-sky-random-colours-generate>
			<?php echo esc_html__('Générer', 'skyminds'); ?>
		</button>

		<div class="sky-random-colours__grid" data-sky-random-colours-grid aria-live="polite"></div>
	</section>
	<?php

	return (string) ob_get_clean();
}

/**
 * Enqueue shortcode assets only when needed.
 *
 * @return void
 */
function sky_random_colours_enqueue_assets(): void {
	if (! is_singular()) {
		return;
	}

	global $post;

	if (! $post instanceof WP_Post || ! has_shortcode((string) $post->post_content, 'sky_random_colours')) {
		return;
	}

	wp_register_style('sky-random-colours', false, array(), '1.0.0');
	wp_enqueue_style('sky-random-colours');

	wp_add_inline_style(
		'sky-random-colours',
		'
		.sky-random-colours {
			display: grid;
			gap: 1rem;
		}

		.sky-random-colours__input {
			max-width: 8rem;
		}

		.sky-random-colours__button {
			width: fit-content;
			cursor: pointer;
		}

		.sky-random-colours__grid {
			display: grid;
			grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
			gap: 1rem;
		}

		.sky-random-colour-card {
			display: grid;
			gap: 0.35rem;
			min-height: 8rem;
			padding: 1rem;
			border-radius: 0.75rem;
			background: var(--card-background);
			color: var(--card-colour);
			box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
		}

		.sky-random-colour-card__title {
			margin: 0;
			font-size: 1rem;
		}

		.sky-random-colour-card__value {
			font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
			font-size: 0.925rem;
		}
		'
	);

	wp_register_script('sky-random-colours', '', array(), '1.0.0', true);
	wp_enqueue_script('sky-random-colours');

	wp_add_inline_script(
		'sky-random-colours',
		<<<'JS'
(function () {
	'use strict';

	function ready(callback) {
		if (document.readyState === 'loading') {
			document.addEventListener('DOMContentLoaded', callback);
			return;
		}

		callback();
	}

	function getRandomInteger(maxExclusive) {
		var randomValues = new Uint32Array(1);
		var maxValidValue = Math.floor(4294967296 / maxExclusive) * maxExclusive;

		do {
			window.crypto.getRandomValues(randomValues);
		} while (randomValues[0] >= maxValidValue);

		return randomValues[0] % maxExclusive;
	}

	function channelToHex(channel) {
		var hex = channel.toString(16);

		return hex.length === 1 ? '0' + hex : hex;
	}

	function rgbToHex(red, green, blue) {
		return '#' + channelToHex(red) + channelToHex(green) + channelToHex(blue);
	}

	function getRandomColour() {
		var red = getRandomInteger(256);
		var green = getRandomInteger(256);
		var blue = getRandomInteger(256);

		return {
			red: red,
			green: green,
			blue: blue,
			hex: rgbToHex(red, green, blue)
		};
	}

	function getLinearChannel(channel) {
		var srgb = channel / 255;

		if (srgb <= 0.03928) {
			return srgb / 12.92;
		}

		return Math.pow((srgb + 0.055) / 1.055, 2.4);
	}

	function getRelativeLuminance(red, green, blue) {
		return (0.2126 * getLinearChannel(red)) +
			(0.7152 * getLinearChannel(green)) +
			(0.0722 * getLinearChannel(blue));
	}

	function getReadableTextColour(red, green, blue) {
		return getRelativeLuminance(red, green, blue) > 0.45 ? '#111111' : '#ffffff';
	}

	function createColourCard(index) {
		var colour = getRandomColour();
		var textColour = getReadableTextColour(colour.red, colour.green, colour.blue);
		var card = document.createElement('article');
		var title = document.createElement('h3');
		var value = document.createElement('p');

		card.className = 'sky-random-colour-card';
		card.style.setProperty('--card-background', colour.hex);
		card.style.setProperty('--card-colour', textColour);

		title.className = 'sky-random-colour-card__title';
		title.textContent = 'Carte ' + index;

		value.className = 'sky-random-colour-card__value';
		value.textContent = colour.hex.toUpperCase();

		card.appendChild(title);
		card.appendChild(value);

		return card;
	}

	function renderColourCards(grid, amount) {
		var fragment = document.createDocumentFragment();
		var index;

		while (grid.firstChild) {
			grid.removeChild(grid.firstChild);
		}

		for (index = 1; index <= amount; index += 1) {
			fragment.appendChild(createColourCard(index));
		}

		grid.appendChild(fragment);
	}

	function initDemo() {
		var button = document.querySelector('[data-sky-random-colours-generate]');
		var grid = document.querySelector('[data-sky-random-colours-grid]');
		var countInput = document.querySelector('[data-sky-random-colours-count]');

		if (!button || !grid || !countInput || !window.crypto || !window.crypto.getRandomValues) {
			return;
		}

		button.addEventListener('click', function () {
			var requestedAmount = parseInt(countInput.value, 10);
			var safeAmount = requestedAmount || 8;

			if (safeAmount < 1) {
				safeAmount = 1;
			}

			if (safeAmount > 48) {
				safeAmount = 48;
			}

			countInput.value = String(safeAmount);
			renderColourCards(grid, safeAmount);
		});

		renderColourCards(grid, 8);
	}

	ready(initDemo);
}());
JS
	);
}Langage du code : HTML, XML (xml)

Dans Gutenberg, vous insérez ensuite simplement :

[sky_random_colours]Langage du code : JSON / JSON avec commentaires (json)

Cette version est plus propre pour WordPress : le contenu reste léger, et les assets ne sont chargés que si le shortcode apparaît dans l’article.

Améliorations possibles

À partir de cette base, vous pouvez facilement ajouter :

  • un bouton pour copier chaque couleur ;
  • un export JSON des couleurs générées ;
  • un mode HSL au lieu de RGB ;
  • des palettes pastel ;
  • une contrainte de contraste plus stricte ;
  • une grille animée ;
  • une sauvegarde des couleurs dans localStorage.

Le meilleur exercice suivant consiste à générer non pas des couleurs totalement aléatoires, mais une palette harmonieuse : même teinte, saturation contrôlée, luminosité variable. C’est déjà un petit pas vers un générateur de thème.

Erreurs fréquentes

Voici les pièges classiques quand on crée des éléments colorés en JavaScript :

  • utiliser innerHTML pour injecter du texte simple ;
  • oublier le contraste du texte ;
  • écrire dans le DOM à chaque micro-opération ;
  • ne pas limiter le nombre d’éléments générés ;
  • mélanger classes CSS et sélecteurs JavaScript sans convention ;
  • utiliser des couleurs aléatoires comme seule information ;
  • oublier l’état clavier et le focus des boutons.

La génération aléatoire attire vite les effets gadgets. Gardez une règle simple : si l’élément contient du texte, il doit rester lisible. Toujours.

Méthode recommandée aujourd’hui

Pour créer des éléments aux couleurs aléatoires en Vanilla JS, je recommande cette séquence :

  1. préparer un conteneur HTML avec des attributs data-* ;
  2. générer les couleurs avec une fonction dédiée ;
  3. calculer une couleur de texte lisible ;
  4. créer les éléments avec document.createElement() ;
  5. ajouter le texte avec textContent ;
  6. insérer les cartes via un DocumentFragment ;
  7. limiter le nombre d’éléments générés ;
  8. éviter de compter uniquement sur la couleur ;
  9. tester au clavier et sur mobile ;
  10. dans WordPress, encapsuler la démo dans un shortcode propre.

Cette méthode reste simple, mais elle couvre les bases importantes : DOM propre, hasard correct, lisibilité, accessibilité et performance.

À retenir

Créer des éléments aux couleurs aléatoires en Vanilla JS se fait très simplement avec document.createElement(), textContent, append() et quelques fonctions de génération de couleur.

La vraie amélioration consiste à ne pas s’arrêter au hasard. Il faut aussi gérer le contraste, éviter les injections HTML inutiles, insérer les éléments efficacement et garder une interface utilisable.

En clair : générer une couleur, c’est facile. Générer une couleur lisible dans un composant propre, c’est déjà du vrai JavaScript front-end.

FAQ : couleurs aléatoires en Vanilla JS

Comment créer un élément HTML en JavaScript natif ?

Utilisez document.createElement(), puis configurez l’élément avec className, textContent, setAttribute() ou style. Ajoutez-le ensuite au DOM avec append() ou appendChild().

Comment générer une couleur hexadécimale aléatoire ?

Générez trois valeurs entre 0 et 255 pour rouge, vert et bleu, puis convertissez chaque canal en hexadécimal avec toString(16) et padStart(2, '0').

Faut-il utiliser Math.random() ?

Pour une couleur décorative, Math.random() peut suffire. Pour un exemple plus robuste, utilisez crypto.getRandomValues(). Pour un mot de passe ou une valeur sensible, n’utilisez pas Math.random().

Comment rendre le texte lisible sur une couleur aléatoire ?

Calculez la luminance relative de la couleur de fond, puis choisissez une couleur de texte claire ou sombre. Pour un texte normal, visez un contraste suffisant avec le fond.

Pourquoi utiliser un DocumentFragment ?

Un DocumentFragment permet de préparer plusieurs éléments en mémoire, puis de les insérer dans la page en une seule opération. C’est plus propre et plus performant que d’insérer chaque élément directement dans une boucle.

Peut-on intégrer ce code dans WordPress ?

Oui. Le plus propre consiste à créer un shortcode ou un petit plugin, puis à charger le CSS et le JavaScript uniquement quand la démo est présente dans l’article.

Articles liés

Sources

Demandez à l'IA son opinion
Gravatar for Matt Biscay

Je suis Matt Biscay, développeur WordPress & WooCommerce certifié chez Codeable, administrateur système et enseignant.

J’aide les entreprises à créer, optimiser et fiabiliser leurs sites WordPress avec une approche technique propre : performance, sécurité, maintenance, développement sur mesure et résolution de problèmes complexes.

Sur Skyminds, je partage des tutoriels WordPress, WooCommerce, Linux et administration système, avec des solutions testées sur des cas réels et pensées pour durer.

Découvrez mes services WordPress et WooCommerce.

Opinions