Criando snippets Emmet personalizados no VS Code

Publicados: 2022-03-10
Resumo rápido ↬ Neste artigo, Manuel explica por que Emmet é uma de suas ferramentas de produtividade favoritas para escrever HTML e CSS e como você pode criar trechos de Emmet personalizados no Visual Studio Code para ajudá-lo a melhorar ainda mais seus fluxos de trabalho de front-end.

No início deste ano, compartilhei o clichê HTML que gosto de usar ao iniciar novos projetos da Web com explicações linha por linha em meu blog. É uma coleção de tags e atributos principalmente <head> que costumo usar em todos os sites que crio. Até recentemente, eu apenas copiava e colava o clichê sempre que precisasse, mas decidi melhorar meu fluxo de trabalho adicionando-o como um trecho ao VS Code — o editor de minha escolha.

Aqui está uma demonstração rápida dos snippets personalizados que criei.

Trechos e abreviações no código do Visual Studio

O VS Code vem integrado com trechos de usuário personalizados e trechos e abreviações HTML e CSS fornecidos pelo Emmet.

Por exemplo, se você digitar p>a{Sign Up} em um documento HTML e pressionar Enter ou Tab , o Emmet o transformará na seguinte marcação:

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

Observação : visite os documentos do Emmet para aprender a usar a sintaxe de abreviação.

Se precisarmos dessa abreviação específica regularmente, podemos salvá-la como um snippet para melhorar ainda mais nosso fluxo de trabalho.

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

Agora podemos digitar signup e pressionar Enter ou Tab e obteremos o mesmo resultado. Explicarei como criar snippets na próxima seção.

O Emmet vem com vários trechos de HTML por padrão. Por exemplo, ! cria a estrutura básica de um 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>

Isso é ótimo, mas se quisermos adaptar esse trecho removendo ou adicionando elementos e atributos, temos que sobrescrevê-lo e criar nosso próprio trecho.

Criando e substituindo snippets

Se quisermos criar nossos próprios snippets do Emmet ou substituir os existentes no VS Code, são necessárias as seguintes etapas:

  1. Crie um arquivo snippets.json , adicione essa estrutura JSON básica e salve-a em algum lugar do seu disco rígido.
     { "html": { "snippets": { } }, "css": { "snippets": { } } }
  2. Abra as configurações do VS Code (Código → Preferências → Configurações) e procure por “Emmet Extensions Path”.
  3. Clique em “Add Item”, digite o caminho para a pasta onde você salvou o arquivo snippets.json que você criou anteriormente e pressione “OK”.

É isso. Agora estamos prontos para criar trechos adicionando propriedades aos objetos html e css onde a key é o nome do trecho e o value uma abreviação ou uma string.

Alguns dos meus trechos HTML personalizados

Antes de nos aprofundarmos na criação de snippets e mostrar como criei um snippet para meu clichê HTML, vamos começar com alguns snippets pequenos, mas úteis que criei também.

Carregamento lento

Fora da caixa, há uma abreviação de img , mas não há nenhuma para imagens carregadas preguiçosamente. Podemos usar a abreviação padrão e apenas adicionar os atributos adicionais e os valores de atributo que precisamos entre colchetes.

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

img:l + Enter / Tab agora cria a seguinte marcação:

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

Página

A maioria das páginas que crio consistem em <header> , <main> e <footer> pontos de referência e um <h1> . A abreviação de page personalizada me permite criar essa estrutura rapidamente.

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

page + Enter / Tab cria a seguinte marcação:

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

Essa abreviação é bastante longa, então vamos dividi-la em pedaços menores.

Discriminação

Crie um elemento <header> e um filho <h1> .

 header>h1

Mova para cima, volte para o nível do <header> e crie um <footer> que segue <main> .

 ^main+footer

Defina a parada de tabulação final dentro do <footer> e defina o texto padrão como &copy .

 {${0:©}}

Navegação

A abreviação nav apenas cria uma tag de início e fim <nav> por padrão, mas o que eu normalmente preciso é de um <nav> com elementos <ul> , <li> e links aninhados ( <a> ). Se houver vários elementos <nav> em uma página, eles também devem ser rotulados, por exemplo, usando aria-label .

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

Isso parece selvagem, então vamos dividi-lo novamente.

Discriminação

Começamos com um elemento <nav> com um atributo aria-label e um <ul> aninhado. ${1:Main} preenche o atributo com o texto “Main” e cria uma tabulação no valor do atributo movendo o cursor para ele e destacando-o na criação.

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

Em seguida, criamos quatro itens de lista com links aninhados. O primeiro item é especial porque marca a página ativa usando aria-current="page" . Criamos outra tabulação e preenchemos o link com o texto “Página Atual”.

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

Por fim, adicionamos mais três itens de lista com links e o texto do link “Outra página”.

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

Antes de nossas adaptações, obtivemos isso:

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

Agora obtemos isso:

 <-- 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>
Mais depois do salto! Continue lendo abaixo ↓

Estilo

A abreviação de style padrão cria apenas a tag de início e fim <style> , mas geralmente quando uso o elemento <style> faço isso porque quero testar ou depurar algo rapidamente.

Vamos adicionar algumas regras padrão à tag <style> :

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

Discriminação

Alguns caracteres (por exemplo, $ , * , { ou } ) precisam ser escapados usando \\ .

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

\n cria uma quebra de linha e ${1:*} coloca a primeira parada de tabulação no seletor * .

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

Pronto, chega de aquecimento. Vamos criar snippets complexos. A princípio, eu queria criar um único snippet para meu clichê, mas criei três abreviações que atendem a necessidades diferentes.

  1. Pequeno
  2. Médio
  3. Cheio

Caldeira pequena

Este é um clichê para demonstrações rápidas, ele cria o seguinte:

  • Estrutura básica do site,
  • metatag da viewport de visualização,
  • Título da página,
  • 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}}" }

Discriminação

Uma string com o doctype:

 {<!DOCTYPE html>}

O elemento <html> com um atributo lang . O valor do atributo lang é uma variável que você pode alterar nas configurações do código VS (Código → Preferências → Configurações).

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

Você pode alterar o idioma natural padrão da página pesquisando por “variáveis ​​emmet” nas configurações do VS Code e alterando a variável lang . Você também pode adicionar suas variáveis ​​personalizadas aqui.

Existem 2 variáveis ​​padrão no VS Code, lang é definido como en e charset como UTF-8.

O <head> inclui a meta tag charset , a meta tag viewport , <title> e a tag <style> . {} cria uma nova linha.

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

Vamos dar uma primeira olhada rápida no que isso nos dá.

 <!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>

Parece bom, mas a abreviação meta:utf cria a maneira antiga em HTML para definir o charset e meta:vp cria duas paradas de tabulação que não preciso porque nunca uso uma configuração diferente para a viewport .

Vamos substituir esses trechos antes de prosseguirmos.

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

Por último, mas não menos importante, o elemento <body> , um <h1> com texto padrão, seguido pela tabulação final.

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

O clichê 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 mim, essa é a configuração de depuração mínima perfeita.

Caldeira média

Enquanto eu uso o primeiro clichê apenas para demonstrações rápidas, o segundo clichê pode ser usado para páginas complexas. O snippet cria o seguinte:

  • Estrutura básica do site,
  • metatag da viewport de visualização,
  • Título da página,
  • classes .no-js / .js ,
  • Tela externa e folhas de estilo de impressão,
  • description e metatag theme-color ,
  • Estrutura da 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" }

Yeaaah, eu sei, isso parece rabiscos. Vamos dissecá-lo.

Discriminação

O doctype e o elemento raiz são como no primeiro exemplo, mas com uma classe adicional no-js e um comentário que me lembra de alterar o atributo lang , se necessário.

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

A extensão TODO Highlight torna o comentário realmente pop.

A extensão destaca certas palavras-chave como TODO visualmente.

O <head> inclui a meta tag charset , meta tag viewport , <title> . {} cria uma nova linha.

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

Um script com uma linha de JavaScript. Estou cortando a mostarda no suporte do módulo JS. Se um navegador suporta módulos JavaScript, significa que é um navegador que suporta JavaScript moderno (por exemplo, módulos, sintaxe ES 6, busca e assim por diante). Eu envio a maioria dos JS apenas para esses navegadores e uso a classe js em CSS, se o estilo de um componente for diferente, quando o JavaScript estiver ativo.

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

Dois elementos <link> ; o primeiro link para a folha de estilo principal e o segundo para uma folha de estilo de impressão.

 link:css+link:print+{}

A descrição da página:

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

A metatag theme-color :

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

O elemento body e a estrutura básica da página:

 body>page

O clichê final fica assim:

 <!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>

Caldeira Cheia

O clichê completo é semelhante ao segundo clichê; as diferenças são meta adicionais e uma tag de script .

O snippet cria o seguinte:

  • Estrutura básica do site,
  • metatag da viewport de visualização,
  • Título da página,
  • classes js / no-js ,
  • Tela externa e folhas de estilo de impressão,
  • description e metatags de gráfico aberto,
  • meta tag theme-color ,
  • tag canônica <link> ,
  • Tags de favicon,
  • Estrutura da página,
  • < script> marca.
 { "!!!": "{<!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 snippet incrivelmente longo cria isso:

 <!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>

Trechos CSS personalizados

Por uma questão de completude, aqui estão alguns dos trechos de CSS que estou usando.

Depuração

Este snippet cria um contorno vermelho de 5px com um deslocamento personalizado.

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

Centralização

Um snippet que define display como flex e centraliza seus itens filhos.

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

Pegajoso

Define a propriedade position como sticky , com duas paradas de tabulação na propriedade top e left .

 "sticky": "position: sticky;\ntop: ${1:0};\nleft: ${2:0};" 
Uma demonstração de todos os 3 snippets CSS aplicados a um elemento div .

Fragmentos de usuário

No início deste artigo, mencionei que o VS Code também fornece snippets personalizados. A diferença para os snippets do Emmet é que você não pode usar abreviações, mas também pode definir paradas de tabulação e fazer uso de variáveis ​​internas.

Como obter o melhor dos snippets de usuário pode ser um tópico para outro artigo, mas aqui está um exemplo de um snippet CSS personalizado que defini:

 "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 snippet não cria apenas regras CSS, mas um bloco de declaração inteiro quando vh e pressionamos Enter ou 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; }

Palavras finais

Leva algum tempo para criar esses trechos, mas vale a pena o esforço porque você pode personalizar o Emmet de acordo com suas preferências pessoais, automatizar tarefas repetitivas e economizar tempo a longo prazo.

Eu adoraria ver quais snippets você usa, então compartilhe-os conosco nos comentários. Se você quiser usar minhas configurações, você pode encontrar meu snippets.json final no GitHub.

Recursos

  • Snippets de CSS Emmet padrão
  • Fragmentos de Emmet HTML padrão
  • Folha de dicas do Emmet
  • Emmet nos documentos do VS Code