Creación de fragmentos de Emmet personalizados en VS Code
Publicado: 2022-03-10 A principios de este año, compartí el modelo HTML que me gusta usar al iniciar nuevos proyectos web con explicaciones línea por línea en mi blog. Es una colección de etiquetas y atributos en su mayoría <head>
que suelo usar en cada sitio web que construyo. Hasta hace poco, simplemente copiaba y pegaba el texto modelo cada vez que lo necesitaba, pero decidí mejorar mi flujo de trabajo agregándolo como un fragmento a VS Code, el editor de mi elección.
Fragmentos y abreviaturas en el código de Visual Studio
VS Code viene integrado con fragmentos de código de usuario personalizados y fragmentos y abreviaturas de HTML y CSS proporcionados por Emmet.
Por ejemplo, si escribe p>a{Sign Up}
en un documento HTML y presiona Entrar o Tabulador , Emmet lo convertirá en el siguiente marcado:
<p><a href="">Sign Up</a></p>
Nota : Visite los documentos de Emmet para aprender a usar la sintaxis de abreviaturas.
Si necesitamos esta abreviatura específica regularmente, podemos guardarla como un fragmento para mejorar aún más nuestro flujo de trabajo.
{ "html": { "snippets": { "signup": "p>a{Sign Up}" } } }
Ahora podemos escribir signup
y presionar Enter o Tab y obtendremos el mismo resultado. Explicaré cómo crear fragmentos en la siguiente sección.
Emmet viene con un montón de fragmentos de código HTML de forma predeterminada. Por ejemplo, !
crea la estructura básica de 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>
Genial, pero si queremos adaptar este fragmento quitando o añadiendo elementos y atributos, tenemos que sobrescribirlo y crear nuestro propio fragmento.
Crear y sobrescribir fragmentos
Si queremos crear nuestros propios fragmentos de Emmet o sobrescribir los existentes en VS Code, son necesarios los siguientes pasos:
- Cree un archivo snippets.json , agregue esta estructura JSON básica y guárdela en algún lugar de su disco duro.
{ "html": { "snippets": { } }, "css": { "snippets": { } } }
- Abra la configuración de VS Code (Código → Preferencias → Configuración) y busque "Ruta de extensiones de Emmet".
- Haga clic en "Agregar elemento", ingrese la ruta a la carpeta donde guardó el archivo snippets.json que creó anteriormente y presione "Aceptar".
Eso es todo. Ahora estamos listos para crear fragmentos agregando propiedades a los objetos html
y css
donde la key
es el nombre del fragmento y el value
una abreviatura o una cadena.
Algunos de mis fragmentos HTML personalizados
Antes de profundizar en la creación de fragmentos y mostrarle cómo creé un fragmento para mi plantilla de HTML, vamos a calentar primero con algunos fragmentos pequeños pero útiles que también he creado.
Carga lenta
Fuera de la caja, hay una abreviatura img
, pero no hay ninguna para imágenes cargadas de forma diferida. Podemos usar la abreviatura predeterminada y simplemente agregar los atributos adicionales y los valores de atributo que necesitamos entre corchetes.
{ "html": { "snippets": { "img:l": "img[width height loading='lazy']" } } }
img:l
+ Enter / Tab ahora crea el siguiente marcado:
<img src="" alt="" width="" height="" loading="lazy">
Página
La mayoría de las páginas que creo consisten en puntos de referencia <header>
, <main>
y <footer>
y <h1>
. La abreviatura de page
personalizada me permite crear esa estructura rápidamente.
"snippets": { "page": "header>h1^main+footer{${0:©}}" }
page
+ Enter / Tab crea el siguiente marcado:
<header> <h1></h1> </header> <main></main> <footer>©</footer>
Esa abreviatura es bastante larga, así que vamos a dividirla en partes más pequeñas.
Desglose
Cree un elemento <header>
y un elemento secundario <h1>
.
header>h1
Suba, vuelva al nivel de <header>
y cree un <footer>
que siga a <main>
.
^main+footer
Establezca la tabulación final dentro del <footer>
y establezca el texto predeterminado en ©
.
{${0:©}}
Navegación
La abreviatura nav
solo crea una etiqueta de inicio y final <nav>
de forma predeterminada, pero lo que normalmente necesito es un <nav>
con elementos anidados <ul>
, <li>
y enlaces ( <a>
). Si hay varios elementos <nav>
en una página, también deben etiquetarse, por ejemplo, usando aria-label
.
"nav": "nav[aria-label='${1:Main}']>ul>(li>a[aria-current='page']{${2:Current Page}})+(li*3>a{${0:Another Page}})"
Eso parece salvaje, así que vamos a desglosarlo de nuevo.
Desglose
Comenzamos con un elemento <nav>
con un atributo aria-label
y un <ul>
anidado. ${1:Main}
rellena el atributo con el texto "Principal" y crea una tabulación en el valor del atributo moviendo el cursor hacia él y resaltándolo en el momento de la creación.
nav[aria-label='${1:Main}']>ul
Luego creamos cuatro elementos de lista con enlaces anidados. El primer elemento es especial porque marca la página activa usando aria-current="page"
. Creamos otra tabulación y completamos el enlace con el texto "Página actual".
(li>a[aria-current='page']>{${2:Current Page}})
Finalmente, agregamos tres elementos de lista más con enlaces y el texto del enlace "Otra página".
(li*3>a>{${0:Another Page}})
Antes de nuestras adaptaciones, tenemos esto:
<-- Before: nav + TAB/Enter --> <nav></nav>
Ahora obtenemos esto:
<-- 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>
Estilo
La abreviatura de style
predeterminada solo crea la etiqueta de inicio y finalización <style>
, pero generalmente cuando uso el elemento <style>
lo hago porque quiero probar o depurar algo rápidamente.
Agreguemos algunas reglas predeterminadas a la etiqueta <style>
:
"style": "style>{\\* { box-sizing: border-box; \\}}+{\n${1:*}:focus \\{${2: outline: 2px solid red; }\\} }+{\n${0}}"
Desglose
Algunos caracteres (por ejemplo, $
, *
, {
o }
) deben escaparse usando \\
.
style>{\\* { box-sizing: border-box; \\}}
\n
crea un salto de línea y ${1:*}
coloca la primera tabulación en el selector *
.
{\n${1:*}:focus \\{${2: outline: 2px solid red; }\\}}
- Antes :
<style><style>
- después de :
<style> * { box-sizing: border-box; }
*:focus { outline: 2px solid red; } </style>
Muy bien, suficiente calentamiento. Vamos a crear fragmentos complejos. Al principio, quería crear un solo fragmento para mi texto modelo, pero creé tres abreviaturas que satisfacen diferentes necesidades.
- Pequeña
- Medio
- Completo
Modelo pequeño
Este es un modelo para demostraciones rápidas, crea lo siguiente:
- Estructura básica del sitio,
- metaetiqueta de
viewport
gráfica, - Título de la página,
- elemento
<style>
, - Un
<h1>
.
{ "!": "{<!DOCTYPE html>}+html[lang=${1}${lang}]>(head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)+body>(h1>{${3: New Document}})+{${0}}" }
Desglose
Una cadena con el tipo de documento:
{<!DOCTYPE html>}
El elemento <html>
con un atributo lang
. El valor del atributo lang
es una variable que puede cambiar en la configuración del código VS (Código → Preferencias → Configuración).
html[lang=${1}${lang}]
Puede cambiar el idioma natural predeterminado de la página buscando "variables emmet" en la configuración de VS Code y cambiando la variable lang
. También puede agregar sus variables personalizadas aquí.
El <head>
incluye la metaetiqueta charset
, la metaetiqueta viewport
, <title>
y la etiqueta <style>
. {}
crea una nueva línea.
(head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)
Echemos un primer vistazo rápido a lo que esto nos da.
<!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>
Se ve bien, pero la abreviatura meta:utf
crea la forma antigua en HTML para definir el conjunto de charset
y meta:vp
crea dos tabulaciones que no necesito porque nunca uso una configuración diferente para la viewport
.
Sobreescribamos estos fragmentos antes de continuar.
{ "meta:vp": "meta[name=viewport content='width=device-width, initial-scale=1']", "meta:utf": "meta[charset=${charset}]" }
Por último, pero no menos importante, el elemento <body>
, un <h1>
con texto predeterminado, seguido de la tabulación final.
body>(h1>{${3: New Document}})+{${0}}
El repetitivo final:
<!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>
Para mí, esa es la configuración de depuración mínima perfecta.
Medio repetitivo
Si bien uso el primer modelo solo para demostraciones rápidas, el segundo modelo se puede usar para páginas complejas. El fragmento crea lo siguiente:
- Estructura básica del sitio,
- metaetiqueta de
viewport
gráfica, - Título de la página,
- Clases
.no-js
/.js
, - Hojas de estilo de pantalla e impresión externas,
-
description
y metaetiquetatheme-color
, - Estructura de la página.
{ "!!": "{<!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 sé, eso parece un galimatías. Vamos a diseccionarlo.
Desglose
El doctype
y el elemento raíz son como en el primer ejemplo, pero con una clase no-js
adicional y un comentario que me recuerda cambiar el atributo lang
, si es necesario.
{<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{ }
La extensión TODO Highlight hace que el comentario realmente destaque.
El <head>
incluye la metaetiqueta charset
, la metaetiqueta viewport
, <title>
. {}
crea una nueva línea.
(head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}
Un script con una línea de JavaScript. Estoy cortando la mostaza en el soporte del módulo JS. Si un navegador admite módulos de JavaScript, significa que es un navegador que admite JavaScript moderno (por ejemplo, módulos, sintaxis de ES 6, recuperación, etc.). Envío la mayoría de JS solo a estos navegadores, y uso la clase js
en CSS, si el estilo de un componente es diferente, cuando JavaScript está activo.
(script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}
Dos elementos <link>
; el primero enlaza con la hoja de estilo principal y el segundo con una hoja de estilo de impresión.
link:css+link:print+{}
La descripción de la página:
meta[name=\"description\"\][content=\"${2: Change me (up to ~155 characters)}\"]+{ }
La metaetiqueta theme-color
:
meta[name=\"theme-color\"\][content=\"${2:#FF00FF}\"])
El elemento del cuerpo y la estructura básica de la página:
body>page
El repetitivo final se ve así:
<!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>
Repetitivo completo
El modelo completo es similar al segundo modelo; las diferencias son etiquetas meta
adicionales y una etiqueta de secuencia de script
.
El fragmento crea lo siguiente:
- Estructura básica del sitio,
- metaetiqueta de
viewport
gráfica, - Título de la página,
- clases
js
/no-js
, - Hojas de estilo de pantalla e impresión externas,
-
description
y metaetiquetas de gráficos abiertos, - metaetiqueta
theme-color
, - etiqueta canónica
<link>
, - etiquetas de favoritos,
- Estructura de la página,
- etiqueta <
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\"]" }
Este fragmento increíblemente largo crea esto:
<!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>
Fragmentos de CSS personalizados
En aras de la exhaustividad, estos son algunos de los fragmentos de CSS que estoy usando.
depuración
Este fragmento crea un contorno rojo de 5 píxeles con un desplazamiento personalizado.
"debug": "outline: 5px solid red;\noutline-offset: -5px;"
Centrado
Un fragmento que configura la display
para flexionar y centra sus elementos secundarios.
"center": "display: flex;\njustify-content: center;\nalign-items: center;"
Pegajoso
Establece la propiedad de position
en sticky
, con dos tabulaciones en la propiedad top
e left
.
"sticky": "position: sticky;\ntop: ${1:0};\nleft: ${2:0};"
Fragmentos de usuario
Al comienzo de este artículo, mencioné que VS Code también proporciona fragmentos personalizados. La diferencia con los fragmentos de Emmet es que no puede usar abreviaturas, pero también puede definir tabulaciones y usar variables internas.
Cómo obtener lo mejor de los fragmentos de código de usuario podría ser un tema para otro artículo, pero aquí hay un ejemplo de un fragmento de CSS personalizado que he definido:
"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." }
Este fragmento no solo crea reglas CSS, sino un bloque de declaración completo cuando vh
y presionamos Enter 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; }
Ultimas palabras
Lleva algo de tiempo crear estos fragmentos, pero vale la pena el esfuerzo porque puede personalizar Emmet según sus preferencias personales, automatizar tareas repetitivas y ahorrar tiempo a largo plazo.
Me encantaría ver qué fragmentos usas, así que compártelos con nosotros en los comentarios. Si desea utilizar mi configuración, puede encontrar mi snippets.json final en GitHub.
Recursos
- Fragmentos de CSS Emmet predeterminados
- Fragmentos de HTML Emmet predeterminados
- Hoja de trucos de Emmet
- Emmet en documentos de VS Code