🍺 Buy me a beer
🎨

UI/UX per Svogliati

Interfacce decenti senza fare il designer.
Per chi costruisce cose e vuole che siano usabili, non solo funzionanti.

"Il design è come un barzelletta. Se devi spiegarlo, non funziona."
— cit. vari, usata a sproposito in ogni pitch deck dal 2015

// 01

UI vs UX — la differenza che tutti confondono

No, non sono la stessa cosa. Sì, lo sapevi già. No, non cambia niente finché non lo applichi.

🖼️ UI — User Interface

È la parte visiva: colori, tipografia, layout, pulsanti, icone, animazioni. È come appare l'interfaccia. Un pittore che fa un bel quadro fa UI.

Se il tuo sito è bello ma incomprensibile, hai fatto buona UI e pessima UX.

🧭 UX — User Experience

È l'esperienza complessiva: l'utente riesce a fare quello che vuole fare? In quanto tempo? Con quanta frustrazione? È come funziona. Un cartello stradale chiaro fa UX.

Se il tuo sito è brutto ma intuitivo, hai fatto cattiva UI e buona UX.

L'analogia migliore Un locale con arredamento fantastico ma camerieri che non sai dove trovare e menu incomprensibile → buona UI, pessima UX.
Un locale con sedie di plastica ma menu chiaro, ordine veloce, conto corretto → cattiva UI, buona UX.
Vuoi entrambe. Inizia dalla UX.

🎯 Per chi costruisce cose: il 20% che conta

Non devi diventare un designer. Devi evitare gli errori che rendono le tue interfacce inutilizzabili. La maggior parte dei problemi di UX nei progetti fatti da sviluppatori non vengono da mancanza di creatività — vengono da 5-6 errori sistematici che si ripetono sempre.

  • Gerarchia visiva inesistente — tutto sembra ugualmente importante
  • Feedback assente — l'utente non sa se il click ha fatto qualcosa
  • Form incomprensibili — errori comunicati male o mai
  • Mobile non considerato — "lo faccio dopo" che non arriva mai
  • Contrasto insufficiente — leggibile solo con schermo brightness al massimo
  • Stato vuoto non gestito — la pagina carica e mostra... niente
// 02

I principi base

Quattro parole che i designer usano nelle riunioni. Impara cosa significano così puoi capire quando stanno dicendo cose sensate e quando no.

📐 Gerarchia visiva

L'occhio umano non legge una pagina linearmente — la scansiona. La gerarchia visiva guida questo scan: cosa è più importante visivamente viene visto prima. Titolo > sottotitolo > corpo > dettagli.

Se tutto è in grassetto, niente è in grassetto. Se tutto è grande, niente è grande.

// esempio — gerarchia visiva

❌ Tutto uguale

Titolo della pagina

Descrizione del prodotto

Dettaglio tecnico importante

Nota a piè di pagina

✅ Gerarchia chiara

Titolo della pagina

Descrizione del prodotto

Dettaglio tecnico · Nota

📡 Feedback

Ogni azione dell'utente deve avere una risposta visibile. Ho cliccato il bottone? Funziona? Sta caricando? È andato a buon fine? Il silenzio dell'interfaccia è la fonte numero uno di frustrazione e doppi click.

  • Hover state — il cursore cambia, il bottone cambia colore
  • Active/press state — il bottone si "schiaccia" visivamente
  • Loading state — spinner, skeleton, progress bar
  • Success state — ✓ verde, messaggio di conferma
  • Error state — rosso, messaggio leggibile (non "Error 500")

🔄 Coerenza

Se il bottone primario è blu in una pagina, deve essere blu ovunque. Se un'azione si annulla con "Annulla", non deve essere "Indietro" in un'altra schermata. La coerenza riduce il carico cognitivo — l'utente non deve reimparare le convenzioni ogni volta.

Il modo più semplice per averla: usa un design system, anche minimale. Anche solo 3-4 variabili CSS con i colori e i font risolve il 70% dei problemi di incoerenza.

🚪 Affordance

Un bottone deve sembrare cliccabile. Un campo di input deve sembrare editabile. L'affordance è la qualità di un elemento che comunica come si usa senza spiegazioni. Un bottone flat con zero elevazione e zero bordo non comunica "cliccami" — comunica "sono testo".

Regola pratica: se devi scrivere "clicca qui" o "trascina qui", l'affordance è rotta.

👁️
Principio
Gerarchia

Guida l'occhio con dimensione, peso e colore

📣
Principio
Feedback

Ogni azione ha una risposta visibile

🔗
Principio
Coerenza

Stessi elementi, stessi comportamenti ovunque

// 03

Tipografia

Il 90% di un'interfaccia è testo. Trattalo bene. No, "Comic Sans dà personalità" non è un argomento valido.

📏 La scala tipografica

Non inventare dimensioni a caso. Usa una scala predefinita — ogni valore è un multiplo del precedente. Le più comuni sono basate su rapporti come 1.25 (Major Third) o 1.333 (Perfect Fourth). Sì, i designer hanno davvero dato nomi musicali alle scale tipografiche. Sono fatti così.

// scala tipografica — Major Third (×1.25)
xs12px — label, caption, metadati
sm14px — testo secondario, note
base16px — corpo del testo principale
lg18px — sottotitolo, intro
xl20px — titolo sezione
2xl24px — titolo pagina
3xl30px — hero title

📖 Leggibilità: le regole pratiche

  • Line height: 1.5–1.7 per il corpo, 1.2–1.3 per i titoli
  • Lunghezza riga: 60–80 caratteri. Oltre è faticoso da leggere.
  • Font size minimo: 14px per testo leggibile, 12px per label
  • Interletteratura: negativa per titoli grandi, normale per corpo
  • Peso: 400 per corpo, 600–700 per enfasi, 900 solo per hero

🔤 Quanti font usare

Uno è sufficiente nella maggior parte dei casi. Due è il massimo sensato (uno per titoli, uno per corpo). Tre font in una stessa interfaccia è un design problem travestito da scelta creativa.

Font sicuri e gratuiti: Inter (interfacce), JetBrains Mono (codice), Geist (moderno), System UI (zero latenza, zero personalità).

/* Design token tipografici in CSS — copia e adatta */
:root {
  --font-sans: 'Inter', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', monospace;

  --text-xs:   0.75rem;    /* 12px */
  --text-sm:   0.875rem;   /* 14px */
  --text-base: 1rem;       /* 16px */
  --text-lg:   1.125rem;   /* 18px */
  --text-xl:   1.25rem;    /* 20px */
  --text-2xl:  1.5rem;     /* 24px */
  --text-3xl:  1.875rem;   /* 30px */
  --text-4xl:  2.25rem;    /* 36px */

  --leading-tight:  1.25;
  --leading-normal: 1.6;
  --leading-loose:  1.8;
}
// 04

Colori

La regola 60-30-10, il contrasto WCAG, e perché quel grigio chiarissimo su sfondo bianco che ti sembra elegante è illeggibile per metà degli utenti.

🎨 La regola 60-30-10

In qualsiasi schema di colori ben bilanciato: 60% colore dominante (sfondo, aree neutre), 30% colore secondario (card, elementi strutturali), 10% colore accent (CTA, link, highlight). Se superi il 10% di accent, l'interfaccia diventa rumorosa.

// palette minima — esempio dark theme
bg
surface
border
muted
text
accent
success
error
warn

9 colori. Non ne servono di più per il 90% dei progetti.

Contrasto — WCAG in 30 secondi

Le WCAG (Web Content Accessibility Guidelines) definiscono rapporti minimi di contrasto tra testo e sfondo. Non è burocrazia — è che il tuo testo grigio chiaro su sfondo bianco è illeggibile per il 30% degli utenti anche senza disabilità visive dichiarate.

// esempi contrasto
Testo grigio su bianco — ratio 2.3:1 FAIL
Grigio medio su bianco — ratio 5.7:1 AA ✓
Testo chiaro su dark — ratio 14.5:1 AAA ✓✓
Livello WCAGRatio minimoApplicazione
AA4.5:1Testo normale (standard minimo accettabile)
AA Large3:1Testo grande (18px+ o 14px bold)
AAA7:1Massima accessibilità
Tool per controllare il contrasto webaim.org/resources/contrastchecker — incolla due hex, ti dice il ratio Browser DevTools → Inspect elemento → clicca sul colore → mostra ratio automaticamente Figma con plugin "Contrast" — controlla tutto il file in un click
// 05

Spazio e layout

Il whitespace non è spazio sprecato. Anche se il tuo capo continua a chiedere di "sfruttare meglio lo spazio".

📦 La scala degli spazi

Stessa logica della tipografia: usa una scala fissa invece di valori random. La base comune è 4px o 8px — ogni valore è un multiplo. Tailwind CSS usa questa scala di default e funziona benissimo.

// scala spazi — base 4px
1 — 4px
2 — 8px
3 — 12px
4 — 16px
6 — 24px
8 — 32px
12 — 48px
16 — 64px

🧲 Legge della prossimità

Elementi correlati devono stare vicini. Elementi non correlati devono avere più spazio tra loro. Se il label di un campo form è lontano quanto il campo successivo, l'utente non capisce cosa appartiene a cosa.

Regola pratica: lo spazio interno a un gruppo deve essere minore dello spazio tra gruppi diversi.

📐 Max-width per la leggibilità

Su schermi larghi, il testo a piena larghezza diventa impossibile da leggere. Il corpo del testo non dovrebbe mai superare i 65-75ch (caratteri) di larghezza. Per layout più ampi, usa colonne o max-width sul container di testo.

.prose { max-width: 65ch; }
/* Design token spaziatura — base 4px */
:root {
  --space-1:  0.25rem;  /* 4px  */
  --space-2:  0.5rem;   /* 8px  */
  --space-3:  0.75rem;  /* 12px */
  --space-4:  1rem;     /* 16px */
  --space-6:  1.5rem;   /* 24px */
  --space-8:  2rem;     /* 32px */
  --space-12: 3rem;     /* 48px */
  --space-16: 4rem;     /* 64px */
  --space-24: 6rem;     /* 96px */
}
// 06

Componenti comuni

Bottoni, toast, modal. Quelli che tutti sanno fare ma quasi nessuno fa bene. Inclusi i team con il design system da 200 componenti.

🔘 Bottoni — stati e gerarchia

Un bottone ha almeno 5 stati: default, hover, active (pressed), focus, disabled. Se ne manca anche uno solo, l'interfaccia sembra rotta. E ci sono tre livelli di gerarchia: primary (CTA principale), secondary (azione alternativa), ghost/tertiary (azione di minor peso).

// gerarchia bottoni
// distruttivo
Non mettere mai due Primary nella stessa schermata Se hai due bottoni primary, l'utente non sa cosa fare. Uno è primary, uno è secondary. Se sono davvero equivalenti, entrambi secondary e scrivi meglio il copy per distinguerli.

🔔 Feedback: Toast e Alert

I toast sono notifiche temporanee (2-4 secondi) per azioni completate. Gli alert sono messaggi persistenti per stati importanti. Entrambi devono avere quattro varianti semantiche: success (verde), error (rosso), warning (giallo), info (blu).

// alert variants
✓ Salvataggio completato con successo.
✗ Errore di connessione. Riprova tra qualche secondo.
⚠ La sessione scade tra 5 minuti.
ℹ Il deploy è in corso. Potrebbe richiedere 2-3 minuti.

💀 Loading e stati vuoti

Ogni componente che carica dati da rete ha tre stati che devi gestire: loading (spinner o skeleton), empty (nessun dato), error (qualcosa è andato storto). Se gestisci solo lo stato "dati presenti", il 30% delle volte la tua UI è rotta senza che tu lo sappia.

  • Preferisci gli skeleton loader agli spinner — riducono la perceived latency
  • Lo stato vuoto non è "nessun risultato" in grigio — è un'opportunità: spiega perché è vuoto e cosa fare
  • L'errore deve dire cosa è successo e cosa può fare l'utente (non "Something went wrong")
// 07

Form

Il componente più odiato dagli sviluppatori, il più usato dagli utenti, e quello su cui ci sono più tutorial sbagliati in circolazione.

📝 Le regole d'oro dei form

  • Un campo per riga — layout a colonne per form lunghi aumenta gli errori
  • Label sopra il campo, non a sinistra e non come placeholder
  • Placeholder ≠ label — il placeholder sparisce quando scrivi: l'utente dimentica cosa stava compilando
  • Errore inline, non in cima — accanto al campo che ha l'errore, non in un banner generale
  • Valida on blur, non on submit — l'utente scopre l'errore subito, non dopo aver compilato tutto
  • Submit solo se il form è valido — o grayed out, o mostra cosa manca
// form — stato normale, errore, hint
Useremo questa email solo per il login
Minimo 8 caratteri, almeno un numero

❌ Errori comuni

  • Placeholder come unica label
  • "Campo obbligatorio" solo dopo submit
  • Errore generico in cima: "Correggi i dati"
  • Reset al posto di Cancel
  • CAPTCHA su form di login interni
  • Conferma password senza mostra/nascondi

✅ Best practice

  • Label persistente sopra il campo
  • Validazione on blur con messaggio specifico
  • Asterisco su campi obbligatori, non facoltativi
  • Bottone submit con stato loading
  • Autofocus sul primo campo
  • Enter per submit sui form semplici
// 08

Mobile-first

Non è "la versione piccola del desktop". E no, non basta testarlo ridimensionando Chrome sul tuo MacBook da 16 pollici.

Mobile-first non significa "ridimensiona" Significa progettare prima per il contesto più vincolato (schermo piccolo, connessione lenta, dita invece del cursore) e poi espandere. Se fai il contrario — "desktop-first e poi comprimo" — il risultato è sempre scomodo su mobile.

👆 Touch target size

Le dita non sono cursori. Un touch target troppo piccolo è la fonte numero uno di tap errati su mobile. Apple HIG raccomanda 44×44pt minimi, Google Material raccomanda 48×48dp. Nella pratica: ogni bottone, link, o elemento interattivo deve avere almeno 44px di area tappabile, anche se visivamente è più piccolo.

/* Trick: aumenta l'area di tap senza cambiare l'aspetto */
.small-btn {
  position: relative;
  padding: 12px;  /* area reale */
}
/* oppure */
.icon-btn {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

📱 Breakpoint essenziali

/* Mobile-first: scrivi base per mobile,
   poi sovrascrivi per schermi più grandi */

/* default: mobile */
.grid { grid-template-columns: 1fr; }

/* tablet ≥768px */
@media (min-width: 768px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}

/* desktop ≥1024px */
@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}

Performance su mobile

  • Immagini: usa srcset e loading="lazy"
  • Font: max 2 weight per font family, usa font-display: swap
  • Animazioni: transform e opacity sono GPU-accelerated. Evita margin, width, height nelle animazioni
  • Evita vh puro su mobile — la barra del browser cambia altezza durante lo scroll. Usa svh o dvh
// 09

Accessibilità pratica

Non serve diventare esperti WCAG. Bastano 10 regole. Di cui almeno 4 probabilmente stai già violando.

Perché l'accessibilità non è solo per i disabili Il 15% della popolazione mondiale ha qualche forma di disabilità. Ma le tecniche di accessibilità aiutano tutti: sottotitoli li usano anche in ambienti rumorosi, alto contrasto lo apprezzano anche all'aperto con il sole, la navigazione da tastiera la usano i power user.

🏷️ Semantic HTML — gratis e fondamentale

Usare i tag HTML giusti risolve il 60% dei problemi di accessibilità senza scrivere una riga di CSS o JS aggiuntivo. Gli screen reader capiscono <button>, <nav>, <main>, <h1>. Non capiscono <div class="btn"> e <span class="title">.

❌ Non semantico

<div class="nav">
  <span onclick="go()">
    Home
  </span>
</div>
<div class="title">Ciao</div>
<div class="btn" onclick="submit()">
  Invia
</div>

✅ Semantico

<nav>
  <a href="/">
    Home
  </a>
</nav>
<h1>Ciao</h1>
<button type="submit">
  Invia
</button>

⌨️ Le 10 regole pratiche

  • Usa tag semantici: <nav>, <main>, <article>, <button>, <h1-h6>
  • Ogni immagine ha alt descrittivo (o alt="" se decorativa)
  • Contrasto testo/sfondo ≥ 4.5:1
  • Tutto è navigabile da tastiera (Tab, Enter, Escape)
  • Focus visibile — non fare outline: none senza sostituirlo
  • Form label collegate ai field (<label for="id">)
  • Errori non comunicati solo con il colore (aggiungi testo o icona)
  • Video con sottotitoli o trascrizione
  • Niente flash più di 3 volte al secondo (epilessia fotosensibile)
  • Ordine logico del DOM — non riordinare solo con CSS flex/grid
/* Focus visibile — non toglierlo, miglioralo */
:focus-visible {
  outline: 2px solid #38bdf8;
  outline-offset: 2px;
  border-radius: 4px;
}

/* Rimuovi solo per mouse, non per tastiera */
:focus:not(:focus-visible) {
  outline: none;
}
// 10

Dark mode

Non è "inverti i colori". Non è filter: invert(1). Non è "metti tutto su sfondo nero". È una palette separata e ci vuole cinque minuti a farlo bene.

🌑 Come funziona davvero

L'errore più comune nel dark mode è usare filter: invert(1) o semplicemente invertire i colori. Il risultato è quasi sempre sbagliato — le immagini si invertono, i colori saturati diventano aggressivi, le ombre non funzionano. Il secondo errore più comune è annunciare il dark mode come feature importante quando è solo sfondo nero con testo bianco.

Il dark mode corretto ha una palette separata definita come CSS custom properties, e si attiva con prefers-color-scheme o con una classe sul <html>.

/* Design token con dark mode automatico */
:root {
  --bg:      #ffffff;
  --surface: #f8fafc;
  --text:    #0f172a;
  --muted:   #64748b;
  --accent:  #0ea5e9;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:      #0f172a;
    --surface: #1e293b;
    --text:    #e2e8f0;
    --muted:   #94a3b8;
    --accent:  #38bdf8; /* più chiaro in dark */
  }
}

/* Toggle manuale via classe */
.dark {
  --bg:      #0f172a;
  /* ... */
}

⚠️ Insidie del dark mode

  • Sfondo nero puro (#000) affatica gli occhi — usa grigio scuro (#0f172a)
  • Ombre in dark mode: usa box-shadow con colori chiari invece che scuri
  • Immagini con sfondo bianco diventano brutte — usa mix-blend-mode o fornisci versioni separate
  • I colori accent saturati su sfondo scuro "vibrano" — desaturali leggermente

💡 Colori per dark mode

  • Sfondo: #0f172a non #000000
  • Surface: #1e293b — per card e modal
  • Border: rgba(255,255,255,0.08) — quasi invisibile
  • Text primario: #e2e8f0 non #ffffff puro
  • Text muted: #94a3b8
  • Elevazione: aumenta la lightness, non la shadow
// 11

Tools

Cosa usare, perché, e soprattutto cosa non devi comprare/abbonare/imparare prima di aver fatto una sola riga di CSS.

ToolCosa faQuando usarlo
Figma Design, prototipo, handoff Se lavori con un designer o vuoi progettare prima di codare
Excalidraw Wireframe veloci, diagrammi Sketching rapido, brainstorming, zero overhead
Tailwind CSS Utility-first CSS framework Quando vuoi costruire veloce senza design system custom
shadcn/ui Componenti React pronti (copia nel progetto) React + Tailwind, componenti accessibili senza libreria esterna
Radix UI Primitive UI accessibili headless Quando vuoi stile custom ma accessibilità garantita
Coolors.co Generatore palette colori Trovare combinazioni armoniche in 30 secondi
Google Fonts Font gratuiti Inter, Geist, JetBrains Mono — già ottimi per interfacce
Contrast Checker Verifica ratio WCAG Prima di decidere qualsiasi combinazione testo/sfondo
Lighthouse Audit performance, a11y, SEO DevTools → Lighthouse — gratis, diretto, usa sempre
axe DevTools Audit accessibilità automatico Extension browser, trova i problemi a11y evidenti automaticamente
Figma non è obbligatorio Se costruisci da solo o in un team piccolo senza designer, puoi benissimo partire direttamente dal codice con Tailwind e un sistema di token CSS. Figma aggiunge valore quando hai collaboratori non tecnici o quando la UI è complessa abbastanza da richiedere iterazioni prima dello sviluppo.
// 12

Checklist finale

Prima di andare in produzione. Spuntala davvero, non solo leggila pensando "sì sì" e chiudendo la tab.

🎨 Visual

  • ☐ Contrasto testo/sfondo ≥ 4.5:1 ovunque
  • ☐ Font leggibile, massimo 2 famiglie
  • ☐ Scala tipografica coerente
  • ☐ Spaziatura da scala fissa (non valori random)
  • ☐ Gerarchia visiva chiara nella hero/header
  • ☐ Colori semantici: verde=ok, rosso=errore, giallo=warn
  • ☐ Dark mode (o almeno non si rompe con prefers-color-scheme)

🧭 UX

  • ☐ Ogni azione ha feedback visivo
  • ☐ Stati loading, empty, error gestiti
  • ☐ Nessun bottone primario doppio nella stessa schermata
  • ☐ Messaggi di errore specifici (non "errore generico")
  • ☐ Il flusso principale funziona in 3 click o meno
  • ☐ Undo disponibile per azioni distruttive
  • ☐ Copy chiaro: i bottoni dicono cosa fanno (non "Ok")

📱 Mobile

  • ☐ Touch target ≥ 44×44px
  • ☐ Testo leggibile senza zoom (min 16px per body)
  • ☐ Niente hover-only interactions
  • ☐ Input type corretto (email, tel, number)
  • ☐ Viewport meta tag presente
  • ☐ Testato su schermo reale, non solo DevTools

Accessibilità

  • ☐ HTML semantico (no div-soup)
  • ☐ Alt su tutte le immagini
  • ☐ Focus visibile su tutti gli elementi interattivi
  • ☐ Tab order logico
  • ☐ Form label collegate ai field
  • ☐ Lighthouse accessibilità ≥ 90
  • ☐ Testato con tastiera (solo Tab + Enter + Esc)
La regola dell'80% Non devi fare tutto perfetto. Ma se spunti l'80% di questa checklist, la tua interfaccia è già nel top 20% di quello che gira su internet. Il perfetto è nemico del buono. Lancia, poi migliora in base al feedback reale degli utenti.