Creazione di frammenti Emmet personalizzati in VS Code
Pubblicato: 2022-03-10 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.
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:
- Crea un file snippets.json , aggiungi questa struttura JSON di base e salvala da qualche parte sul tuo disco rigido.
{ "html": { "snippets": { } }, "css": { "snippets": { } } }
- Apri le impostazioni del codice VS (Codice → Preferenze → Impostazioni) e cerca "Percorso estensioni Emmet".
- 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 ©
.
{${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>
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.
- Piccolo
- medio
- 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.
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 tagtheme-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.
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};"
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