Mettez à jour l’état du composant lorsqu’un choix doit maintenir la cohérence des commandes, du texte et du comportement. Remplacez le CSS uniquement pour modifier la présentation. Ce guide s’appuie sur un aperçu local de tuiles dans Safari sur Mac pour montrer comment choisir et vérifier les deux approches.

La tâche du lecteur est précise : modifier une petite page Web que vous créez afin que ses commandes de forme restent synchronisées et que son style décoratif demeure facile à modifier. Ici, l’état du composant désigne un objet JavaScript géré par la fonction de mise à jour de la page elle-même. Aucun framework ni aucune fonctionnalité d’édition propre à un produit ne sont présupposés.

Quels changements relèvent de l’état du composant ?

Commencez par vous demander ce qui doit concorder après le changement. Si la sélection d’une tuile ronde doit mettre à jour une case à cocher, l’aperçu et une description écrite, attribuez à ce choix une source unique dans l’état. Dérivez ensuite ces trois résultats de cette source. Il s’agit d’une recommandation de mise en œuvre : elle explicite le lien entre un choix et les résultats affichés.

Une propriété personnalisée CSS telle que --tile-size a un autre rôle. Elle fournit une valeur aux déclarations qui la référencent avec var(). Les propriétés personnalisées participent à la cascade et sont normalement héritées ; leur comportement suit les règles CSS même lorsque JavaScript les définit. La spécification CSS Custom Properties définit ce contrat.

Utilisez ce guide de décision avant de modifier le code :

Changement demandé Source à privilégier Raison dans cet exemple
Le lecteur sélectionne une tuile ronde ou carrée État du composant La case à cocher, la description et la forme doivent concorder
Le lecteur choisit la taille d’une tuile État du composant, transmis au CSS Le curseur, la description et les dimensions partagent une même valeur
Chaque tuile doit avoir une couleur décorative différente Déclaration de feuille de style Aucune valeur sélectionnée ni aucun texte ne doit être mis à jour
L’aperçu a besoin de plus d’espace autour de lui Déclaration de feuille de style Cela modifie la disposition autour de la tuile
Une dimension temporaire est nécessaire pendant l’inspection Surcharge CSS locale C’est une expérience visuelle à supprimer ensuite

La distinction dépend de la tâche. Dans cet aperçu, la couleur relève du CSS, car il s’agit d’une décoration fixe. Si vous ajoutez plus tard un sélecteur de couleur et une description de la couleur choisie, traitez cette sélection comme un état et produisez son effet visuel à partir de cet état. Évitez de créer deux valeurs modifiables indépendamment pour un même choix.

Les commandes natives ont également leur propre état. Pour une case à cocher, lisez sa propriété actuelle checked. L’attribut HTML checked définit son état coché par défaut et ne suit pas les changements ultérieurs de l’utilisateur. Cette distinction est documentée dans la référence MDN sur la propriété des cases à cocher.

Créer un aperçu autonome sur votre Mac

Utilisez un éditeur de code en texte brut pour enregistrer le document complet ci-dessous sous le nom tile-preview.html, puis ouvrez-le dans Safari. Conservez l’extension .html. L’exemple contient son CSS et son JavaScript, utilise les polices système et dessine une tuile géométrique simple sans ressources externes.

La feuille de style se trouve dans l’en-tête du document. HTML définit l’élément style comme moyen d’intégrer du CSS et distingue les styles internes autonomes des feuilles de style faisant référence à des ressources supplémentaires. En gardant cet exemple autonome, les paramètres de style restent explicites. Consultez les sections de la norme HTML consacrées aux styles et aux scripts.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Tile preview</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      margin: 2rem;
      color: #222;
      background: #fff;
    }
    label { display: block; margin-block: 1rem; }
    .preview { padding: 24px; background: #eee; }
    .tile {
      width: 80px;
      height: 80px;
      border-radius: 0;
      width: var(--tile-size, 80px);
      height: var(--tile-size, 80px);
      border-radius: var(--tile-radius, 0);
      background-color: #547899;
    }
  </style>
</head>
<body>
  <h1>Tile preview</h1>
  <label>
    <input id="round" type="checkbox"> Round tile
  </label>
  <label>
    Tile size
    <input id="size" type="range" min="40" max="160"
           step="1" value="80">
  </label>
  <button id="reset" type="button">Reset choices</button>
  <p id="summary"></p>
  <div class="preview">
    <div id="tile" class="tile" aria-hidden="true"></div>
  </div>
  <script>
    const state = { rounded: false, size: 80 };
    const round = document.getElementById('round');
    const size = document.getElementById('size');
    const summary = document.getElementById('summary');
    const tile = document.getElementById('tile');
    const reset = document.getElementById('reset');

    function render() {
      round.checked = state.rounded;
      size.value = String(state.size);
      tile.style.setProperty('--tile-size', `${state.size}px`);
      tile.style.setProperty('--tile-radius', state.rounded ? '50%' : '0');
      summary.textContent = `Tile A: ${state.rounded ? 'round' : 'square'}, ${state.size}px.`;
    }

    function update(patch) {
      const next = { ...state, ...patch };
      if (typeof next.rounded !== 'boolean' ||
          !Number.isInteger(next.size) ||
          next.size < 40 || next.size > 160) {
        throw new RangeError('Use a boolean and a size from 40 to 160.');
      }
      Object.assign(state, next);
      render();
    }

    round.addEventListener('change', () => {
      update({ rounded: round.checked });
    });
    size.addEventListener('input', () => {
      update({ size: Number(size.value) });
    });
    reset.addEventListener('click', () => {
      update({ rounded: false, size: 80 });
    });
    render();
  </script>
</body>
</html>

L’interface de style utilisée ici est documentée : element.style.setProperty() écrit une déclaration en ligne, y compris une propriété personnalisée. Les noms de propriétés reprennent la notation CSS, comme --tile-size. Consultez la référence MDN de setProperty.

Essayez de sélectionner Round tile, de régler Tile size sur une autre valeur, puis de choisir Reset choices. Les deux premières actions doivent mettre à jour la forme et la description ; la réinitialisation doit rétablir un carré de 80 pixels. Dans ce programme, affecter une valeur à un champ de state ne déclenche pas à lui seul l’appel à render(). Faites passer les changements par update() afin que la validation et l’affichage soient effectués ensemble.

La logique de mise à jour et d’affichage a été vérifiée dans Node avec des commandes simulées et un objet de style simulé, pour les valeurs initiales, les valeurs modifiées, les tailles non valides et la réinitialisation. Ces vérifications ont réussi ; elles ne garantissent pas le rendu dans un navigateur. Utilisez les vérifications visuelles ci-dessus pour contrôler le fichier dans Safari.

Quand faut-il remplacer une déclaration CSS ?

Pour un changement décoratif durable, modifiez la feuille de style enregistrée. Par exemple, remplacez la valeur background-color de .tile par une autre couleur CSS, ou ajustez le remplissage de .preview. Dans ce programme, aucun de ces changements ne nécessite de nouveau champ d’état, car aucun ne représente un choix sélectionné.

Pour une expérience temporaire, activez l’inspecteur de Safari via Safari → Réglages… → Avancées → Afficher les fonctionnalités pour les développeurs web. Ouvrez Développement → Afficher l’inspecteur web, ou appuyez sur Option-Commande-I. Ces étapes pour Mac sont documentées dans le guide de l’inspecteur de WebKit.

Lorsque l’exemple est ouvert, l’extrait complet suivant, à saisir dans la console, modifie temporairement la couleur de la tuile et fournit une fonction qui supprime ensuite cette surcharge :

const previewTile = document.getElementById('tile');
if (!previewTile) throw new Error('Open tile-preview.html first.');
previewTile.style.setProperty('background-color', '#8069a6');
function restoreTileColor() {
  previewTile.style.removeProperty('background-color');
}
// Run restoreTileColor() when finished comparing colors.

La suppression de cette déclaration en ligne laisse la cascade restante déterminer à nouveau la couleur. Elle ne supprime pas la déclaration de couleur de la feuille de style. La méthode de suppression est définie dans la référence MDN de removeProperty. Pour conserver une couleur choisie après rechargement dans cet exemple, modifiez et enregistrez le code CSS source.

Évitez les surcharges temporaires pour les valeurs gérées par la fonction de rendu. Si vous modifiez manuellement --tile-size, la description indiquera toujours la valeur de l’état, et le prochain appel à render() remplacera votre expérience. Modifiez la taille avec la commande ou la fonction de mise à jour lorsque vous souhaitez que tout le composant concorde.

Pourquoi une surcharge peut-elle sembler sans effet ?

Diagnostiquez le cheminement de la valeur avant d’augmenter la spécificité du sélecteur. Une déclaration peut être valide, mais perdre dans la cascade, ou cibler une propriété personnalisée que la déclaration gagnante n’utilise plus.

  1. Vérifiez la cible. Confirmez que vous avez sélectionné l’élément qui affiche la forme.
  2. Vérifiez la valeur saisie. Dans l’exemple, la taille doit être un entier compris entre 40 et 160. Les mises à jour non valides provoquent une erreur avant de modifier l’état.
  3. Vérifiez l’utilisation. Les dimensions de la tuile utilisent var(--tile-size). Une déclaration directe width gagnante peut contourner cette valeur pour la largeur, tandis que la hauteur continue de l’utiliser.
  4. Vérifiez la priorité. Comparez les déclarations applicables, leur importance, leurs couches et leur spécificité.
  5. Vérifiez l’interaction suivante. Si le changement disparaît après avoir déplacé une commande, examinez ce que render() écrit.

Les déclarations en ligne normales ont priorité sur les règles normales des feuilles de style de l’auteur. Toutefois, l’importance, les animations et les transitions influent sur l’ordre général. Une déclaration ultérieure ne l’emporte pas automatiquement, et un sélecteur plus spécifique ne résout pas tous les conflits. Le guide MDN sur la cascade documente ces conditions.

Distinguez également les valeurs en ligne des valeurs résolues. element.style expose le style en ligne ; une valeur en ligne vide ne signifie donc pas que l’élément n’a aucun style. getComputedStyle() lit les valeurs résolues après l’application des feuilles de style actives. Consultez la référence MDN sur style et la référence sur getComputedStyle.

Exécutez cet extrait de diagnostic complet dans la console de la page d’exemple :

const inspectedTile = document.getElementById('tile');
if (!inspectedTile) throw new Error('Open tile-preview.html first.');
console.table({
  inlineSizeToken: inspectedTile.style.getPropertyValue('--tile-size'),
  inlineWidth: inspectedTile.style.getPropertyValue('width'),
  resolvedWidth: getComputedStyle(inspectedTile).width,
  resolvedHeight: getComputedStyle(inspectedTile).height
});

Juste après avoir ouvert l’exemple sans le modifier, les valeurs attendues sont un jeton de taille en ligne égal à 80px, une largeur en ligne vide et des dimensions résolues de 80px. Cela montre comment une propriété personnalisée en ligne peut alimenter une déclaration de feuille de style sans créer de déclaration width en ligne.

Quelles limites liées au navigateur et aux ressources faut-il prendre en compte ?

MDN indique que les propriétés personnalisées CSS sont largement prises en charge par les navigateurs depuis avril 2017. Cela ne garantit pas leur prise en charge dans tous les anciens navigateurs. L’exemple contient des déclarations de dimensions ordinaires avant ses déclarations var(), afin que la tuile garde une apparence statique lorsque les propriétés personnalisées ne sont pas disponibles. Consultez la référence MDN sur les propriétés personnalisées.

La valeur de repli dans var(--tile-size, 80px) ne rend pas l’exemple compatible avec un navigateur incapable d’interpréter les propriétés personnalisées. Elle ne valide pas non plus chaque jeton fourni : une valeur définie telle que blue ne devient pas une largeur valide du seul fait qu’une valeur de repli existe. Ces limites sont expliquées dans le guide MDN sur les propriétés personnalisées.

Si un navigateur cible ancien ne prend pas en charge les propriétés personnalisées, l’alternative compatible consiste à modifier la fonction de rendu afin qu’elle écrive des déclarations en ligne ordinaires width, height et border-radius avec setProperty(). Conservez la même validation de l’état et la même synchronisation des commandes. Cela modifie le contrat de rendu ; supprimez donc les écritures concurrentes de la fonction de rendu et vérifiez le navigateur cible au lieu de supposer que la prise en charge est identique.

Pour cet aperçu local, le choix pratique est clair : utilisez l’état pour les sélections de forme et de taille, transmettez ces choix au moyen d’un petit ensemble de paramètres CSS et gardez les éléments décoratifs dans la feuille de style. Après chaque changement, testez une interaction avec une commande et la réinitialisation. L’aperçu, les commandes et la description doivent continuer à refléter les mêmes valeurs sélectionnées.

Sources