Creazione di frammenti Emmet personalizzati in VS Code

Pubblicato: 2022-03-10
Riepilogo rapido ↬ In questo articolo, Manuel spiega perché Emmet è uno dei suoi strumenti di produttività preferiti per la scrittura di HTML e CSS e come puoi creare snippet Emmet personalizzati in Visual Studio Code per migliorare ulteriormente i flussi di lavoro front-end.

All'inizio di quest'anno, ho condiviso lo standard HTML che mi piace usare quando inizio nuovi progetti web con spiegazioni riga per riga sul mio blog. È una raccolta di tag e attributi principalmente <head> che di solito utilizzo su ogni sito Web che creo. Fino a poco tempo, copiavo e incollavo semplicemente il boilerplate ogni volta che ne avevo bisogno, ma ho deciso di migliorare il mio flusso di lavoro aggiungendolo come snippet a VS Code, l'editor di mia scelta.

Ecco una rapida demo degli snippet personalizzati che ho creato.

Snippet e abbreviazioni nel codice di Visual Studio

VS Code è integrato con frammenti utente personalizzati e frammenti e abbreviazioni HTML e CSS forniti da Emmet.

Ad esempio, se digiti p>a{Sign Up} in un documento HTML e premi Invio o Tab , Emmet lo trasformerà nel seguente markup:

 <p><a href="">Sign Up</a></p>

Nota : visita i documenti di Emmet per imparare a usare la sintassi delle abbreviazioni.

Se abbiamo bisogno regolarmente di questa specifica abbreviazione, possiamo salvarla come snippet per migliorare ulteriormente il nostro flusso di lavoro.

 { "html": { "snippets": { "signup": "p>a{Sign Up}" } } }

Ora possiamo digitare signup e premere Invio o Tab e otterremo lo stesso risultato. Spiegherò come creare frammenti nella prossima sezione.

Emmet viene fornito con un sacco di frammenti di codice HTML per impostazione predefinita. Ad esempio, ! crea la struttura di base di un documento HTML.

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> </body> </html>

È fantastico, ma se vogliamo adattare questo snippet rimuovendo o aggiungendo elementi e attributi, dobbiamo sovrascriverlo e creare il nostro snippet.

Creazione e sovrascrittura di frammenti

Se vogliamo creare i nostri frammenti di Emmet o sovrascrivere quelli esistenti in VS Code, sono necessari i seguenti passaggi:

  1. Crea un file snippets.json , aggiungi questa struttura JSON di base e salvala da qualche parte sul tuo disco rigido.
     { "html": { "snippets": { } }, "css": { "snippets": { } } }
  2. Apri le impostazioni del codice VS (Codice → Preferenze → Impostazioni) e cerca "Percorso estensioni Emmet".
  3. Fai clic su "Aggiungi elemento", inserisci il percorso della cartella in cui hai salvato il file snippets.json che hai creato in precedenza e premi "OK".

Questo è tutto. Ora siamo pronti per creare snippet aggiungendo proprietà agli oggetti html e css dove la key è il nome dello snippet e il value un'abbreviazione o una stringa.

Alcuni dei miei frammenti HTML personalizzati

Prima di approfondire la creazione di snippet e mostrarti come ho creato uno snippet per il mio boilerplate HTML, scaldiamoci prima con alcuni piccoli ma utili snippet che ho creato.

Caricamento pigro

Fuori dagli schemi, c'è un'abbreviazione img , ma non ce n'è per le immagini caricate pigramente. Possiamo utilizzare l'abbreviazione predefinita e aggiungere semplicemente gli attributi aggiuntivi e i valori degli attributi di cui abbiamo bisogno tra parentesi quadre.

 { "html": { "snippets": { "img:l": "img[width height loading='lazy']" } } }

img:l + Invio / Tab ora crea il seguente markup:

 <img src="" alt="" width="" height="" loading="lazy">

Pagina

La maggior parte delle pagine che creo sono costituite da <header> , <main> e <footer> punti di riferimento e da un <h1> . L'abbreviazione della page personalizzata mi consente di creare rapidamente quella struttura.

 "snippets": { "page": "header>h1^main+footer{${0:©}}" }

page + Invio / Tab crea il seguente markup:

 <header> <h1></h1> </header> <main></main> <footer>©</footer>

Quell'abbreviazione è piuttosto lunga, quindi scomponiamola in parti più piccole.

Guasto

Crea un elemento <header> e un figlio <h1> .

 header>h1

Spostati in alto, torna al livello di <header> e crea un <footer> che segua <main> .

 ^main+footer

Imposta il punto di tabulazione finale all'interno del <footer> e imposta il testo predefinito su &copy .

 {${0:©}}

Navigazione

L'abbreviazione nav crea solo un tag di inizio e fine <nav> per impostazione predefinita, ma quello di cui di solito ho bisogno è un <nav> con <ul> , <li> elementi e collegamenti nidificati ( <a> ). Se ci sono più elementi <nav> su una pagina, dovrebbero anche essere etichettati, ad esempio usando aria-label .

 "nav": "nav[aria-label='${1:Main}']>ul>(li>a[aria-current='page']{${2:Current Page}})+(li*3>a{${0:Another Page}})"

Sembra selvaggio, quindi analizziamolo di nuovo.

Guasto

Iniziamo con un elemento <nav> con un attributo aria-label e un <ul> annidato. ${1:Main} popola l'attributo con il testo "Principale" e crea un punto di tabulazione sul valore dell'attributo spostando il cursore su di esso ed evidenziandolo al momento della creazione.

 nav[aria-label='${1:Main}']>ul

Quindi creiamo quattro voci di elenco con collegamenti nidificati. Il primo elemento è speciale perché contrassegna la pagina attiva usando aria-current="page" . Creiamo un altro punto di tabulazione e popola il collegamento con il testo "Pagina corrente".

 (li>a[aria-current='page']>{${2:Current Page}})

Infine, aggiungiamo altre tre voci di elenco con collegamenti e il testo del collegamento "Un'altra pagina".

 (li*3>a>{${0:Another Page}})

Prima dei nostri adattamenti, abbiamo ottenuto questo:

 <-- Before: nav + TAB/Enter --> <nav></nav>

Ora otteniamo questo:

 <-- After: nav + TAB/Enter --> <nav aria-label="Main"> <ul> <li><a href="" aria-current="page">Current Page</a></li> <li><a href="">Another Page</a></li> <li><a href="">Another Page</a></li> <li><a href="">Another Page</a></li> </ul> </nav>
Altro dopo il salto! Continua a leggere sotto ↓

Stile

L'abbreviazione di style predefinita crea solo il tag di inizio e fine <style> , ma di solito quando utilizzo l'elemento <style> lo faccio perché voglio testare o eseguire rapidamente il debug di qualcosa.

Aggiungiamo alcune regole predefinite al tag <style> :

 "style": "style>{\\* { box-sizing: border-box; \\}}+{\n${1:*}:focus \\{${2: outline: 2px solid red; }\\} }+{\n${0}}"

Guasto

Alcuni caratteri (ad esempio $ , * , { o } ) devono essere sottoposti a escape utilizzando \\ .

 style>{\\* { box-sizing: border-box; \\}}

\n crea un'interruzione di riga e ${1:*} posiziona la prima tabulazione sul selettore * .

 {\n${1:*}:focus \\{${2: outline: 2px solid red; }\\}}
  • Prima : <style><style>
  • Dopo :
     <style> * { box-sizing: border-box; }
    *:focus { outline: 2px solid red; } </style>

Va bene, abbastanza riscaldamento. Creiamo frammenti complessi. All'inizio volevo creare un singolo snippet per il mio boilerplate, ma ho creato tre abbreviazioni che soddisfano esigenze diverse.

  1. Piccolo
  2. medio
  3. Completo

Piastra Caldaia Piccola

Questo è un boilerplate per demo veloci, crea quanto segue:

  • Struttura di base del sito,
  • meta tag viewport ,
  • Titolo della pagina,
  • elemento <style> ,
  • A <h1> .
 { "!": "{<!DOCTYPE html>}+html[lang=${1}${lang}]>(head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)+body>(h1>{${3: New Document}})+{${0}}" }

Guasto

Una stringa con il doctype:

 {<!DOCTYPE html>}

L'elemento <html> con un attributo lang . Il valore dell'attributo lang è una variabile che puoi modificare nelle impostazioni del codice VS (Codice → Preferenze → Impostazioni).

 html[lang=${1}${lang}]

Puoi modificare la lingua naturale predefinita della pagina cercando "variabili emmet" nelle impostazioni di VS Code e modificando la variabile lang . Puoi anche aggiungere le tue variabili personalizzate qui.

Ci sono 2 variabili predefinite in VS Code, lang è impostato su en e charset su UTF-8.

Il <head> include il meta tag charset , il meta tag viewport , il tag <title> e <style> . {} crea una nuova riga.

 (head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)

Diamo una prima rapida occhiata a ciò che questo ci offre.

 <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>New document</title> </head> </html>

Sembra a posto, ma l'abbreviazione meta:utf crea il vecchio modo in HTML per definire il charset e meta:vp crea due tabulazioni di cui non ho bisogno perché non uso mai un'impostazione diversa per il viewport .

Sovrascriviamo questi frammenti prima di andare avanti.

 { "meta:vp": "meta[name=viewport content='width=device-width, initial-scale=1']", "meta:utf": "meta[charset=${charset}]" }

Ultimo ma non meno importante, l'elemento <body> , un <h1> con testo predefinito, seguito dal punto di tabulazione finale.

 body>(h1>{${3: New Document}})+{${0}}

La targa finale:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>New document</title> <style> * { box-sizing: border-box; } *:focus { outline: 2px solid red; } </style> </head> <body> <h1> New Document</h1> </body> </html>

Per me, questa è la configurazione di debug minima perfetta.

Caldaia media

Mentre utilizzo il primo boilerplate solo per demo veloci, il secondo boilerplate può essere utilizzato per pagine complesse. Lo snippet crea quanto segue:

  • Struttura di base del sito,
  • meta tag viewport ,
  • Titolo della pagina,
  • classi .no-js / .js ,
  • Schermi esterni e fogli di stile di stampa,
  • description e meta tag theme-color ,
  • Struttura della pagina.
 { "!!": "{<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{<!-- TODO: Check lang attribute --> }+(head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}+(script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}+link:css+link:print+{}+meta[name=\"description\"][content=\"${2: Change me (up to ~155 characters)}\"]+{<!-- TODO: Change page description --> }+meta[name=\"theme-color\"][content=\"${2:#FF00FF}\"])+body>page" }

Sì, lo so, sembra incomprensibile. Analizziamolo.

Guasto

Il doctype e l'elemento root sono come nel primo esempio, ma con una classe no-js aggiuntiva e un commento che mi ricorda di cambiare l'attributo lang , se necessario.

 {<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{ }

L'estensione TODO Highlight rende il commento davvero pop.

L'estensione mette in evidenza alcune parole chiave come TODO visivamente.

Il <head> include il meta tag charset , il meta tag viewport , <title> . {} crea una nuova riga.

 (head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}

Uno script con una riga di JavaScript. Sto tagliando la senape al supporto del modulo JS. Se un browser supporta moduli JavaScript, significa che è un browser che supporta JavaScript moderno (ad esempio moduli, sintassi ES 6, fetch e così via). Spedisco la maggior parte dei JS solo a questi browser e utilizzo la classe js in CSS, se lo stile di un componente è diverso, quando JavaScript è attivo.

 (script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}

Due elementi <link> ; il primo si collega al foglio di stile principale e il secondo a un foglio di stile di stampa.

 link:css+link:print+{}

La descrizione della pagina:

 meta[name=\"description\"\][content=\"${2: Change me (up to ~155 characters)}\"]+{ }

Il meta tag theme-color :

 meta[name=\"theme-color\"\][content=\"${2:#FF00FF}\"])

L'elemento body e la struttura di base della pagina:

 body>page

Il boilerplate finale si presenta così:

 <!DOCTYPE html> <html lang="en" class="no-js"> <!-- TODO: Check lang attribute --> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title> Change me</title> <script type="module"> document.documentElement.classList.replace('no-js', 'js'); </script> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="print.css" media="print"> <meta name="description" content=" Change me (up to ~155 characters)"> <!-- TODO: Change page description --> <meta name="theme-color" content="#FF00FF"> </head> <body> <header> <h1></h1> </header> <main></main> <footer>©</footer> </body> </html>

Piastra Caldaia Piena

Il boilerplate completo è simile al secondo boilerplate; le differenze sono meta tag aggiuntivi e un tag script .

Lo snippet crea quanto segue:

  • Struttura di base del sito,
  • meta tag viewport ,
  • Titolo della pagina,
  • classi js / no-js ,
  • Schermi esterni e fogli di stile di stampa,
  • description e meta tag del grafico aperto,
  • meta tag theme-color ,
  • canonico <link> tag,
  • tag Favicon,
  • struttura della pagina,
  • tag < script> .
 { "!!!": "{<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{<!-- TODO: Check lang attribute --> }+(head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}+(script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}+link:css+link:print+{}+meta[property=\"og:title\"][content=\"${1: Change me}\"]+meta[name=\"description\"][content=\"${2: Change me (up to ~155 characters)}\"]+meta[property=\"og:description\"][content=\"${2: Change me (up to ~155 characters)}\"]+meta[property=\"og:image\"][content=\"${1:https://}\"]+meta[property=\"og:locale\"][content=\"${1:en_GB}\"]+meta[property=\"og:type\"][content=\"${1:website}\"]+meta[name=\"twitter:card\"][content=\"${1:summary_large_image}\"]+meta[property=\"og:url\"][content=\"${1:https://}\"]+{<!-- TODO: Change social media stuff --> }+{}+link[rel=\"canonical\"][href=\"${1:https://}\"]+{<!-- TODO: Change canonical link --> }+{}+link[rel=\"icon\"][href=\"${1:/favicon.ico}\"]+link[rel=\"icon\"][href=\"${1:/favicon.svg}\"][type=\"image/svg+xml\"]+link[rel=\"apple-touch-icon\"][href=\"${1:/apple-touch-icon.png}\"]+link[rel=\"manifest\"][href=\"${1:/my.webmanifest}\"]+{}+meta[name=\"theme-color\"][content=\"${2:#FF00FF}\"])+body>page+{}+script:src[type=\"module\"]" }

Questo frammento incredibilmente lungo crea questo:

 <!DOCTYPE html> <html lang="en" class="no-js"> <!-- TODO: Check lang attribute --> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title> Change me</title> <script type="module"> document.documentElement.classList.replace('no-js', 'js'); </script> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="print.css" media="print"> <meta property="og:title" content=" Change me"> <meta name="description" content=" Change me (up to ~155 characters)"> <meta property="og:description" content=" Change me (up to ~155 characters)"> <meta property="og:image" content="https://"> <meta property="og:locale" content="en_GB"> <meta property="og:type" content="website"> <meta name="twitter:card" content="summary_large_image"> <meta property="og:url" content="https://"> <!-- TODO: Change social media stuff --> <link rel="canonical" href="https://"> <!-- TODO: Change canonical link --> <link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/apple-touch-icon.png"> <link rel="manifest" href="/my.webmanifest"> <meta name="theme-color" content="#FF00FF"> </head> <body> <header> <h1></h1> </header> <main></main> <footer>©</footer> <script src="" type="module"></script> </body> </html>

Snippet CSS personalizzati

Per completezza, ecco alcuni dei frammenti CSS che sto usando.

Debug

Questo frammento crea un contorno rosso di 5px con un offset personalizzato.

 "debug": "outline: 5px solid red;\noutline-offset: -5px;"

Centraggio

Uno snippet che imposta la display su flex e centra gli elementi figlio.

 "center": "display: flex;\njustify-content: center;\nalign-items: center;"

Appiccicoso

Imposta la proprietà position su sticky , con due punti di tabulazione nella proprietà in top e a left .

 "sticky": "position: sticky;\ntop: ${1:0};\nleft: ${2:0};" 
Una dimostrazione di tutti e 3 i frammenti CSS applicati a un elemento div .

Snippet utente

All'inizio di questo articolo, ho menzionato che VS Code fornisce anche frammenti personalizzati. La differenza rispetto ai frammenti di Emmet è che non puoi utilizzare abbreviazioni, ma puoi anche definire punti di tabulazione e utilizzare variabili interne.

Come ottenere il meglio dagli snippet utente potrebbe essere un argomento per un altro articolo, ma ecco un esempio di uno snippet CSS personalizzato che ho definito:

 "Visually hidden": { "prefix": "vh", "body": [ ".u-vh {", " position: absolute;\n white-space: nowrap;\n width: 1px;\n height: 1px;\n overflow: hidden;\n border: 0;\n padding: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n margin: -1px;", "}" ], "description": "A utility class for screen reader accessible hiding." }

Questo snippet non crea solo regole CSS, ma un intero blocco di dichiarazione quando vh e premiamo Invio o Tab .

 .u-vh { position: absolute; white-space: nowrap; width: 1px; height: 1px; overflow: hidden; border: 0; padding: 0; clip: rect(0 0 0 0); clip-path: inset(50%); margin: -1px; }

Parole finali

Ci vuole del tempo per creare questi frammenti, ma ne vale la pena perché puoi personalizzare Emmet in base alle tue preferenze personali, automatizzare le attività ripetitive e risparmiare tempo a lungo termine.

Mi piacerebbe vedere quali snippet usi, quindi condividili con noi nei commenti. Se vuoi usare le mie impostazioni, puoi trovare il mio snippets.json finale su GitHub.

Risorse

  • Snippet CSS Emmet predefiniti
  • Snippet HTML Emmet predefiniti
  • Cheat sheet di Emmet
  • Emmet nei documenti VS Code