VS 코드에서 사용자 지정 Emmet 조각 만들기
게시 됨: 2022-03-10 올해 초, 나는 새로운 웹 프로젝트를 시작할 때 사용하는 HTML 상용구를 내 블로그에 한 줄 한 줄 설명과 함께 공유했습니다. 내가 만드는 모든 웹사이트에서 주로 사용하는 대부분의 <head>
태그와 속성 모음입니다. 최근까지는 필요할 때마다 상용구를 복사하여 붙여넣었지만, 내가 선택한 편집기인 VS Code에 스니펫으로 추가하여 워크플로를 개선하기로 결정했습니다.
Visual Studio Code의 조각 및 약어
VS Code는 Emmet에서 제공하는 사용자 정의 사용자 스니펫과 HTML 및 CSS 스니펫 및 약어와 함께 기본 제공됩니다.
예를 들어 HTML 문서에 p>a{Sign Up}
을 입력하고 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 Code 설정(Code → Preferences → Settings)을 열고 "Emmet Extensions Path"를 검색합니다.
- "항목 추가"를 클릭하고 이전에 생성한 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>
수준으로 돌아가서 <main>
다음에 오는 <footer>
를 만듭니다.
^main+footer
<footer>
내에서 마지막 탭 정지를 설정하고 기본 텍스트를 ©
로 설정하십시오.
{${0:©}}
항해
약어 nav
는 기본적으로 <nav>
시작 및 종료 태그를 생성하지만 일반적으로 필요한 것은 중첩된 <ul>
, <li>
요소 및 링크( <a>
)가 있는 <nav>
입니다. 페이지에 <nav>
요소가 여러 개 있는 경우 aria-label
을 사용하여 레이블도 지정해야 합니다.
"nav": "nav[aria-label='${1:Main}']>ul>(li>a[aria-current='page']{${2:Current Page}})+(li*3>a{${0:Another Page}})"
이상해 보이므로 다시 분석해 보겠습니다.
고장
aria-label
속성과 중첩된 <ul>
이 있는 <nav>
요소로 시작합니다. ${1:Main}
은 속성을 "Main" 텍스트로 채우고 커서를 속성 값으로 이동하고 생성 시 강조 표시하여 속성 값에 탭 정지를 만듭니다.
nav[aria-label='${1:Main}']>ul
그런 다음 중첩된 링크가 있는 4개의 목록 항목을 만듭니다. 첫 번째 항목은 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>}
lang
속성이 있는 <html>
요소. lang
속성의 값은 VS 코드 설정(코드 → 기본 설정 → 설정)에서 변경할 수 있는 변수입니다.
html[lang=${1}${lang}]
VS 코드 설정에서 "emmet 변수"를 검색하고 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
약어는 HTML에서 charset
을 정의하는 오래된 방식을 생성하고 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
과 root 요소는 첫 번째 예와 비슷하지만 추가 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를 이러한 브라우저에만 제공하고 JavaScript가 활성화된 상태에서 구성 요소의 스타일이 다른 경우 CSS에서 js
클래스를 사용합니다.
(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>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 스니펫 중 일부입니다.
디버깅
이 스니펫은 맞춤 오프셋이 있는 5px 빨간색 윤곽선을 만듭니다.
"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을 개인 취향에 맞게 사용자 정의하고 반복적인 작업을 자동화하며 장기적으로 시간을 절약할 수 있기 때문에 노력할 가치가 있습니다.
어떤 스니펫을 사용하는지 보고 싶으므로 댓글로 공유해 주세요. 내 설정을 사용하려면 GitHub에서 최종 snippets.json을 찾을 수 있습니다.
자원
- 기본 CSS Emmet 스니펫
- 기본 HTML Emmet 스니펫
- 에밋 치트 시트
- VS Code 문서의 Emmet