Creación de fragmentos de Emmet personalizados en VS Code

Publicado: 2022-03-10
Resumen rápido ↬ En este artículo, Manuel explica por qué Emmet es una de sus herramientas de productividad favoritas para escribir HTML y CSS, y cómo puede crear fragmentos personalizados de Emmet en Visual Studio Code para ayudarlo a mejorar aún más sus flujos de trabajo front-end.

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.

Aquí hay una demostración rápida de los fragmentos personalizados que he creado.

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:

  1. 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": { } } }
  2. Abra la configuración de VS Code (Código → Preferencias → Configuración) y busque "Ruta de extensiones de Emmet".
  3. 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 &copy .

 {${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>
¡Más después del salto! Continúe leyendo a continuación ↓

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.

  1. Pequeña
  2. Medio
  3. 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í.

Hay 2 variables predeterminadas en VS Code, lang se establece en en y charset en UTF-8.

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 metaetiqueta theme-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.

La extensión destaca ciertas palabras clave como TODO visualmente.

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};" 
Una demostración de los 3 fragmentos de CSS aplicados a un elemento div .

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