1. Struttura di base HTML5 Moderno


<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="referrer" content="strict-origin-when-cross-origin">
  <title>Titolo Ottimizzato SEO</title>
  <meta name="description" content="Descrizione accattivante per i risultati di ricerca.">
  <link rel="canonical" href="https://example.com/pagina">
  
  <!-- Preconnessione ai font esterni -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  
  <!-- Stili -->
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main>
    <h1>Contenuto Principale</h1>
  </main>
</body>
</html>
          

2. Layout Semantico e Accessibile


<header role="banner">
  <nav aria-label="Navigazione principale">
    <ul>
      <li><a href="/" aria-current="page">Home</a></li>
      <li><a href="/servizi">Servizi</a></li>
    </ul>
  </nav>
</header>

<main id="main-content" role="main">
  <article>
    <header>
      <h1>Titolo dell'Articolo</h1>
      <p>Pubblicato il <time datetime="2026-07-04">4 Luglio 2026</time></p>
    </header>
    
    <section aria-labelledby="sec-intro">
      <h2 id="sec-intro">Introduzione</h2>
      <p>Contenuto descrittivo...</p>
    </section>
  </article>
  
  <aside aria-label="Risorse correlate">
    <h3>Link utili</h3>
  </aside>
</main>

<footer role="contentinfo">
  <p>&copy; 2026 Codedge. Tutti i diritti riservati.</p>
</footer>
          

3. Form di Contatto Strutturato


<form action="/submit" method="POST" class="form-container" novalidate>
  <div class="form-group">
    <label for="user-name">Nome Completo</label>
    <input type="text" id="user-name" name="name" required minlength="3" autocomplete="name">
  </div>

  <div class="form-group">
    <label for="user-email">Indirizzo Email</label>
    <input type="email" id="user-email" name="email" required autocomplete="email">
  </div>

  <div class="form-group">
    <label for="user-message">Messaggio</label>
    <textarea id="user-message" name="message" rows="5" required minlength="10" placeholder="Scrivi qui..."></textarea>
  </div>

  <button type="submit" class="submit-btn">Invia Richiesta</button>
</form>
          

4. Immagine Responsive con Picture e WebP


<picture>
  <!-- Schermi grandi (desktop) fallback WebP -->
  <source media="(min-width: 1024px)" srcset="image-large.webp" type="image/webp">
  <source media="(min-width: 1024px)" srcset="image-large.jpg" type="image/jpeg">
  
  <!-- Schermi piccoli (mobile) fallback WebP -->
  <source srcset="image-small.webp" type="image/webp">
  
  <!-- Immagine di fallback standard -->
  <img src="image-small.jpg" alt="Descrizione dell'immagine" loading="lazy" decoding="async" width="600" height="400">
</picture>
          

5. Iframe Video Responsivo (Anti-CLS)


<div class="video-container">
  <iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" 
          title="Video di esempio" 
          frameborder="0" 
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" 
          allowfullscreen 
          loading="lazy">
  </iframe>
</div>

<style>
.video-container {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9; /* Risolve il problema del CLS senza padding-top hack */
}
.video-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 8px;
}
</style>
          

1. Reset CSS Moderno


/* Reset basato sulle best practice moderne */
*, *::before, *::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: #ffffff;
  color: #1a1a1a;
  text-rendering: optimizeLegibility;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
  height: auto;
}

input, button, textarea, select {
  font: inherit;
}

p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

html:focus-within {
  scroll-behavior: smooth;
}
          

2. Centratura e Allineamento Flexbox


/* Centratura perfetta in un contenitore */
.flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* Row flessibile e responsiva con gap */
.flex-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  justify-content: space-between;
  align-items: center;
}

/* Forza la colonna flex su piccoli schermi */
@media (max-width: 640px) {
  .flex-row {
    flex-direction: column;
    align-items: stretch;
  }
}
          

3. Griglia Auto-Responsive (Senza Media Queries)


/* Genera colonne dinamiche in base allo spazio disponibile */
.auto-grid {
  display: grid;
  /* Minimo 280px, massimo 1 parte dello spazio rimanente */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

/* Griglia per layout asimmetrici (Sidebar 300px + Main flessibile) */
.layout-grid {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: 2rem;
}

@media (max-width: 768px) {
  .layout-grid {
    grid-template-columns: 1fr;
  }
}
          

4. Variabili CSS e Dark Mode nativa


/* Root per tema chiaro di base */
:root {
  --primary-color: #007bf0;
  --bg-color: #ffffff;
  --text-color: #1a1a1a;
  --border-color: #e5e7eb;
}

/* Attivazione dark mode nativa del sistema */
@media (prefers-color-scheme: dark) {
  :root {
    --primary-color: #3b82f6;
    --bg-color: #111827;
    --text-color: #f9fafb;
    --border-color: #374151;
  }
}

/* Utilizzo pratico delle custom properties */
body {
  background-color: var(--bg-color);
  color: var(--text-color);
  border-color: var(--border-color);
}
          

5. Hover ed Effetti UI


/* Effetto bottone lucido con transizione smooth */
.btn-interactive {
  position: relative;
  display: inline-flex;
  padding: 0.75rem 1.5rem;
  background-color: var(--primary-color, #007bf0);
  color: #fff;
  border-radius: 6px;
  overflow: hidden;
  transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.btn-interactive:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(0, 123, 240, 0.25);
  background-color: #0060be;
}

.btn-interactive:active {
  transform: translateY(1px);
}
          

6. Carosello CSS con Scroll Snap


/* Contenitore a scorrimento orizzontale magnetico */
.carousel-snap {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  gap: 1rem;
  padding: 1rem 0;
}

/* Singolo elemento del carosello */
.carousel-item {
  flex: 0 0 80%; /* 80% della larghezza del parent */
  scroll-snap-align: center;
  border-radius: 8px;
  background: #2a2a2a;
}
          

7. Troncamento Testo Multilinea


/* Limita il testo a un numero esatto di righe con ellissi (...) */
.truncate-lines-3 {
  display: -webkit-box;
  -webkit-line-clamp: 3; /* Numero massimo di righe */
  -webkit-box-orient: vertical;  
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Singolo troncatore classico su una sola riga */
.single-line-ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
}
          

1. Event Delegation su elementi dinamici


// Ascolta i click sull'intero container per intercettare bottoni generati al volo
const container = document.querySelector('.dynamic-list');

container.addEventListener('click', (event) => {
  // Trova l'elemento target con classe specifica
  const deleteBtn = event.target.closest('.btn-delete');
  
  if (deleteBtn) {
    const item = deleteBtn.closest('.list-item');
    item.remove(); // Rimuove l'elemento corrispondente
  }
});
          

2. Ottimizzazioni Debounce e Throttle


// Debounce: esegue la funzione solo dopo N millisecondi di inattività
function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

// Throttle: esegue la funzione al massimo una volta ogni N millisecondi
function throttle(fn, limit) {
  let inThrottle = false;
  return function (...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// Esempio: throttle sullo scroll o debounce sulla ricerca input
window.addEventListener('scroll', throttle(() => console.log('Scrolled!'), 200));
          

3. Chiamata Fetch API con Async/Await


async function fetchData(url = '') {
  try {
    const response = await fetch(url, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      }
    });

    if (!response.ok) {
      throw new Error(`Errore HTTP: status ${response.status}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Errore durante la chiamata fetch:', error);
    return null;
  }
}
          

4. LocalStorage JSON Helper


const storage = {
  // Salva un oggetto convertendolo in stringa JSON
  set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (e) {
      console.error('Errore scrittura LocalStorage:', e);
      return false;
    }
  },

  // Recupera l'oggetto deserializzandolo
  get(key) {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : null;
    } catch (e) {
      console.error('Errore lettura LocalStorage:', e);
      return null;
    }
  }
};
          

5. Intersection Observer per Lazy/Animations


// Crea un observer per monitorare la visibilità degli elementi nello schermo
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('visible'); // Aggiunge la classe per avviare transizioni CSS
      observer.unobserve(entry.target); // Smette di osservare l'elemento una volta attivato
    }
  });
}, {
  threshold: 0.15, // Attiva l'azione al 15% di visibilità dell'elemento
  rootMargin: '0px 0px -50px 0px' // Margine inferiore per anticipare l'azione
});

// Avvia l'osservatore su tutti i target stabiliti
document.querySelectorAll('.animate-on-scroll').forEach(el => observer.observe(el));
          

1. Indice lettura con progress bar


<div class="reading-progress" data-reading-progress>
  <aside class="reading-progress__toc" aria-label="Indice contenuto">
    <a href="#intro" data-reading-link class="is-active">Introduzione</a>
    <a href="#setup" data-reading-link>Setup</a>
    <a href="#checks" data-reading-link>Controlli</a>
    <button type="button" data-reading-top>Torna su</button>
  </aside>

  <article class="reading-progress__content" data-reading-scroller tabindex="0">
    <div class="reading-progress__bar" aria-hidden="true">
      <span data-reading-bar></span>
    </div>
    <section id="intro" data-reading-section><h2>Introduzione</h2><p>Primo blocco contenuto...</p></section>
    <section id="setup" data-reading-section><h2>Setup</h2><p>Secondo blocco contenuto...</p></section>
    <section id="checks" data-reading-section><h2>Controlli</h2><p>Terzo blocco contenuto...</p></section>
  </article>
</div>

<style>
.reading-progress {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  border: 1px solid #d8dde6;
  border-radius: 8px;
  overflow: hidden;
}
.reading-progress__toc {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: 1rem;
  background: #f7f9fc;
}
.reading-progress__toc a,
.reading-progress__toc button {
  border-radius: 6px;
  padding: .6rem .7rem;
  text-align: left;
}
.reading-progress__toc a.is-active {
  background: #e8f3ff;
  color: #075985;
  font-weight: 700;
}
.reading-progress__toc button {
  border: 1px solid #0f766e;
  background: #123743;
  color: #f8fbff;
  cursor: pointer;
  font-weight: 800;
  margin-top: auto;
}
.reading-progress__toc button:hover,
.reading-progress__toc button:focus-visible {
  background: #a8f0df;
  border-color: #0f766e;
  color: #10201f;
}
.reading-progress__content {
  max-height: 480px;
  overflow: auto;
  position: relative;
}
.reading-progress__bar {
  position: sticky;
  top: 0;
  height: 6px;
  background: #e5e7eb;
}
.reading-progress__bar span {
  display: block;
  height: 100%;
  background: #0ea5e9;
  transform: scaleX(0);
  transform-origin: left center;
}
.reading-progress__content section {
  min-height: 340px;
  padding: 1.5rem;
}
@media (max-width: 760px) {
  .reading-progress { grid-template-columns: 1fr; }
}
</style>

<script>
function initReadingProgress(rootSelector = '[data-reading-progress]') {
  const root = document.querySelector(rootSelector);
  if (!root) return;

  const scroller = root.querySelector('[data-reading-scroller]');
  const bar = root.querySelector('[data-reading-bar]');
  const links = [...root.querySelectorAll('[data-reading-link]')];
  const sections = [...root.querySelectorAll('[data-reading-section]')];

  function sectionTop(section) {
    return section.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
  }

  function update() {
    const max = Math.max(1, scroller.scrollHeight - scroller.clientHeight);
    bar.style.transform = 'scaleX(' + scroller.scrollTop / max + ')';

    let active = sections[0];
    const readingLine = scroller.scrollTop + scroller.clientHeight * 0.45;

    sections.forEach((section) => {
      if (sectionTop(section) <= readingLine) active = section;
    });

    if (scroller.scrollTop >= max - 2) active = sections[sections.length - 1];

    links.forEach((link) => {
      link.classList.toggle('is-active', link.getAttribute('href') === '#' + active.id);
    });
  }

  links.forEach((link) => {
    link.addEventListener('click', (event) => {
      const target = root.querySelector(link.getAttribute('href'));
      if (!target) return;
      event.preventDefault();
      scroller.scrollTo({ top: sectionTop(target) - 12, behavior: 'smooth' });
    });
  });

  root.querySelector('[data-reading-top]')?.addEventListener('click', () => {
    scroller.scrollTo({ top: 0, behavior: 'smooth' });
  });

  scroller.addEventListener('scroll', update, { passive: true });
  update();
}

initReadingProgress();
</script>
            

2. Card contenuto riusabile


<article class="content-card" data-content-card>
  <div class="content-card__topline">
    <span class="content-card__badge">Guida</span>
    <button class="content-card__save" type="button" data-card-save aria-pressed="false">
      Salva
    </button>
  </div>

  <h2>Accessibilita web base</h2>
  <p>Checklist essenziale per focus, testi alternativi, contrasto e navigazione da tastiera.</p>

  <dl class="content-card__meta">
    <div><dt>Tempo</dt><dd>18 min</dd></div>
    <div><dt>Livello</dt><dd>Base</dd></div>
  </dl>

  <a class="content-card__link" href="#">Apri risorsa</a>
</article>

<style>
.content-card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 360px;
  padding: 1rem;
  border: 1px solid #d8dde6;
  border-top: 4px solid #14b8a6;
  border-radius: 8px;
  background: #fff;
  color: #172033;
}
.content-card__topline {
  display: flex;
  justify-content: space-between;
  gap: .75rem;
  align-items: center;
}
.content-card__badge {
  color: #64748b;
  font-size: .75rem;
  font-weight: 800;
  text-transform: uppercase;
}
.content-card__save {
  border: 1px solid #cbd5e1;
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
  padding: .45rem .7rem;
}
.content-card__save[aria-pressed="true"] {
  background: #fff7ed;
  border-color: #fb923c;
  color: #c2410c;
}
.content-card h2 { margin: 0; font-size: 1.35rem; line-height: 1.2; }
.content-card p { margin: 0; color: #475569; line-height: 1.6; }
.content-card__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .65rem;
  margin: auto 0 0;
}
.content-card__meta div { background: #f8fafc; border-radius: 6px; padding: .7rem; }
.content-card__meta dt { color: #64748b; font-size: .72rem; font-weight: 800; text-transform: uppercase; }
.content-card__meta dd { margin: .2rem 0 0; font-weight: 800; }
.content-card__link {
  display: inline-flex;
  justify-content: center;
  border-radius: 6px;
  border: 1px solid #0f766e;
  background: #123743;
  color: #f8fbff;
  font-weight: 800;
  padding: .75rem .9rem;
  text-decoration: none;
}
.content-card__link:hover,
.content-card__link:focus-visible {
  background: #a8f0df;
  border-color: #0f766e;
  color: #10201f;
}
</style>

<script>
document.querySelectorAll('[data-card-save]').forEach((button) => {
  button.addEventListener('click', () => {
    const active = button.getAttribute('aria-pressed') === 'true';
    button.setAttribute('aria-pressed', String(!active));
  });
});
</script>
            

3. Header responsive accessibile


<nav class="site-header" data-accessible-header aria-label="Navigazione principale">
  <a class="site-header__brand" href="/">Brand</a>

  <button class="site-header__toggle" type="button" data-header-toggle
    aria-controls="site-header-menu" aria-expanded="false">
    Menu
  </button>

  <ul class="site-header__menu" id="site-header-menu" data-header-menu>
    <li><a href="/" data-header-link aria-current="page">Home</a></li>
    <li><a href="/risorse/" data-header-link>Risorse</a></li>
    <li><a href="/progetti/" data-header-link>Progetti</a></li>
    <li><a href="/contatti/" data-header-link>Contatti</a></li>
  </ul>
</nav>

<style>
.site-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4rem;
  padding: .85rem 1rem;
  background: #172033;
  color: #fff;
}
.site-header__brand,
.site-header__menu a {
  color: inherit;
  text-decoration: none;
}
.site-header__brand { font-weight: 900; }
.site-header__menu {
  display: flex;
  gap: .25rem;
  align-items: center;
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-header__menu a {
  display: inline-flex;
  border-radius: 999px;
  padding: .55rem .75rem;
  font-weight: 700;
}
.site-header__menu a:hover,
.site-header__menu a:focus-visible,
.site-header__menu a[aria-current="page"] {
  background: rgba(255, 255, 255, .12);
}
.site-header__toggle {
  display: none;
  border: 1px solid rgba(255, 255, 255, .24);
  border-radius: 999px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font: inherit;
  font-weight: 800;
  padding: .55rem .75rem;
}
.site-header a:focus-visible,
.site-header button:focus-visible {
  outline: 2px solid #67e8f9;
  outline-offset: 3px;
}
@media (max-width: 720px) {
  .site-header { flex-wrap: wrap; }
  .site-header__toggle { display: inline-flex; }
  .site-header__menu {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
    padding-top: .75rem;
  }
  .site-header.is-open .site-header__menu { display: flex; }
  .site-header__menu a { border-radius: 6px; width: 100%; }
}
</style>

<script>
function initAccessibleHeader(selector = '[data-accessible-header]') {
  const header = document.querySelector(selector);
  if (!header) return;

  const toggle = header.querySelector('[data-header-toggle]');
  const links = [...header.querySelectorAll('[data-header-link]')];

  function setOpen(open) {
    header.classList.toggle('is-open', open);
    toggle.setAttribute('aria-expanded', String(open));
  }

  toggle.addEventListener('click', (event) => {
    event.stopPropagation();
    setOpen(toggle.getAttribute('aria-expanded') !== 'true');
  });

  links.forEach((link) => link.addEventListener('click', () => setOpen(false)));
  document.addEventListener('click', (event) => {
    if (!header.contains(event.target)) setOpen(false);
  });
  document.addEventListener('keydown', (event) => {
    if (event.key === 'Escape') setOpen(false);
  });
}

initAccessibleHeader();
</script>
            

4. Form contatto con validazione


<form class="contact-form" data-contact-form novalidate>
  <div class="field">
    <label for="name">Nome</label>
    <input id="name" name="name" required minlength="2" data-validate="name"
      aria-describedby="name-error" aria-invalid="false">
    <p class="error" id="name-error"></p>
  </div>

  <div class="field">
    <label for="email">Email</label>
    <input id="email" name="email" type="email" required data-validate="email"
      aria-describedby="email-error" aria-invalid="false">
    <p class="error" id="email-error"></p>
  </div>

  <div class="field">
    <label for="message">Messaggio</label>
    <textarea id="message" name="message" required minlength="12" data-validate="message"
      aria-describedby="message-error" aria-invalid="false"></textarea>
    <p class="error" id="message-error"></p>
  </div>

  <button type="submit" data-submit-button>Invia richiesta</button>
  <p class="status" data-form-status role="status" aria-live="polite"></p>
</form>

<style>
.contact-form {
  display: grid;
  gap: 1rem;
  max-width: 520px;
  padding: 1rem;
  border: 1px solid #d8dde6;
  border-radius: 8px;
}
.field { display: grid; gap: .4rem; }
.field label { font-weight: 800; }
.field input,
.field textarea {
  width: 100%;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  font: inherit;
  padding: .75rem .8rem;
}
.field textarea { min-height: 8rem; resize: vertical; }
.field input:focus,
.field textarea:focus {
  border-color: #0ea5e9;
  box-shadow: 0 0 0 3px rgba(14, 165, 233, .18);
  outline: 0;
}
.field [aria-invalid="true"] { border-color: #ef4444; }
.error { min-height: 1.2rem; margin: 0; color: #b91c1c; font-size: .9rem; }
.status { margin: 0; color: #047857; font-weight: 700; }
button[type="submit"] {
  border: 0;
  border-radius: 6px;
  background: #0f172a;
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-weight: 800;
  padding: .8rem 1rem;
}
button[disabled] { cursor: wait; opacity: .7; }
</style>

<script>
function initValidatedContactForm(selector = '[data-contact-form]') {
  const form = document.querySelector(selector);
  if (!form) return;

  const fields = [...form.querySelectorAll('[data-validate]')];
  const status = form.querySelector('[data-form-status]');
  const submit = form.querySelector('[data-submit-button]');

  function getMessage(field) {
    const value = field.value.trim();
    if (field.required && !value) return 'Campo obbligatorio.';
    if (field.type === 'email' && !field.validity.valid) return 'Inserisci una email valida.';
    if (field.minLength > 0 && value.length < field.minLength) {
      return 'Inserisci almeno ' + field.minLength + ' caratteri.';
    }
    return '';
  }

  function validate(field) {
    const error = document.getElementById(field.id + '-error');
    const message = getMessage(field);
    field.setAttribute('aria-invalid', message ? 'true' : 'false');
    if (error) error.textContent = message;
    return !message;
  }

  fields.forEach((field) => {
    field.addEventListener('input', () => validate(field));
    field.addEventListener('blur', () => validate(field));
  });

  form.addEventListener('submit', (event) => {
    event.preventDefault();
    const valid = fields.map(validate).every(Boolean);
    if (!valid) {
      fields.find((field) => field.getAttribute('aria-invalid') === 'true')?.focus();
      status.textContent = 'Controlla i campi evidenziati.';
      return;
    }

    submit.disabled = true;
    submit.textContent = 'Invio in corso';
    status.textContent = "Messaggio pronto per l'invio.";
  });
}

initValidatedContactForm();
</script>