Создание пользовательских фрагментов Emmet в VS Code

Опубликовано: 2022-03-10
Краткое резюме ↬ В этой статье Мануэль объясняет, почему Emmet является одним из его любимых инструментов повышения производительности для написания HTML и CSS, и как вы можете создавать собственные фрагменты кода Emmet в Visual Studio Code, чтобы помочь вам еще больше улучшить свои интерфейсные рабочие процессы.

Ранее в этом году я поделился шаблоном HTML, который мне нравится использовать при запуске новых веб-проектов, с построчными пояснениями в своем блоге. Это набор в основном тегов и атрибутов <head> , которые я обычно использую на каждом веб-сайте, который я создаю. До недавнего времени я просто копировал и вставлял шаблон всякий раз, когда он мне был нужен, но я решил улучшить свой рабочий процесс, добавив его в виде фрагмента в VS Code — редактор по моему выбору.

Вот краткая демонстрация пользовательских фрагментов, которые я создал.

Фрагменты и сокращения в коде Visual Studio

VS Code поставляется со встроенными пользовательскими фрагментами, а также фрагментами HTML и CSS и сокращениями, предоставленными Emmet.

Например, если вы наберете p>a{Sign Up} в HTML-документе и нажмете Enter или Tab , Emmet превратит его в следующую разметку:

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

Примечание . Посетите документацию Emmet, чтобы узнать, как использовать синтаксис аббревиатуры.

Если нам нужно это конкретное сокращение регулярно, мы можем сохранить его как фрагмент, чтобы еще больше улучшить наш рабочий процесс.

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

Теперь мы можем ввести signup и нажать Enter или Tab , и мы получим тот же результат. Я объясню, как создавать фрагменты в следующем разделе.

Emmet по умолчанию поставляется с набором фрагментов HTML. Например, ! создает базовую структуру 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>

Это здорово, но если мы хотим адаптировать этот фрагмент, удалив или добавив элементы и атрибуты, мы должны перезаписать его и создать собственный фрагмент.

Создание и перезапись фрагментов

Если мы хотим создать собственные фрагменты Emmet или перезаписать существующие в VS Code, необходимо выполнить следующие шаги:

  1. Создайте файл snippets.json , добавьте эту базовую структуру JSON и сохраните ее где-нибудь на жестком диске.
     { "html": { "snippets": { } }, "css": { "snippets": { } } }
  2. Откройте настройки кода VS (Код → Настройки → Настройки) и найдите «Путь к расширениям Emmet».
  3. Нажмите «Добавить элемент», введите путь к папке, в которой вы сохранили созданный ранее файл snippets.json , и нажмите «ОК».

Вот и все. Теперь мы готовы создавать фрагменты, добавляя свойства к объектам html и css , где key — это имя фрагмента, а value — аббревиатура или строка.

Некоторые из моих пользовательских фрагментов HTML

Прежде чем мы углубимся в создание сниппетов, и я покажу вам, как я создал сниппет для моего шаблона HTML, давайте сначала разогреемся с некоторыми небольшими, но полезными сниппетами, которые я тоже создал.

Ленивая загрузка

Из коробки есть аббревиатура img , но нет ее для лениво загружаемых изображений. Мы можем использовать аббревиатуру по умолчанию и просто добавить дополнительные атрибуты и значения атрибутов, которые нам нужны, в квадратных скобках.

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

img:l + Enter / Tab теперь создает следующую разметку:

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

Страница

Большинство страниц, которые я создаю, состоят из ориентиров <header> , <main> и <footer> и <h1> . Аббревиатура пользовательской page позволяет мне быстро создать эту структуру.

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

page + Enter / Tab создает следующую разметку:

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

Эта аббревиатура довольно длинная, поэтому давайте разобьем ее на более мелкие части.

Авария

Создайте элемент <header> и дочерний <h1> .

 header>h1

Переместитесь вверх, вернитесь на уровень <header> и создайте <footer> , следующий за <main> .

 ^main+footer

Установите последнюю позицию табуляции в <footer> и установите текст по умолчанию на &copy .

 {${0:©}}

Навигация

Аббревиатура nav просто создает начальный и конечный теги <nav> по умолчанию, но мне обычно нужен <nav> с вложенными элементами <ul> , <li> и ссылками ( <a> ). Если на странице есть несколько элементов <nav> , они также должны быть помечены, например, с помощью aria-label .

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

Это выглядит дико, так что давайте снова разберемся.

Авария

Мы начинаем с элемента <nav> с атрибутом aria-label и вложенным элементом <ul> . ${1:Main} заполняет атрибут текстом «Main» и создает позицию табуляции на значении атрибута, перемещая на него курсор и выделяя его при создании.

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

Затем мы создаем четыре элемента списка с вложенными ссылками. Первый элемент особенный, потому что он помечает активную страницу с помощью aria-current="page" . Мы создаем еще одну позицию табуляции и заполняем ссылку текстом «Текущая страница».

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

Наконец, мы добавляем еще три элемента списка со ссылками и текстом ссылки «Другая страница».

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

Перед нашей адаптацией мы получили это:

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

Теперь мы получаем это:

 <-- 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>
Еще после прыжка! Продолжить чтение ниже ↓

Стиль

Аббревиатура style по умолчанию создает только начальный и конечный теги <style> , но обычно, когда я использую элемент <style> , я делаю это, потому что хочу быстро протестировать или отладить что-то.

Давайте добавим некоторые правила по умолчанию в <style> :

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

Авария

Некоторые символы (например, $ , * , { или } ) необходимо экранировать с помощью \\ .

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

\n создает разрыв строки, а ${1:*} помещает первую позицию табуляции в селектор * .

 {\n${1:*}:focus \\{${2: outline: 2px solid red; }\\}}
  • До : <style><style>
  • После :
     <style> * { box-sizing: border-box; }
    *:focus { outline: 2px solid red; } </style>

Ладно, хватит разминки. Давайте создадим сложные фрагменты. Сначала я хотел создать один сниппет для своего шаблона, но создал три аббревиатуры, которые служат разным потребностям.

  1. Небольшой
  2. Середина
  3. Полный

Шаблон Малый

Это шаблон для быстрых демонстраций, он создает следующее:

  • Базовая структура сайта,
  • метатег viewport ,
  • Заголовок страницы,
  • элемент <style> ,
  • <h1> .
 { "!": "{<!DOCTYPE html>}+html[lang=${1}${lang}]>(head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)+body>(h1>{${3: New Document}})+{${0}}" }

Авария

Строка с типом документа:

 {<!DOCTYPE html>}

Элемент <html> с атрибутом lang . Значение атрибута lang — это переменная, которую вы можете изменить в настройках кода VS (Code → Preferences → Settings).

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

Вы можете изменить естественный язык страницы по умолчанию, выполнив поиск «переменные emmet» в настройках VS Code и изменив переменную lang . Здесь вы также можете добавить свои пользовательские переменные.

В VS Code есть 2 переменные по умолчанию: для lang установлено значение en, ​​а для кодировки — UTF-8.

<head> включает в себя метатег charset , метатег области viewport , теги <title> и <style> . {} создает новую строку.

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

Давайте сначала быстро посмотрим, что это нам дает.

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

Выглядит нормально, но аббревиатура meta:utf создает старый способ определения charset в HTML, а meta:vp создает две позиции табуляции, которые мне не нужны, потому что я никогда не использую другую настройку для viewport .

Давайте перезапишем эти фрагменты, прежде чем двигаться дальше.

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

И последнее, но не менее важное: элемент <body> , <h1> с текстом по умолчанию, за которым следует последняя позиция табуляции.

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

Окончательный шаблон:

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

Для меня это идеальная минимальная настройка отладки.

Стандартный средний

Хотя я использую первый шаблон только для быстрых демонстраций, второй шаблон можно использовать для сложных страниц. Фрагмент создает следующее:

  • Базовая структура сайта,
  • метатег viewport ,
  • Заголовок страницы,
  • классы .no-js / .js ,
  • Внешний экран и таблицы стилей печати,
  • description и метатег theme-color ,
  • Структура страницы.
 { "!!": "{<!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" }

Даааа, я знаю, это выглядит как тарабарщина. Давайте разберем его.

Авария

Тип doctype и корневой элемент такие же, как в первом примере, но с дополнительным классом no-js и комментарием, который напоминает мне, что нужно изменить атрибут lang , если это необходимо.

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

Расширение TODO Highlight делает комментарий действительно популярным.

Расширение визуально выделяет определенные ключевые слова, такие как TODO.

<head> включает в себя метатег charset , метатег области viewport , <title> . {} создает новую строку.

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

Скрипт со строкой JavaScript. Я режу горчицу в поддержке модуля JS. Если браузер поддерживает модули JavaScript, это означает, что этот браузер поддерживает современный JavaScript (например, модули, синтаксис ES 6, выборку и т. д.). Я отправляю большую часть JS только в эти браузеры и использую класс js в CSS, если стиль компонента отличается, когда JavaScript активен.

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

Два элемента <link> ; первая ссылка на основную таблицу стилей, а вторая — на таблицу стилей печати.

 link:css+link:print+{}

Описание страницы:

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

theme-color :

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

Элемент body и базовая структура страницы:

 body>page

Окончательный шаблон выглядит так:

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

Полный шаблон

Полный шаблон подобен второму шаблону; отличия заключаются в дополнительных meta и теге script .

Фрагмент создает следующее:

  • Базовая структура сайта,
  • метатег viewport ,
  • Заголовок страницы,
  • классы js / no-js ,
  • Внешний экран и таблицы стилей печати,
  • метатеги description и открытого графа,
  • метатег theme-color ,
  • канонический <link> ,
  • теги фавикон,
  • Структура страницы,
  • тег < 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\"]" }

Этот невероятно длинный фрагмент создает это:

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

Пользовательские фрагменты CSS

Для полноты картины приведу несколько фрагментов CSS, которые я использую.

Отладка

Этот фрагмент создает красный контур толщиной 5 пикселей с произвольным смещением.

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

Центрирование

Фрагмент, который настраивает display на гибкий и центрирует дочерние элементы.

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

Липкий

Задает для свойства position значение sticky с двумя позициями табуляции top и left .

 "sticky": "position: sticky;\ntop: ${1:0};\nleft: ${2:0};" 
Демонстрация всех трех фрагментов CSS, примененных к элементу div .

Пользовательские фрагменты

В начале этой статьи я упомянул, что VS Code также предоставляет пользовательские фрагменты кода. Отличие от фрагментов Emmet заключается в том, что вы не можете использовать сокращения, но вы также можете определять позиции табуляции и использовать внутренние переменные.

Как получить максимальную отдачу от пользовательских фрагментов может быть темой для другой статьи, но вот пример пользовательского фрагмента CSS, который я определил:

 "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." }

Этот фрагмент не просто создает правила CSS, а целый блок объявлений, когда мы vh и нажимаем Enter или 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; }

Заключительные слова

Создание этих фрагментов занимает некоторое время, но оно того стоит, потому что вы можете настроить Emmet в соответствии со своими личными предпочтениями, автоматизировать повторяющиеся задачи и сэкономить время в долгосрочной перспективе.

Я хотел бы увидеть, какие фрагменты вы используете, поэтому, пожалуйста, поделитесь ими с нами в комментариях. Если вы хотите использовать мои настройки, вы можете найти мой окончательный файл snippets.json на GitHub.

Ресурсы

  • Фрагменты CSS Emmet по умолчанию
  • Фрагменты кода HTML Emmet по умолчанию
  • Шпаргалка Эммета
  • Эммет в документах VS Code