Создание пользовательских фрагментов Emmet в VS Code
Опубликовано: 2022-03-10 Ранее в этом году я поделился шаблоном 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, необходимо выполнить следующие шаги:
-  Создайте файл snippets.json , добавьте эту базовую структуру JSON и сохраните ее где-нибудь на жестком диске.
{ "html": { "snippets": { } }, "css": { "snippets": { } } } -  Откройте настройки кода VS (Код → Настройки → Настройки) и найдите «Путь к расширениям Emmet». 

 -  Нажмите «Добавить элемент», введите путь к папке, в которой вы сохранили созданный ранее файл 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> и установите текст по умолчанию на © .
 {${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> 
Ладно, хватит разминки. Давайте создадим сложные фрагменты. Сначала я хотел создать один сниппет для своего шаблона, но создал три аббревиатуры, которые служат разным потребностям.
- Небольшой
 - Середина
 - Полный
 
Шаблон Малый
Это шаблон для быстрых демонстраций, он создает следующее:
- Базовая структура сайта,
 -  метатег 
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 . Здесь вы также можете добавить свои пользовательские переменные. 

 <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 делает комментарий действительно популярным.

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