Creare un componente Impostazioni

Una panoramica di base sulla creazione di un componente delle impostazioni di cursori e caselle di controllo.

In questo post, voglio condividere le riflessioni sulla creazione di un componente Impostazioni per web che sia reattivo, supporti più input del dispositivo e funziona su browser. Prova la demo.

Demo

Se preferisci i video o vuoi un'anteprima UI/UX di ciò che stiamo creando, ecco un procedura dettagliata più breve su YouTube:

Panoramica

Ho suddiviso gli aspetti di questo componente nelle seguenti sezioni:

  1. Layout
  2. Colore
  3. Inserimento intervallo personalizzato
  4. Inserimento della casella di controllo personalizzata
  5. Considerazioni sull'accessibilità
  6. JavaScript
di Gemini Advanced.

Layout

Questa è la prima demo di GUI Challenge essere all CSS Grid. Ecco ogni griglia evidenziato con la griglia Chrome DevTools per:

Overlay con contorni colorati e spaziatura spazi vuoti che consentono di mostrare tutte le caselle che compongono il layout delle impostazioni.

Solo per il divario

Layout più comune:

foo {
  display: grid;
  gap: var(--something);
}

Chiamo questo layout "solo per intervallo" perché utilizza solo la griglia per aggiungere intervalli tra i blocchi.

Questa strategia viene utilizzata da cinque layout. Vengono visualizzati tutti:

Layout a griglia verticale evidenziati con contorni e spazi vuoti

L'elemento fieldset, che contiene ogni gruppo di input (.fieldset-item), utilizza gap: 1px per creano bordi sottili tra gli elementi. Nessuna soluzione complessa per le frontiere.

Spazio vuoto
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Trucco per i bordi
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Wrapping di griglia naturale

Il layout più complesso è stato il layout macro, il layout logico tra <main> e <form>.

Centrare i contenuti del wrapping

Flexbox e griglia forniscono funzionalità a align-items o align-content e, quando si gestiscono elementi di wrapping, il layout content gli allineamenti distribuiranno lo spazio tra gli elementi secondari in gruppo.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

L'elemento principale è l'utilizzo dell'allineamento place-content: center si tratta di una forma breve che i publisher secondari siano centrati verticalmente e orizzontalmente nei layout a una e a due colonne.

Guarda il video qui sopra come i "contenuti" rimane centrata, anche se il wrapping si è verificato un errore.

Ripeti adattamento automatico minmax

L'<form> utilizza un layout a griglia adattivo per ogni sezione. Questo layout passa da una a due colonne in base allo spazio disponibile.

form {
  display: grid;
  gap: var(--space-xl) var(--space-xxl);
  grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
  align-items: flex-start;
  max-width: 89vw;
}

Questa griglia ha un valore diverso per row-gap (--space-xl) da column-gap (--space-xxl) per dare un tocco personalizzato al layout reattivo. Quando le colonne si sovrappongono, uno spazio ampio, ma non come su uno schermo largo.

La proprietà grid-template-columns utilizza tre funzioni CSS: repeat(), minmax() e min(). Una Kravets ha un ottimo blog di layout su questo argomento, RAM.

Ci sono 3 aggiunte speciali nel nostro layout, se lo confronti con quello di Una:

  • Passiamo una funzione min() aggiuntiva.
  • Specifichiamo align-items: flex-start.
  • Esiste uno stile max-width: 89vw.

La funzione min() aggiuntiva è ben descritta da Evan Minto nel suo blog nella pubblicare Griglia CSS intrinseca reattiva con minmax() e min(). Ti consiglio di leggerlo. La correzione dell'allineamento flex-start è rimuovi l'effetto di allungamento predefinito, in modo che gli elementi secondari di questo layout devono avere altezze uguali, possono avere altezze naturali e intrinseche. La I video di YouTube offrono una rapida suddivisione dell'aggiunta di questo allineamento.

Vale la pena analizzare un po' di più in questo post per max-width: 89vw. Vediamo il layout con e senza lo stile applicato:

Che cosa succede? Quando max-width è specificato, fornisce contesto, dimensioni esplicite o definite dimensioni per auto-fit all'algoritmo di layout per sapere molte ripetizioni può adattarsi allo spazio. Sebbene sembri ovvio che lo spazio è "a larghezza intera", in base alle specifiche della griglia CSS, una dimensione definita o la dimensione massima devono essere fornite. Ho indicato una taglia massima.

Allora, perché 89vw? Perché "ha funzionato" per il mio layout. Io e un paio di altre persone di Chrome stiamo cercando di capire perché un valore più ragionevole, come 100vw non è sufficiente e indica se si tratta di un bug.

Spaziatura

Gran parte dell'armonia di questo layout deriva da una tavolozza limitata di spazi, 7 per l'esattezza.

:root {
  --space-xxs: .25rem;
  --space-xs:  .5rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2rem;
  --space-xl:  3rem;
  --space-xxl: 6rem;
}

L'utilizzo di questi fluidi è molto ottimale con la griglia, con la sintassi CSS @nest e con la sintassi di livello 5 di @media. Ecco un esempio, l'insieme di stili completamente <main>.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
  padding: var(--space-sm);

  @media (width >= 540px) {
    & {
      padding: var(--space-lg);
    }
  }

  @media (width >= 800px) {
    & {
      padding: var(--space-xl);
    }
  }
}

Una griglia con contenuti centrati e leggermente riempiti per impostazione predefinita (come sui dispositivi mobili). Ma man mano che diventa disponibile spazio nell'area visibile, questo si diffonde aumentando la spaziatura interna. I CSS del 2021 vanno benissimo.

Ricordi il layout precedente, "solo per un intervallo"? Ecco una versione più completa di il loro aspetto in questo componente:

header {
  display: grid;
  gap: var(--space-xxs);
}

section {
  display: grid;
  gap: var(--space-md);
}

Colore

Un uso controllato del colore ha permesso a questo design di distinguersi, ma allo stesso tempo espressivo minimo. Faccio in questo modo:

:root {
  --surface1: lch(10 0 0);
  --surface2: lch(15 0 0);
  --surface3: lch(20 0 0);
  --surface4: lch(25 0 0);

  --text1: lch(95 0 0);
  --text2: lch(75 0 0);
}

Definisco i colori della mia superficie e del testo con dei numeri anziché con nomi come surface-dark e surface-darker perché in una query supporti e il chiaro e il buio non sono significativi.

Li inserisco in una query multimediale di preferenza come questa:

:root {
  ...

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --surface2: lch(100 0 0);
      --surface3: lch(98 0 0);
      --surface4: lch(85 0 0);

      --text1: lch(20 0 0);
      --text2: lch(40 0 0);
    }
  }
}

È importante dare un'occhiata veloce al quadro generale e alla strategia prima di nei dettagli della sintassi dei colori. Ma, dal momento che sono un po' più avanti di me, faccio un po' di backup.

LCH?

Senza scendere troppo nel campo della teoria dei colori, LCH è una sintassi orientata all'uomo, che si adatta al modo in cui percepiamo il colore, non al modo in cui misuriamo il colore con i calcoli matematici (come 255). Ciò gli conferisce un netto vantaggio, in quanto gli esseri umani possono scriverlo più facilmente e umani saranno in sintonia con questi cambiamenti.

Uno screenshot della pagina web pod.link/csspodcast, con il colore 2: episodio di percezione visualizzato
. Scopri di più sul colore percettivo (e non solo) nel podcast CSS

Per oggi, in questa demo, concentriamoci sulla sintassi e sui valori che inverto per rendere chiaro e scuro. Diamo un'occhiata a un colore per la superficie e un colore del testo:

:root {
  --surface1: lch(10 0 0);
  --text1:    lch(95 0 0);

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --text1:    lch(40 0 0);
    }
  }
}

--surface1: lch(10 0 0) si traduce in 10% leggerezza, crominanza 0 e tonalità 0: a grigio molto scuro e incolore. Quindi, nella query multimediale per la modalità Luce, la luminosità è impostato su 90% con --surface1: lch(90 0 0);. Questa è la sostanza strategia. Inizia semplicemente modificando la leggerezza tra i due temi, mantenendo rapporti di contrasto richiesti dal design o che possono mantenere l'accessibilità.

Il vantaggio di lch() qui è che la leggerezza è orientata all'uomo e possiamo una modifica di %, che sarà percettiva e coerente che % è diverso. hsl(), ad esempio, non è così affidabili.

C'è altro da fare scopri di più spazi colore e lch() se ti interessa. Sta arrivando!

Al momento CSS non può accedere a questi colori. Ripeto: non abbiamo accesso a un terzo dei colori nella monitor. Non si tratta solo di colori, ma di colori più vividi che lo schermo può essere visualizzato. I nostri siti web sono sbiaditi a causa dell'evoluzione dell'hardware del monitor più rapidamente delle specifiche CSS e delle implementazioni del browser.

Lea Verou

Controlli adattivi dei moduli con schema di colori

Molti browser offrono controlli del tema scuro, al momento Safari e Chromium, ma devi specificare in CSS o HTML che vengono utilizzati dal tuo progetto.

Quanto riportato sopra mostra l'effetto della proprietà nel riquadro Stili di DevTools. La demo utilizza il tag HTML, che a mio parere è generalmente una posizione migliore:

<meta name="color-scheme" content="dark light">

Scopri di più in questo color-scheme articolo di Thomas Steiner. C'è molto altro da guadagnare delle caselle di controllo scure.

CSS accent-color

Ci sono state attività nei dintorni accent-color negli elementi del modulo, essendo un singolo stile CSS in grado di modificare colore di tinta utilizzato nell'elemento di input del browser. Scopri di più qui su GitHub. L'ho incluso nel mio stili per questo componente. Man mano che i browser lo supportano, le mie caselle di controllo di più sul tema con i colori rosa e viola.

input[type="checkbox"] {
  accent-color: var(--brand);
}

Uno screenshot di Chromium su Linux di caselle di controllo rosa

Colori in risalto con sfumature fisse e messa a fuoco all'interno

Il colore risalta di più quando è usato con parsimonia e uno dei modi in cui mi piace ottenerlo. attraverso interazioni con l'interfaccia utente colorate.

Il video sopra riportato offre diversi livelli di feedback e interazione nell'interfaccia utente, che contribuiscono a dare più personalità all'interazione:

  • Evidenziazione del contesto.
  • Invio di feedback sull'interfaccia utente relativi al livello di riempimento. il valore è compreso nell'intervallo.
  • Invio di un feedback all'interfaccia utente in cui si comunica che un campo accetta input.

Per fornire un feedback durante l'interazione con un elemento, il CSS utilizza la sezione :focus-within pseudoclasse per modificare l'aspetto di vari elementi, analizziamo .fieldset-item, è molto interessante:

.fieldset-item {
  ...

  &:focus-within {
    background: var(--surface2);

    & svg {
      fill: white;
    }

    & picture {
      clip-path: circle(50%);
      background: var(--brand-bg-gradient) fixed;
    }
  }
}

Quando uno degli elementi secondari di questo elemento ha lo stato attivo all'interno di:

  1. Allo sfondo .fieldset-item viene assegnato un colore della superficie con contrasto più elevato.
  2. L'elemento svg nidificato è bianco per un maggiore contrasto.
  3. L'elemento <picture> clip-path nidificato si espande in un cerchio completo e sullo sfondo viene riempito con un gradiente fisso luminoso.

Intervallo personalizzato

Dato il seguente elemento di input HTML, ti mostrerò come ne ho personalizzato aspetto:

<input type="range">

L'elemento deve essere personalizzato in tre parti:

  1. Elemento / contenitore dell'intervallo
  2. Track
  3. Pollice

Stili degli elementi dell'intervallo

input[type="range"] {
  /* style setting variables */
  --track-height: .5ex;
  --track-fill: 0%;
  --thumb-size: 3ex;
  --thumb-offset: -1.25ex;
  --thumb-highlight-size: 0px;

  appearance: none;         /* clear styles, make way for mine */
  display: block;
  inline-size: 100%;        /* fill container */
  margin: 1ex 0;            /* ensure thumb isn't colliding with sibling content */
  background: transparent;  /* bg is in the track */
  outline-offset: 5px;      /* focus styles have space */
}

Le prime righe in CSS sono le parti personalizzate degli stili e spero che etichettarli in modo chiaro aiuta. Gli altri stili vengono per lo più reimpostati, per forniscono una base coerente per la creazione delle parti complesse del componente.

Stili di monitoraggio

input[type="range"]::-webkit-slider-runnable-track {
  appearance: none; /* clear styles, make way for mine */
  block-size: var(--track-height);
  border-radius: 5ex;
  background:
    /* hard stop gradient:
        - half transparent (where colorful fill we be)
        - half dark track fill
        - 1st background image is on top
    */
    linear-gradient(
      to right,
      transparent var(--track-fill),
      var(--surface1) 0%
    ),
    /* colorful fill effect, behind track surface fill */
    var(--brand-bg-gradient) fixed;
}

Il trucco è "rivelazione" il vivace colore di riempimento. Questo viene fatto utilizzando gradiente di interruzione definitiva in alto. Il gradiente è trasparente fino alla percentuale di riempimento e, successivamente, che utilizza il colore della superficie della traccia inevasa. Dietro questa superficie inevasa, c'è colore a larghezza intera, in attesa che venga rivelato da una trasparenza.

Stile di riempimento del monitoraggio

Per mantenere lo stile di riempimento, il mio design richiede JavaScript. Là sono strategie solo CSS, ma richiedono che l'elemento pollice abbia la stessa altezza e non sono riuscita a trovare un'armonia entro quei limiti.

/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')

/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
  const max = slider.getAttribute('max') || 10;
  const percent = slider.value / max * 100;

  return `${parseInt(percent)}%`;
};

/* on page load, set the fill amount */
sliders.forEach(slider => {
  slider.style.setProperty('--track-fill', rangeToPercent(slider));

  /* when a slider changes, update the fill prop */
  slider.addEventListener('input', e => {
    e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
  })
})

Penso che sia un bel miglioramento visivo. Il cursore funziona perfettamente senza JavaScript, la proprietà --track-fill non è obbligatoria, semplicemente non avrà stile di riempimento se non presente. Se JavaScript è disponibile, compila il campo osservando al contempo eventuali modifiche dell'utente, sincronizzando la proprietà personalizzata il valore.

Ecco un ottimo pubblica su CSS-Tricks di Ana Tudor, che dimostra una soluzione solo CSS per traccia di riempimento. Ho trovato anche questo Elemento range molto stimolante.

Stili pollici

input[type="range"]::-webkit-slider-thumb {
  appearance: none; /* clear styles, make way for mine */
  cursor: ew-resize; /* cursor style to support drag direction */
  border: 3px solid var(--surface3);
  block-size: var(--thumb-size);
  inline-size: var(--thumb-size);
  margin-top: var(--thumb-offset);
  border-radius: 50%;
  background: var(--brand-bg-gradient) fixed;
}

La maggior parte di questi stili è pensata per creare un bel cerchio. Anche in questo caso vediamo il gradiente di sfondo fisso che unisce colori dinamici di pollici, tracce ed elementi SVG associati. Ho separato gli stili dell'interazione in modo da isolare box-shadow utilizzata per evidenziare il passaggio del mouse:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

::-webkit-slider-thumb {
  

  /* shadow spread is initally 0 */
  box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);

  /* if motion is OK, transition the box-shadow change */
  @media (--motionOK) {
    & {
      transition: box-shadow .1s ease;
    }
  }

  /* on hover/active state of parent, increase size prop */
  @nest input[type="range"]:is(:hover,:active) & {
    --thumb-highlight-size: 10px;
  }
}

L'obiettivo era un'evidenziazione visiva animata e facile da gestire per il feedback degli utenti. Utilizzando un'ombra di una casella, posso evitare di attivare layout con l'effetto. Faccio creando un'ombra non sfocata che corrisponda alla forma circolare pollice. Poi modifico e trasferisco le dimensioni distribuite al passaggio del mouse.

Se solo l'effetto di evidenziazione fosse così facile con le caselle di controllo...

Selettori cross-browser

Ho scoperto di aver bisogno di questi selettori -webkit- e -moz- per ottenere cross-browser coerenza:

input[type="range"] {
  &::-webkit-slider-runnable-track {}
  &::-moz-range-track {}
  &::-webkit-slider-thumb {}
  &::-moz-range-thumb {}
}

Casella di controllo personalizzata

Dato il seguente elemento di input HTML, ti mostrerò come ne ho personalizzato aspetto:

<input type="checkbox">

L'elemento deve essere personalizzato in tre parti:

  1. Elemento casella di controllo
  2. Etichette associate
  3. Effetto evidenziazione

Elemento casella di controllo

input[type="checkbox"] {
  inline-size: var(--space-sm);   /* increase width */
  block-size: var(--space-sm);    /* increase height */
  outline-offset: 5px;            /* focus style enhancement */
  accent-color: var(--brand);     /* tint the input */
  position: relative;             /* prepare for an absolute pseudo element */
  transform-style: preserve-3d;   /* create a 3d z-space stacking context */
  margin: 0;
  cursor: pointer;
}

Gli stili transform-style e position si preparano per lo pseudo-elemento che introdurremo in seguito per definire lo stile dell'evidenziazione. Altrimenti, per lo più roba minore di stile da parte mia. Mi piace che il cursore sia un puntatore, scarti contorni, le caselle di controllo predefinite sono troppo piccole e se accent-color è supportato, porta questi le caselle di controllo nella combinazione di colori del brand.

Etichette casella di controllo

È importante fornire le etichette per le caselle di controllo per due motivi. Il primo è rappresentare lo scopo della casella di controllo e rispondere "per cosa?" Il secondo è per l'esperienza utente. Gli utenti web si sono abituati a interagire caselle di controllo tramite le etichette associate.

input
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
etichetta
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

Nell'etichetta, inserisci un attributo for che rimandi a una casella di controllo in base all'ID: <label for="text-notifications">. Nella casella di controllo, raddoppia il nome e l'ID per assicurati che venga trovato con tecnologie e strumenti diversi, come un mouse o uno screen reader: <input type="checkbox" id="text-notifications" name="text-notifications">. :hover, :active e altri servizi sono senza costi con la connessione, il che aumenta il modalità di interazione con il modulo.

Evidenziazione della casella di controllo

Voglio che le interfacce siano coerenti e che l'elemento di scorrimento abbia un buon l'evidenziazione delle miniature che vorrei utilizzare con la casella di controllo. La miniatura è può utilizzare box-shadow e la sua proprietà spread consente di fare lo scale up di uno shadow up e verso il basso. Tuttavia, l'effetto non funziona in questo caso perché le caselle di controllo sono e dovrebbero quadrato.

Ho ottenuto lo stesso effetto visivo con uno pseudoelemento e una una sfortunata quantità di CSS:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

input[type="checkbox"]::before {
  --thumb-scale: .01;                        /* initial scale of highlight */
  --thumb-highlight-size: var(--space-xl);

  content: "";
  inline-size: var(--thumb-highlight-size);
  block-size: var(--thumb-highlight-size);
  clip-path: circle(50%);                     /* circle shape */
  position: absolute;                         /* this is why position relative on parent */
  top: 50%;                                   /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
  left: 50%;
  background: var(--thumb-highlight-color);
  transform-origin: center center;            /* goal is a centered scaling circle */
  transform:                                  /* order here matters!! */
    translateX(-50%)                          /* counter balances left: 50% */
    translateY(-50%)                          /* counter balances top: 50% */
    translateZ(-1px)                          /* PUTS IT BEHIND THE CHECKBOX */
    scale(var(--thumb-scale))                 /* value we toggle for animation */
  ;
  will-change: transform;

  @media (--motionOK) {                       /* transition only if motion is OK */
    & {
      transition: transform .2s ease;
    }
  }
}

/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
  --thumb-scale: 1;
}

Creare uno pseudo-elemento circolare è un lavoro semplice, ma posizionarlo dietro l'elemento a cui è attaccato era più difficile. Ecco prima e dopo averlo corretto:

Sicuramente è una micro interazione, ma per me è importante mantenere gli elementi visivi coerenza. La tecnica di ridimensionamento dell'animazione è la stessa che abbiamo utilizzato nella in altri posti. Impostiamo una proprietà personalizzata su un nuovo valore e lasciamo che sia CSS la transizione in base alle preferenze di movimento. La funzionalità principale in questo caso è translateZ(-1px). La il genitore ha creato uno spazio 3D a cui è stato toccato questo pseudo-elemento secondario posizionandosi leggermente all'indietro nello spazio z.

Accessibilità

Il video di YouTube offre un'ottima dimostrazione dell'uso di mouse, tastiera e le interazioni con lo screen reader per questo componente delle impostazioni. Chiederò alcuni dei i dettagli qui.

Scelte dell'elemento HTML

<form>
<header>
<fieldset>
<picture>
<label>
<input>

Ciascuno di questi contiene suggerimenti per lo strumento di navigazione dell'utente. Alcuni elementi forniscono suggerimenti sull'interazione, qualche interazione e altre ancora aiutano a modellare albero dell'accessibilità consultato da uno screen reader.

Attributi HTML

Possiamo nascondere elementi non necessari agli screen reader, in questo caso l'icona accanto al cursore:

<picture aria-hidden="true">

Il video riportato sopra mostra il flusso dello screen reader su Mac OS. Nota come l'input la messa a fuoco si sposta direttamente da un cursore all'altro. Questo perché abbiamo nascosto l'icona che potrebbe essere stata una fermata lungo il percorso verso il cursore successivo. Senza l'utente deve fermarsi, ascoltare e andare oltre l'immagine, potrebbero non riuscire a vedere.

Il file SVG è un insieme di calcoli matematici, aggiungiamo un elemento <title> per far passare il mouse sopra titolo e un commento leggibile sul calcolo che sta creando:

<svg viewBox="0 0 24 24">
  <title>A note icon</title>
  <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>

A parte questo, abbiamo utilizzato un codice HTML chiaramente contrassegnato, in modo che i test del modulo molto bene su mouse, tastiera, controller per videogiochi e screen reader.

JavaScript

Abbiamo già illustrato come veniva gestito il colore di riempimento della traccia da JavaScript. ora diamo un'occhiata al codice JavaScript correlato <form>:

const form = document.querySelector('form');

form.addEventListener('input', event => {
  const formData = Object.fromEntries(new FormData(form));
  console.table(formData);
})

Ogni volta che viene interagito e modificato il modulo, la console lo registra come un oggetto in una tabella per esaminarlo facilmente prima di inviarlo a un server.

Uno screenshot dei risultati della funzione console.table(), dove i dati del modulo vengono mostrati in una tabella.

Conclusione

Ora che sai come ci ho fatto, come lo faresti?! È un po' divertente dei componenti. Chi creerà la prima versione con slot nel proprio il tuo framework preferito? 🙂

Diversificaamo i nostri approcci e impariamo tutti i modi per creare sul web. Crea una demo, twittami con i link e la aggiungerò alla sezione Remix della community di seguito.

Remix della community

  • @tomayac con il suo stile per quanto riguarda per le etichette delle caselle di controllo. Questa versione non presenta spazi vuoti tra elementi: demo e fonte.