Vai al contenuto
Allin

Le liste di attività in Markdown e cosa viene reso davvero e dove

Pubblicato il 02/07/2025 · 12 min di lettura · Strumenti testo e lingua

Daniel Okonkwo

Daniel OkonkwoSviluppatore front-end e redattore Tech presso Allin

Performance web · Formati di file

Verificato su 4 fonti

Vedi il profilo
In breve

Una lista di attività in Markdown — un elemento di elenco che inizia con [ ] o [x] — non fa parte di CommonMark. Abbiamo cercato nella specifica CommonMark 0.31.2 del 28 gennaio 2024: le espressioni «task list» e «checkbox» vi compaiono zero volte. Le liste di attività sono definite nella specifica GitHub Flavored Markdown 0.29-gfm del 6 aprile 2019, sezione 5.3, come estensione. È tutta qui la spiegazione del fatto che lo stesso file mostri caselle su GitHub e parentesi quadre letterali altrove. Abbiamo passato una riga, «- [ ] comprare il latte», per quattro motori: solo quello di sapore GitHub ha prodotto un elemento input di tipo checkbox; l'implementazione di riferimento CommonMark e altre due configurazioni hanno prodotto un elemento di elenco con il testo letterale [ ] comprare il latte. La regola del marcatore è esatta e poco indulgente: una sequenza facoltativa di spazi, una parentesi quadra aperta, o uno spazio o la lettera x in qualunque cassa, una parentesi quadra chiusa, e poi almeno uno spazio prima del contenuto. «- [x]comprare» senza spazio esce come testo ovunque, «- []» esce come testo e «- [ ]» con due spazi pure. La stessa prudenza vale per tabelle, testo barrato e collegamenti automatici, anch'essi estensioni, e per le note a piè di pagina, che non stanno in nessuna delle due specifiche.

Le liste di attività non sono in CommonMark. Sono un'estensione di GitHub Flavored Markdown, ed è per questo che lo stesso file mostra caselle in un posto e parentesi quadre letterali in un altro. La regola esatta del marcatore, cosa fa l'annidamento e una tabella di cosa è CommonMark, cosa è GFM e cosa non è nessuno dei due — verificato su entrambe le specifiche e quattro motori di resa.

Una riga, quattro motori, due documenti diversi

Abbiamo preso una sola riga — un trattino, uno spazio, una coppia di parentesi quadre vuota, uno spazio e del testo — e l'abbiamo resa in quattro modi. Con l'analisi di sapore GitHub attiva diventa un elemento di elenco con un elemento input di tipo checkbox, disabilitato. Con la stessa libreria e il sapore spento, con l'implementazione di riferimento CommonMark e con una terza libreria nella sua configurazione predefinita, diventa un elemento di elenco con i caratteri [ ] seguiti dal testo. Nulla è fallito. Quattro motori corretti hanno prodotto due documenti diversi dallo stesso file.

La ragione è documentata, non misteriosa. Abbiamo cercato «task list» e «checkbox» nella specifica CommonMark 0.31.2 del 28 gennaio 2024: entrambe compaiono zero volte. La specifica GitHub Flavored Markdown 0.29-gfm del 6 aprile 2019 ha una sezione 5.3 intitolata «Task list items (extension)». La parola estensione fa tutto il lavoro in quel titolo: GFM è CommonMark più cinque aggiunte con nome, e un motore che implementa solo CommonMark non è rotto quando stampa le tue caselle come parentesi. È corretto.

La regola del marcatore, carattere per carattere

La sezione 5.3 di GFM definisce un elemento di lista di attività come un elemento il cui primo blocco è un paragrafo che inizia con un marcatore di lista di attività seguito da almeno uno spazio prima di qualsiasi altro contenuto. Il marcatore è un numero facoltativo di spazi, una parentesi quadra aperta, o uno spazio o la lettera x in minuscolo o maiuscolo, e una parentesi quadra chiusa. Ogni parola di quella frase porta peso, e i fallimenti sono silenziosi: abbiamo eseguito ogni violazione e tutte sono uscite come testo ordinario in tutti e quattro i motori.

Ometti lo spazio dopo la parentesi di chiusura e non succede nulla: «- [x]comprare il latte» è testo. Metti due spazi fra le parentesi e non succede nulla: il marcatore contiene esattamente un carattere. Lascia le parentesi vuote e non succede nulla. Usa una lettera diversa da x e non succede nulla. Sposta il marcatore dall'inizio del paragrafo — «- comprare [ ] il latte» — e non succede nulla. Togli l'elenco e «[ ] comprare il latte» è un paragrafo. Ciò che funziona è più generoso di quanto si creda: la lettera può essere una X maiuscola, il segno di elenco può essere un trattino, un asterisco o un più, l'elenco può essere numerato, e una tabulazione conta come lo spazio dopo la parentesi.

L'annidamento e la regola del primo blocco

Le liste di attività si annidano liberamente, e la specifica lo mostra con un esempio svolto. Abbiamo eseguito un elemento padre con due figli indentati: casella sul padre, elenco annidato dentro lo stesso elemento e casella su ogni figlio. Anche mescolare elementi spuntati, non spuntati e semplici punti elenco nella stessa lista funziona: l'elemento semplice resta semplice e quelli marcati diventano caselle, il che rende una checklist leggibile come un ordine del giorno misto.

Il requisito che il primo blocco sia un paragrafo si viola facilmente. Metti una citazione all'inizio — «- > [ ] citato» — e nessun motore produce una casella, incluso quello di sapore GitHub, perché il primo blocco è una citazione e il marcatore non ha mai la sua occasione. Aggiungi un secondo paragrafo dopo quello marcato e la casella sopravvive, collocata prima del primo paragrafo, con il secondo che segue nello stesso elemento. Non sono stranezze del motore: discendono direttamente dalla frase della sezione 5.3.

Le estensioni vicine, e una che non è in nessuna specifica

Le tabelle sono la sezione 4.10 della specifica GFM, anch'esse un'estensione. La nostra tabella a barre di tre righe è uscita come vero elemento table sotto l'analisi di sapore GitHub e sotto le impostazioni predefinite di un'altra libreria, e come un unico paragrafo di barre letterali sotto l'implementazione di riferimento CommonMark. Il barrato è la sezione 6.5, ed è più strano di quanto sembri: la specifica ammette una o due tilde, quindi ~qui~ è barrato, ma tre o più no, quindi ~~~no~~~ resta letterale. Una libreria testata barrava con due tilde ma non con una, ed emetteva un elemento di testo barrato invece dell'elemento di testo eliminato mostrato dalla spec. GFM. Due motori possono entrambi supportare il barrato e continuare a non essere d'accordo sull'input e sull'output.

I collegamenti automatici esistono in due forme e solo una è nativa. Un indirizzo fra parentesi angolari è CommonMark ed è diventato un collegamento in ogni motore provato. Un indirizzo nudo è la sezione 6.9 di GFM, un'estensione con regole proprie: lo schema http viene inserito davanti a un indirizzo www e la punteggiatura finale resta fuori dal collegamento, così «Visita www.commonmark.org.» collega l'indirizzo e lascia fuori il punto. Solo la configurazione di sapore GitHub ha prodotto quei collegamenti; le altre hanno lasciato il testo com'era.

Le note a piè di pagina sono il caso istruttivo, perché non stanno in nessuna delle due specifiche. La parola footnote compare esattamente una volta nella spec. CommonMark ed esattamente una volta in quella GFM, nella stessa frase storica dell'introduzione sulle implementazioni che aggiunsero convenzioni per note e tabelle. Tutti e quattro i nostri motori hanno lasciato [^1] come testo letterale e trasformato la riga di definizione in un paragrafo orfano. GitHub stesso rende le note a piè di pagina, ed è esattamente questa la trappola: una funzione che hai visto funzionare non è per questo nel formato.

«Markdown» non è un formato

Due specifiche con numeri di versione diversi e cinque anni di distanza, più un insieme di opzioni per libreria, non fanno un formato unico. I disaccordi scendono ben sotto il livello delle funzioni. Di fronte a un ritorno a capo duro, due dei nostri motori hanno emesso un tag di interruzione autochiudente e due la forma HTML5. Di fronte a un elemento script nel sorgente, due l'hanno passato tale e quale all'output e uno l'ha mascherato come testo; la spec. GFM dedica un'intera estensione, la sezione 6.11, a filtrare nove tag precisi sostituendo la loro parentesi angolare di apertura con un'entità. Niente di tutto ciò è un bug.

La regola pratica che ne segue è breve: scrivi per il motore che davvero prendi di mira, e sappi quale sia. Un README su una piattaforma di codice, un generatore di siti di documentazione, un client di chat e un costruttore di siti statici sono quattro destinazioni con quattro insiemi di funzioni, e un documento che appare bene in una non offre alcuna garanzia sulle altre. Se la destinazione è ignota, resta dentro CommonMark: titoli, enfasi, elenchi, codice, collegamenti, collegamenti automatici fra parentesi angolari e citazioni sono uguali ovunque.

Verifica l'andata e ritorno, e conta dalla sorgente

Il test più economico di una checklist è l'aritmetica. Abbiamo scritto un elenco di sprint annidato da cinque elementi, due marcati come fatti, li abbiamo contati dalla sorgente markdown con un modello che riconosce il marcatore a inizio elemento e abbiamo ottenuto 2 su 5. Rendendo lo stesso documento con analisi di sapore GitHub e contando gli elementi input spuntati nell'HTML si ottiene ancora 2 su 5. Rendendolo con l'implementazione di riferimento CommonMark si ottengono zero elementi input — il documento è intatto, le caselle semplicemente non sono mai state una funzione di quel dialetto.

È questa l'abitudine da tenere: conta dalla sorgente, non dalla resa. Il file markdown è il registro; l'HTML ne è un'interpretazione, e quale ne ottieni dipende da una versione di libreria e da un flag. Il nostro generatore di checklist scrive il marcatore GFM esattamente come lo specifica la sezione 5.3 — punto elenco, spazio, parentesi, un carattere, parentesi, spazio — così il file funziona dove l'estensione è supportata e degrada a un elenco con parentesi leggibile dove non lo è. Se hai bisogno che la casella sopravviva ovunque, l'alternativa onesta è un elenco semplice con la parola «fatto» dentro.

Cosa definisce ciascuna specifica e cosa quattro motori hanno prodotto davvero, eseguiti in Node 26.3.0 con marked 18.0.7, l'implementazione di riferimento commonmark 0.31.2 e markdown-it 15.0.0 in due preset. «GFM» qui significa marked con gfm attivo; «markdown-it predefinito» è la sua configurazione di fabbrica.
FunzioneIn CommonMark 0.31.2?Nella spec. GFM 0.29?Output dell'implementazione di riferimentoOutput di markdown-it predefinito
Lista di attività - [ ] / - [x]No — 0 menzioniSì — sezione 5.3, estensione[ ] letterale nell'elemento di elenco[ ] letterale nell'elemento di elenco
Tabella con barreNoSì — sezione 4.10, estensioneUn paragrafo di barre letteraliUn vero elemento table
Barrato con due tildeNoSì — sezione 6.5, estensioneTilde letteraliUn elemento barrato, ma s invece di del
Barrato con una tildeNoSì — una o due tildeTilde letteraliTilde letterali — ne richiede due
URL nudo trasformato in collegamentoNoSì — sezione 6.9, estensioneTesto sempliceTesto semplice nelle configurazioni provate
Collegamento automatico fra parentesi angolariSì — parte della specifica di baseSì, ereditatoUn vero collegamentoUn vero collegamento
Nota a piè di pagina [^1]NoNo — nemmeno nella specifica[^1] letterale e una riga di definizione orfana[^1] letterale e una riga di definizione orfana
HTML grezzo lasciato passareSì, per defaultSì, meno nove tag filtratiPassato invariatoMascherato come testo
Generatore di checklist MarkdownTrasforma un elenco di righe in una lista di attività Markdown (- [ ] elemento).Prova lo strumento

Domande frequenti

Perché le mie caselle appaiono come [ ] invece che come caselle?
Perché il motore implementa CommonMark senza le estensioni GitHub. Le liste di attività sono la sezione 5.3 della spec. GFM e non compaiono da nessuna parte in CommonMark 0.31.2. La seconda possibilità è un marcatore malformato: lo spazio dopo la parentesi di chiusura è obbligatorio, fra le parentesi va esattamente un carattere, e il marcatore deve aprire il primo paragrafo dell'elemento. Tutti questi errori escono come testo letterale senza alcun avviso.
La x deve essere minuscola?
No. La spec. GFM dice la lettera x in minuscolo o maiuscolo, e abbiamo confermato che entrambe producono una casella spuntata. Nessun'altra lettera funziona: una o fra le parentesi è uscita come testo letterale in ogni motore provato. Nemmeno due caratteri sono ammessi — un marcatore con due spazi fra le parentesi non è un marcatore.
Le liste di attività si possono annidare o usare in un elenco numerato?
Entrambe. La spec. GFM mostra liste di attività annidate liberamente in un esempio svolto, e la nostra esecuzione ha prodotto una casella sul padre e su ogni figlio indentato. Un elemento di elenco numerato funziona allo stesso modo — il marcatore sta dopo il numero e il punto. Ciò che non funziona è un elemento il cui primo blocco non sia un paragrafo: una citazione prima del marcatore ha soppresso la casella in ogni motore.
Tabelle e barrato si possono usare ovunque?
No. Entrambe sono estensioni GFM, sezioni 4.10 e 6.5, e nessuna è in CommonMark. La nostra tabella è uscita come vera tabella in due configurazioni e come paragrafo di barre letterali in un'altra. Il barrato è peggio: la spec. GFM barra il testo racchiuso fra una o due tilde ma non fra tre, mentre un'altra libreria molto usata ne richiedeva due e produceva un elemento HTML diverso per il risultato.
Le note a piè di pagina fanno parte di GitHub Flavored Markdown?
Secondo la specifica GFM pubblicata, no. La parola footnote vi compare esattamente una volta, in una frase storica dell'introduzione, e non esiste alcuna sezione sulle note. Il sito di GitHub le rende comunque, il che illustra bene la differenza fra una specifica e un prodotto. Tutti e quattro i motori provati hanno lasciato il richiamo come testo letterale e la definizione come paragrafo orfano.

Articoli che potrebbero interessarti

Tutte le guide
GuidaConvertire fra formati di elenco senza perdere dati: le regole di virgolettatura che nessuno leggeTrasformare un elenco a capo in un elenco a virgole è banale finché un elemento non contiene una virgola. Le regole di virgolettatura della RFC 4180, perché un campo CSV può contenere un a capo, perché i fogli di calcolo europei usano il punto e virgola, e cosa fa un elemento vuoto all'andata e ritorno — ogni caso eseguito e stampato.GuidaTogliere il Markdown: che cosa perde il testo semplice, e che cosa sbaglia una regexUn link diventa testo con la destinazione cancellata, un elenco annidato perde la gerarchia, una tabella diventa una fila di parole. Poi la metà tecnica: il markdown non ha una sola specifica, e un ripulitore a base di regex rovina un nome di file, un segno di moltiplicazione e l'interno di un blocco di codice — tutto messo a confronto con un vero parser.SpiegazioneDove una riga può andare a capo: l'algoritmo Unicode dietro ogni paragrafo mandato a capo«Andare a capo sugli spazi» fallisce nella maggior parte dei sistemi di scrittura. UAX #14 assegna a ogni carattere una classe di interruzione di riga; abbiamo cercato le nostre in Unicode 17.0.0 ed eseguito un'implementazione conforme su spazi unificatori, trattini morbidi, spazi a larghezza zero, URL, giapponese e thai.TutorialFiltrare righe secondo uno schema, senza riga di comandoQuesto è grep per chi non usa grep, con una differenza importante: la ricerca è una sottostringa letterale, quindi una vera espressione regolare restituisce un riquadro vuoto e nessun errore. Ogni affermazione è stata verificata eseguendo lo strumento.SpiegazioneContare le parole è ambiguo, e ogni strumento risponde in modo diversoUn conteggio di parole è una definizione, non una misura. Abbiamo contato lo stesso paragrafo in quattro modi ottenendo 25, 28, 33 e 38; poi abbiamo contato 50.000 caratteri di prosa ordinaria ottenendo accordo entro il 4,5 %. Lo scarto dipende interamente da composti, cifre e URL.GuidaFormattare i numeri per sei lingue: separatori, valuta e il ritorno al valore1.234,56 e 1,234.56 sono lo stesso numero, e confonderli cambia il valore che un lettore legge. Abbiamo eseguito Intl.NumberFormat per tutte e sei le lingue del sito e stampato ogni separatore — compreso quello invisibile usato dal francese — e poi misurato perché parseFloat non può disfare nulla di tutto ciò.

Strumenti correlati

Fonti

Hai notato un errore in questo articolo?