Sovrascrivere una variabile CSS su un elemento figlio non ricrea una proprietà personalizzata composita ereditata dal genitore. Il genitore ha già risolto il riferimento annidato. Per usare il valore dell’elemento figlio, dichiara la proprietà composita su quell’elemento oppure componi lì la proprietà finale.

Questa guida spiega questo comportamento e propone un esercizio riproducibile sul desktop in Chrome su Mac. L’obiettivo è fare in modo che il bordo di un componente segua la sua sovrascrittura locale del colore, mantenendo al contempo i valori predefiniti condivisi.

Perché la proprietà composita ereditata mantiene il colore del genitore?

Considera questo frammento CSS. Presuppone un elemento .sample-tile all’interno di un elemento .sample-board:

.sample-board {
  --sample-color: teal;
  --sample-border: 6px solid var(--sample-color);
}

.sample-tile {
  --sample-color: darkorange;
  border: var(--sample-border);
}

Il bordo dell’elemento figlio rimane teal. La specifica CSS Variables afferma che le proprietà personalizzate risolvono le funzioni var() annidate al momento del valore calcolato, prima dell’ereditarietà. Di conseguenza, l’elemento figlio eredita un valore composito equivalente a 6px solid teal; non eredita un’espressione che sostituirà --sample-color con il valore dell’elemento figlio. CSS Custom Properties for Cascading Variables Module Level 1.

Qui si tratta di due proprietà distinte. Impostare --sample-color sull’elemento figlio cambia il valore locale di quella proprietà. Non dichiara anche un nuovo valore per --sample-border. Il riferimento di MDN alle proprietà personalizzate descrive le normali proprietà personalizzate non registrate come ereditate, con valori calcolati in cui le variabili sono state sostituite. Proprietà personalizzate: variabili CSS.

La sequenza in questo esempio è:

  1. Il genitore calcola --sample-color come teal.
  2. La sua proprietà --sample-border sostituisce quel colore, producendo 6px solid teal.
  3. L’elemento figlio eredita questo valore composito e imposta separatamente il proprio token colore su darkorange.
  4. La dichiarazione border dell’elemento figlio usa il valore composito teal ereditato.

Non si tratta di un’istantanea permanente del genitore. Se cambia il colore del genitore, anche la sua proprietà composita può aggiornarsi ed essere ereditata di nuovo. Il confine è l’elemento in cui viene risolto il riferimento annidato: una sovrascrittura di un discendente non risale fino a influire su quel calcolo. Variabili CSS: risoluzione delle dipendenze.

Riprodurre il comportamento in Chrome su Mac

Usa una pagina vuota per evitare interferenze da parte degli stili esistenti. Apri una nuova scheda di Chrome, inserisci about:blank nella barra degli indirizzi, quindi premi Command + Option + J per aprire la Console. Google documenta questa scorciatoia per Mac nella guida a DevTools. Aprire Chrome DevTools.

Il programma completo per la console del browser riportato di seguito crea tre forme astratte con etichette e il relativo foglio di stile. Non richiede librerie, immagini, richieste di rete o elementi di pagina esistenti. Esegui l’intero blocco una volta nella pagina vuota. I risultati attesi riportati sotto derivano dalle regole CSS documentate; non sono presentati come misurazioni registrate nel browser.

(() => {
  const board = document.createElement("section");
  board.className = "sample-board";

  const style = document.createElement("style");
  style.textContent = `
    .sample-board {
      --sample-color: teal;
      --sample-border: 6px solid var(--sample-color);
      display: flex;
      flex-wrap: wrap;
      gap: 24px;
      padding: 32px;
      font: 16px system-ui;
    }

    .sample-board .sample-tile {
      --sample-color: darkorange;
      display: grid;
      place-items: center;
      width: 120px;
      height: 80px;
      border: var(--sample-border);
      border-radius: 24px;
      background: white;
      color: black;
    }

    .sample-board .sample-local {
      --sample-border: 6px solid var(--sample-color);
    }

    .sample-board .sample-direct {
      border: 6px solid var(--sample-color);
    }
  `;

  const samples = [
    ["Inherited", "sample-inherited"],
    ["Local", "sample-local"],
    ["Direct", "sample-direct"]
  ];

  const tiles = samples.map(([label, className]) => {
    const tile = document.createElement("div");
    tile.className = `sample-tile ${className}`;
    tile.textContent = label;
    board.append(tile);
    return tile;
  });

  document.head.append(style);
  document.body.append(board);

  function report(stage) {
    console.log(stage);
    console.table(tiles.map((tile) => {
      const computed = getComputedStyle(tile);
      return {
        sample: tile.textContent,
        localColor: computed
          .getPropertyValue("--sample-color").trim(),
        composite: computed
          .getPropertyValue("--sample-border").trim(),
        paintedBorder: computed.borderTopColor
      };
    }));
  }

  report("Initial values");
  board.style.setProperty("--sample-color", "rebeccapurple");
  report("After changing the parent color");
})();

Il programma stampa due tabelle. I colori attesi dei bordi sono:

Campione Inizialmente Dopo la modifica del genitore Motivo
Inherited Teal Viola Usa la proprietà composita calcolata del genitore
Local Arancione Arancione Dichiara la proprietà composita sull’elemento figlio
Direct Arancione Arancione Sostituisce direttamente il colore locale in border

Tutti e tre gli elementi figli mantengono darkorange come token colore locale. L’elemento utile per la diagnosi è il campione Direct: la sua proprietà composita ereditata contiene ancora il colore del genitore, ma il bordo visualizzato usa il token locale perché la relativa dichiarazione del bordo non usa la proprietà composita.

getComputedStyle() legge i valori risolti delle proprietà dopo l’applicazione dei fogli di stile attivi. Può quindi rivelare il valore effettivamente ricevuto da un elemento, invece di mostrare soltanto l’espressione dichiarata. La serializzazione del colore può apparire come valore rgb() invece che come il nome originale del colore. Window: metodo getComputedStyle().

Ricarica la scheda vuota per cancellare l’esercizio. Per una pagina esistente, inserisci la correzione CSS scelta nel foglio di stile; le modifiche effettuate nella console sono utili per la diagnosi, ma non modificano i file sorgente.

Quale correzione scegliere?

Dichiara la proprietà composita al confine del componente

Il campione Local mantiene il token del bordo riutilizzabile e ne dichiara la formula sullo stesso elemento che fornisce la sovrascrittura. Ecco il frammento CSS pertinente del programma:

.sample-board .sample-local {
  --sample-color: darkorange;
  --sample-border: 6px solid var(--sample-color);
  border: var(--sample-border);
}

Scegli questo schema quando più dichiarazioni hanno bisogno dello stesso valore composto. Inserisci i valori primitivi predefiniti su un elemento antenato e la dichiarazione composita sul componente che gestisce la personalizzazione. Le proprietà personalizzate possono essere dichiarate su elementi specifici ed ereditate dai relativi discendenti; non devono necessariamente trovarsi su :root. Uso delle proprietà personalizzate CSS.

La posizione della dichiarazione resta importante anche più in basso nell’albero. Se un nipote sovrascrive di nuovo il valore primitivo, una proprietà composita ereditata da questo componente continuerà a riflettere il calcolo del componente stesso. Dichiara di nuovo la formula su qualsiasi elemento discendente che debba comporre un risultato diverso.

Componi la proprietà finale nel punto in cui viene usata

Il campione Direct rimuove il token intermedio dalla dichiarazione del bordo. Questo frammento CSS ne mostra la regola essenziale:

.sample-board .sample-direct {
  --sample-color: darkorange;
  border: 6px solid var(--sample-color);
}

Scegli questa soluzione quando la combinazione serve a una sola dichiarazione. Puoi comunque condividere token separati per larghezza, stile e colore, quindi combinarli nella dichiarazione border del componente. MDN documenta che var() può sostituire tutto o parte del valore di un’altra proprietà. Uso delle proprietà personalizzate CSS.

Sovrascrivi l’intera proprietà composita se è il controllo esposto

A volte la personalizzazione prevista per il componente riguarda l’intero bordo. In tal caso, fornisci un valore sostitutivo locale per --sample-border, ad esempio 6px solid darkorange, invece di cambiare soltanto il suo input precedente.

Usa questo schema decisionale per scegliere il contratto del componente:

Personalizzazione prevista Schema adatto
Un colore locale controlla un bordo Componi direttamente in border
Più dichiarazioni condividono un valore composto Dichiara la proprietà composita sul componente
Chi utilizza il componente fornisce l’intero bordo Sovrascrivi la proprietà composita stessa
I discendenti devono usare esattamente il valore composto dal genitore Mantieni la proprietà composita ereditata

Perché specificità, fallback o parole chiave di ereditarietà non la ricompongono?

Per prima cosa, verifica che la sovrascrittura del valore primitivo abbia effettivamente prevalso. Se il valore risolto di --sample-color dell’elemento figlio è già darkorange, rendere più specifica quella stessa dichiarazione non cambierà la proprietà distinta --sample-border ereditata. Entrambe le proprietà hanno già un valore; il problema è il punto in cui è stata composta la proprietà composita.

Analogamente, --sample-border: inherit acquisisce il valore calcolato del genitore. La normale ereditarietà trasferisce valori calcolati invece di rieseguire la dichiarazione scritta dal genitore nel contesto dell’elemento figlio. Ereditarietà.

Anche un fallback come var(--sample-border, 6px solid darkorange) lascia invariato un bordo teal ereditato valido. Un fallback var() gestisce una proprietà personalizzata priva di un valore utilizzabile; non confronta quel valore con gli input preferiti di un discendente. Funzione CSS var().

Tieni distinti i valori non validi da questo problema di ereditarietà. Per esempio, un token non registrato contenente 12px può esistere come valore di una proprietà personalizzata, ma produrre un risultato non valido quando viene sostituito in border-color. Il fallback nella chiamata var() non è un’alternativa generica per il controllo dei tipi. MDN spiega perché la sostituzione di proprietà personalizzate può creare dichiarazioni che diventano non valide al momento del valore calcolato. Uso delle proprietà personalizzate CSS.

Registrare la variabile con @property risolve il problema?

@property consente di specificare la sintassi, il valore iniziale e il comportamento di ereditarietà di una proprietà personalizzata. Non fa sì che una proprietà composita ereditata del genitore venga ricalcolata usando gli input sovrascritti dell’elemento figlio. Registrare il valore primitivo con inherits: false cambierebbe il modo in cui viene acquisito, mentre registrare così la proprietà composita ne interromperebbe la normale ereditarietà. Nessuna delle due soluzioni fornisce la formula locale mancante. Regola CSS @property.

La registrazione ha anche un diverso limite di compatibilità. MDN indica che le normali proprietà personalizzate sono ampiamente disponibili nei browser da aprile 2017, mentre @property ha raggiunto la disponibilità Baseline a luglio 2024 e potrebbe non essere disponibile nei browser meno recenti. Le due correzioni mostrate non richiedono registrazione. Proprietà personalizzate: variabili CSS, Regola CSS @property.

Come diagnosticare lo stesso problema nel foglio di stile

Usa il confronto a tre colonne dell’esercizio sull’elemento dall’aspetto errato:

  1. Leggi il token primitivo, come --sample-color.
  2. Leggi il token composito, come --sample-border.
  3. Leggi la proprietà visualizzata, come border-top-color.
  4. Trova l’elemento a cui si applica la dichiarazione composita.
  5. Sposta o ripeti quella dichiarazione sul confine di personalizzazione previsto, oppure componi direttamente la proprietà finale.

Per individuare le regole pertinenti in Chrome, fai clic con il tasto destro sulla forma e scegli Inspect. DevTools seleziona l’elemento in Elements e la scheda Styles mostra le regole CSS applicate. Aprire Chrome DevTools.

Quando il valore primitivo mostra il valore locale desiderato ma la proprietà composita contiene ancora il valore di un antenato, controlla prima il punto in cui è dichiarata la proprietà composita. Definisci la formula nel punto in cui devono essere letti i relativi input, quindi verifica sia il token risolto sia il risultato visualizzato. In questo modo il componente ha un confine di personalizzazione esplicito e prevedibile.

Fonti