Создание пользовательских фрагментов 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};"
Пользовательские фрагменты
В начале этой статьи я упомянул, что 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