VS CodeでのEmmetの使い方ガイド

Emmet(エメット)とは、ul>li*5 のような短い略語を打つだけで、対応するHTML・CSSのコードへ展開してくれる入力支援エンジンです。VS Codeには拡張機能として最初から同梱されているため、追加インストールなしで .html / .css ファイルを開けばすぐ使えます。

そして、この記事を開いた人の多くが本当に知りたいのは「書き方」ではなく「なぜ自分の環境では効かないのか」のはずです。原因はほぼ5つに絞れます。VS Codeの既定では emmet.triggerExpansionOnTabfalse なので「Tabを押せば必ず展開される」という前提自体が誤りで、ここを知らないまま設定をいじると余計に迷子になります。

本記事では、Emmetの定義と展開の仕組みを整理したうえで、「効かない」を切り分ける5分岐チェック、そのまま貼れる settings.json、そして実際に展開結果を検証した略語表までをまとめます。掲載している略語の展開結果は、Emmet本体(npmパッケージ emmet 2.4.11)で実行して出力を確認したものです。


Emmetとは|VS Codeに標準搭載された略語展開エンジン

Emmetは、CSSセレクタに似た記法でマークアップの構造を書き、それを実際のコードへ展開するツールです。>(子)+(兄弟)*(繰り返し)といった演算子で入れ子構造を1行で表現でき、20文字の入力から数十行のHTMLを生成できます。

重要なのは、Emmetは「拡張機能マーケットプレイスから入れるもの」ではないという点です。VS Codeには vscode.emmet という組み込み拡張として同梱されており、有効化の操作も不要です。検索して出てくる「Emmet」という名前のサードパーティ拡張を追加しても、動作が二重になるだけで解決にはなりません。

既定でEmmetが有効な言語

VS Code公式ドキュメントは、Emmetの略語展開が既定で有効な言語を明示しています。Emmet in Visual Studio Code(VS Code公式)によれば、対象は次の通りです。

分類既定で有効な言語ID
マークアップ系html / haml / pug / slim / jsx / xml / xsl
スタイルシート系css / scss / sass / less / stylus
上記を継承する言語handlebars / php など

.jsx.tsx はこの表の jsx に該当します。VS CodeのEmmet実装は言語ID javascriptreacttypescriptreact を内部で jsx に読み替えるため、ReactのJSX/TSXは設定なしでそのまま使えます。逆に言えば、リストに無い vue や、拡張子が .js のままJSXを書いているファイルは対象外です。

Emmetで短縮できる作業と、できない作業

Emmetが強いのは「構造が決まっているものを大量に置く」場面です。逆に、既存コードの意味を理解して直す作業は守備範囲外で、そこはAIアシスタントやAI時代に本当に必要なVS Code拡張機能で扱う領域になります。

Emmetが得意Emmetでは解決しない
入れ子構造の骨組みを一気に置く既存タグの意味づけ(セマンティクス)の見直し
連番クラス・連番テキストの量産CSSが当たらない原因の調査
CSSプロパティ名のタイプ量削減レイアウト設計そのものの判断
選択範囲を後からタグで包む命名規則やCSS設計の統一

Emmetの展開はTabキーではない|既定の挙動を正しく知る

ネット上の解説で最も多い誤りが「略語を打ってTabキーを押すと展開されます」という説明です。VS Codeの設定 emmet.triggerExpansionOnTab の既定値は false です。この設定について、VS Code同梱のEmmet拡張は次のように説明しています(原文)。

When enabled, Emmet abbreviations are expanded when pressing TAB, even when completions do not show up. When disabled, completions that show up can still be accepted by pressing TAB.

つまり既定の挙動はこうです。略語を入力するとサジェスト(補完候補)に展開後のコードが表示され、それをEnterで確定すると展開されます。候補が表示されている状態ならTabでも確定できますが、候補が出ていない状況ではTabは何もしません(インデントが入るだけです)。「Tabを押せば必ず展開される」ようにしたいなら、設定を true に変える必要があります。

展開する方法は3通りある

方法操作必要な設定
サジェストから確定略語を入力 → 候補をEnter(またはTab)不要(既定の挙動)
コマンドで明示的に展開コマンドパレット → Emmet: Expand Abbreviation不要
常にTabで展開略語を入力 → Tab"emmet.triggerExpansionOnTab": true

コマンドパレットはWindowsが Ctrl + Shift + P、macOSが Cmd + Shift + P です。Emmet関連のコマンドは Emmet: と打てば一覧で絞り込めます。エディタのショートカットを体系的に覚え直したい場合はショートカットキー チートシートでアプリ別に確認できます。


VS CodeでEmmetが効かないときの5分岐チェック

「Emmetが効かない」は原因が複数あり、思いつきで設定を足すと状態が悪化します。上から順に判定し、当たった1つを直したらそこで手を止めてください。各分岐には「何を見れば合格か」の観測ポイントを付けています。判定の材料は ul>li*3 という略語1つで足ります。

症状確認する場所合格ライン対処
HTMLを書いているのに候補が一切出ないステータスバー右下の言語モード表示HTML と表示されている言語モード表示をクリックして正しい言語を選ぶ/拡張子を .html にする
候補は出るがTabで展開されない設定検索欄で emmet.triggerExpansionOnTabチェックがON(trueONにする。またはEnterで確定する運用に切り替える
特定の拡張子だけ全く反応しない設定検索欄で emmet.excludeLanguagesその言語IDが配列に入っていない配列から該当の言語IDを削除する(既定値は ["markdown"]
.js.vue だけ効かない設定検索欄で emmet.includeLanguagesその言語IDのマッピングが存在する{"javascript": "javascriptreact"} などを追加する
候補欄がAI補完などで埋まって選べない設定検索欄で emmet.showExpandedAbbreviation値が alwaysalways に戻す。それでも埋まるならコマンドパレットの Emmet: Expand Abbreviation で確定させる

ファイルの言語モードが違う

最も多い原因がこれです。Emmetは「ファイル名」ではなく「VS Codeが判定した言語モード」で動作を決めます。無題ファイルのまま書いている、.txt で保存している、テンプレートエンジンの拡張子で開いているといった場合、言語モードは Plain Text などになり、Emmetは沈黙します。

合格ライン:VS Codeウィンドウ最下部のステータスバー右側に HTML(CSSファイルなら CSS)と出ていること。ここが Plain Text なら、その表示をクリックして言語を選び直せば即座に効き始めます。恒久的に直すなら、ファイルを正しい拡張子で保存し直してください。

Tabで展開する設定になっていない

前章の通り emmet.triggerExpansionOnTab の既定値は false です。「候補は出ているのにTabを押すとインデントが入るだけ」という症状は、候補にフォーカスが当たっていない状態でTabを押しているケースがほとんどです。

合格ライン:設定画面(CtrlCmd + ,)で emmet.triggerExpansionOnTab を検索し、チェックが入っている状態にしたうえで、.html ファイルに ul>li*3 と打ってTabを押し、li が3つ生成されること。生成されなければ原因は別の分岐です。

excludeLanguagesに入っている

emmet.excludeLanguages は「Emmetを無効化する言語ID」の配列で、既定値は ["markdown"] です。Markdown内でEmmetが効かないのは仕様であり、故障ではありません。過去に自分で言語IDを足していた場合や、チーム共有の .vscode/settings.json にワークスペース単位で書かれている場合も、この配列が効いています。

合格ライン:設定検索で emmet.excludeLanguages を開き、対象の言語IDが配列に含まれていないこと。ユーザー設定とワークスペース設定はタブが分かれているので、両方のタブを確認するのがポイントです。ワークスペース側の値がユーザー設定より優先されます。

.jsや.vueでincludeLanguagesが未設定

既定で有効な言語リストに javascript(拡張子 .js)と vue(拡張子 .vue)は含まれていません。.jsx / .tsx は効くのに .js だけ効かない、という現象はこれが原因です。emmet.includeLanguages で「自分のファイルの言語ID」を「Emmetが知っている言語」へ読み替えさせます。

注意点として、マッピングの右側(値)に指定できるのはEmmetが認識する言語だけです。html / css / scss / sass / less / stylus / xml / xsl / haml / slim / jade / javascriptreact / typescriptreact が該当します。ここに "vue": "jsx" のような存在しない値を書くと、設定は静かに無視されます。

合格ライン:設定を保存した直後、対象ファイルで ul>li*3 と打ってサジェストに展開後のHTMLが表示されること。表示されない場合はウィンドウの再読み込み(コマンドパレットの Developer: Reload Window)を1回だけ試します。

拡張機能に候補を奪われている

AIコード補完やスニペット系の拡張機能を複数入れていると、サジェスト一覧の上位が別の候補で埋まり、Emmetの展開結果が見えないことがあります。この場合Emmet自体は動いているので、設定を書き換えるより確定手段を変えるほうが速いです。

合格ライン:略語を入力した状態でコマンドパレットから Emmet: Expand Abbreviation を実行し、展開されること。これで展開できるなら原因はサジェスト表示側であり、Emmetは正常です。恒久対策として emmet.showExpandedAbbreviationalways であることを確認し、必要なら競合する拡張機能を一時的に無効化して切り分けます。導入済み拡張の棚卸しはVS Code拡張機能の整理が参考になります。

なお、Emmetは動いているのに書いたCSSが画面に反映されない、というのは別の問題です。そちらはChrome・VS Code・GitHubでCSSが反映されない原因と対処法で切り分けてください。


settings.jsonに書く設定|そのまま貼れる完全形

コマンドパレットで Preferences: Open User Settings (JSON) を実行すると settings.json が開きます。既に中身がある場合は、外側の { } の内側へ以下のキーを追記してください(既存の最終行の末尾にカンマが必要です)。

{
  "emmet.triggerExpansionOnTab": true,
  "emmet.showExpandedAbbreviation": "always",
  "emmet.variables": {
    "lang": "ja"
  },
  "emmet.includeLanguages": {
    "javascript": "javascriptreact",
    "vue": "html"
  },
  "emmet.excludeLanguages": [
    "markdown"
  ]
}
キー既定値何が変わるか
emmet.triggerExpansionOnTabfalse候補が出ていなくてもTabで展開できるようになる
emmet.showExpandedAbbreviation"always"展開結果をサジェストに出すかどうか。"never" だと候補が出ない
emmet.variables{}langen! で生成される雛形の langcharset を変えられる
emmet.includeLanguages{}既定で非対応の言語をEmmet対応言語へ読み替える
emmet.excludeLanguages["markdown"]Emmetを無効化する言語を指定する

日本語サイトなら lang を ja にしておく

HTMLの雛形略語 ! の展開結果は、既定では <html lang="en"> になります。日本語のページを作るたびに手で ja へ書き換えているなら、それは設定で解決できる無駄です。

<!-- 既定(emmet.variables 未設定)で ! を展開した結果 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

</body>
</html>

"emmet.variables": { "lang": "ja" } を入れると、同じ !<html lang="ja"> で展開されます(Emmet 2.4.11で実行し、出力が切り替わることを確認済み)。合格ライン:設定保存後に新規 .html! を展開し、2行目が <html lang="ja"> になっていること。charset も同じキーで変更できます。


React・Vueで使うときの設定を切り分ける

「ReactではEmmetの設定が必要」という説明をよく見かけますが、これは半分だけ正しい話です。必要かどうかはファイルの拡張子(=言語ID)で決まります

ファイルVS Codeの言語ID設定
.jsxjavascriptreact不要(内部で jsx として扱われる)
.tsxtypescriptreact不要(内部で jsx として扱われる)
.js にJSXを書くjavascript必要{"javascript": "javascriptreact"}
.vuevue必要{"vue": "html"}

VS Code公式ドキュメントが挙げている例も {"vue-html": "html", "javascript": "javascriptreact"} の形で、いずれも「既定では対応していない言語」を対象にしています.jsx / .tsx にこの設定を書いても効果はありません。

なお、JSXでは class ではなく className を使いますが、Emmetは jsx 構文として展開するときに div.cardclassName 付きで出力します。合格ライン:.jsx ファイルで div.card を展開し、class= ではなく className= になっていること。ここが class= なら、そのファイルはjsxとして扱われていないので言語モードを疑ってください。

Vueについては、Vue用の言語サーバー拡張が独自の補完を提供している場合もあります。まず設定を足さない状態で ul>li*3 を打ち、サジェストが出るかを確認してから追加するのが安全です。


HTML略語の基本文法と展開結果

まず演算子を5つ覚えれば、実務で書く構造のほとんどは表現できます。以下の展開結果はすべてEmmet 2.4.11で実際に実行して確認したものです。

演算子意味
>子要素にするul>li
+兄弟要素にするheader+main+footer
*繰り返すli*5
^階層を1つ戻すdiv>p^div
()グループ化する(header>h1)+main
$連番を差し込むli.item$*3
{}テキストを入れるp{本文}

実行して確認した入出力

入力する略語展開結果
ul>li.item$*3<li class="item1">item3 を持つ ul
ul>li{項目$}*3<li>項目1</li>項目3
div>p^div<div><p></p></div> の後ろに <div></div>
ul.list>li*4>a[href=/page$]{ページ$}<a href="/page1">ページ1</a> を含む li が4つ
select>option*3{選択肢$}nameid 付きの selectoption 3つ
picture>source[srcset]+img[src alt]<source srcset=""><img src="" alt="">
input:checkbox+label<input type="checkbox" name="" id=""><label for=""></label>
link:css<link rel="stylesheet" href="style.css">
meta:vp<meta name="viewport" content="width=device-width, initial-scale=1.0">
div*3>span{$@-}連番が3・2・1と逆順になる

グループ化を使うと、ページ全体の骨組みを1行で置けます。次は div.wrap>(header>h1)+(main>section*2>h2+ul>li*2)+footer の展開結果です。

<div class="wrap">
    <header>
        <h1></h1>
    </header>
    <main>
        <section>
            <h2></h2>
            <ul>
                <li></li>
                <li></li>
            </ul>
        </section>
        <section>
            <h2></h2>
            <ul>
                <li></li>
                <li></li>
            </ul>
        </section>
    </main>
    <footer></footer>
</div>

どのタグを使うべきかで迷ったときはHTMLタグ一覧で用途を確認してから略語に落とし込むと、生成後の手直しが減ります。


CSS略語の基本ルールと展開結果

CSS側の略語は「プロパティ名の子音を拾う+値を続ける」というルールで統一されています。単位を省略した整数は px、小数は em が既定で補われ、区切りには - を使います。

入力展開結果ルール
m10margin: 10px;整数は px が補われる
m1.5margin: 1.5em;小数は em が補われる
p10-20padding: 10px 20px;- が値の区切り
mt-10margin-top: -10px;先頭の - は負値
m0-amargin: 0 auto;キーワードも略せる
bgc#cccbackground-color: #ccc;色は # をそのまま書く
bd1-s-redborder: 1px solid red;複数値も - でつなぐ
dfdisplay: flex;値まで含む短縮形
jccjustify-content: center;同上
aicalign-items: center;同上
fxd:cflex-direction: column;: で値を明示できる
mih100vhmin-height: 100vh;単位を書けばそのまま使われる
maw100pmax-width: 100%;p% の略
bdrs10border-radius: 10px; 
op.5opacity: 0.5;先頭の 0 は省略できる
tdntext-decoration: none; 
curpcursor: pointer; 

覚え方のコツは「単語の頭文字を順に拾う」です。justify-content: center なら j + c + cjcctext-decoration: none なら tdn になります。プロパティ名そのものを引きたい場合はCSSプロパティ一覧が使えます。

既定の単位をremに変える

px をほとんど使わない設計をしているなら、整数に補われる単位そのものを変えられます。

{
  "emmet.preferences": {
    "css.intUnit": "rem"
  }
}

合格ライン:設定後に .cssm10 を展開し、margin: 10px; ではなく margin: 10rem; になること(Emmet 2.4.11で単位が切り替わることを実行確認済み)。既定値は css.intUnitpxcss.floatUnitem です。プロジェクト固有の初期値をまとめて置きたい場合は、EmmetではなくVS Codeのcss.jsonでカスタムスニペットを作る方法のほうが向いています。


略語以外に覚えると差が出るEmmetコマンド

Emmetは「新しく書く」だけの道具ではありません。既に書いたコードを編集するコマンド群があり、こちらのほうが実務での効き目は大きいです。VS Code同梱のEmmet拡張はこれらに既定のキーバインドを割り当てていないため、コマンドパレットで Emmet: と入力して呼び出します。

コマンドできること使いどころ
Wrap with Abbreviation選択範囲を略語で包む既存のリンク群を ul>li* でリスト化する
Balance (outward / inward)選択範囲を親/子のタグ単位で伸縮深い入れ子から目的のブロックを選ぶ
Go to Matching Pair対応する開始/終了タグへ移動長いテンプレートの対応関係を確認する
Remove Tagタグだけ削除して中身を残す不要なラッパー div を外す
Update Tag開始・終了タグを同時に変更divsection に置き換える
Split/Join Tag空タグと開閉タグを相互変換<br /> 形式の統一
Evaluate Math Expression行内の数式を計算結果に置換幅の計算をその場で済ませる
Increment/Decrement by 0.1 / 1 / 10カーソル位置の数値を増減余白や透明度の微調整

特に Wrap with Abbreviation は覚える価値があります。テキストを複数行選択した状態で ul>li* と入力すると、各行が li に分配されます。* の後ろに数を書かないのが要点です。

これらを手に馴染ませるには、実際に手を動かす題材が要ります。HTML/CSS練習問題20選のような課題を、あえて全部Emmetで組んでみると定着が早いです。


よくある質問(FAQ)

Q. VS CodeでEmmetを使うのに拡張機能のインストールは必要ですか?

不要です。EmmetはVS Codeに組み込み拡張として同梱されており、.html.css を開けば追加インストールなしで動作します。マーケットプレイスで見つかる同名の拡張を入れる必要はありません。

Q. Tabキーを押しても展開されないのはなぜですか?

VS Codeの emmet.triggerExpansionOnTab は既定値が false のためです。既定ではサジェスト候補をEnter(候補が出ていればTabでも可)で確定して展開します。候補が出ていない状態でもTabで展開したい場合は、この設定を true にしてください。

Q. ReactのJSXでEmmetを使うには設定が必要ですか?

拡張子が .jsx または .tsx なら設定は不要です。VS Codeが言語IDを javascriptreact / typescriptreact と判定し、Emmetはこれを内部で jsx として扱います。設定が要るのは .js ファイルにJSXを書く場合で、"emmet.includeLanguages": {"javascript": "javascriptreact"} を追加します。

Q. Vueファイルで効かないときはどうしますか?

.vue の言語IDは vue で、Emmetが既定で対応する言語リストに含まれていません。"emmet.includeLanguages": {"vue": "html"} を追加し、ul>li*3 を打ってサジェストが出るかで確認してください。マッピングの値には html のようなEmmet側が認識する言語しか指定できません。

Q. Markdownファイルで動かないのは不具合ですか?

不具合ではなく既定の仕様です。emmet.excludeLanguages の既定値が ["markdown"] になっており、Markdownは意図的に除外されています。使いたい場合はこの配列から markdown を取り除きます。

Q. 生成される雛形のlangをjaにできますか?

できます。"emmet.variables": { "lang": "ja" }settings.json に追加すると、! で生成されるHTML5雛形が <html lang="ja"> になります。既定値は en のため、日本語サイトを作る環境では最初に入れておくと手直しが消えます。

Q. 全部の略語を覚える必要はありますか?

ありません。演算子(> + * ^ ())と、自分がよく書く十数個のCSS略語を押さえれば実務は回ります。網羅的な一覧はEmmet公式チートシートEmmet公式の記法リファレンスで必要になったときだけ引けば十分です。


まとめ|まず言語モードと展開方法を確認する

EmmetはVS Codeに標準搭載されており、動かないときの原因はほぼ「言語モード」「展開方法の誤解」「includeLanguages/excludeLanguages」「サジェストの競合」の4系統に収まります。設定を足す前に、ステータスバーの言語モードを見てコマンドパレットの Emmet: Expand Abbreviation を1回叩く——この2ステップで切り分けが終わることがほとんどです。

そのうえで "emmet.variables": { "lang": "ja" }"emmet.triggerExpansionOnTab": true の2つだけ先に入れておくと、日本語サイト制作での手直しが減ります。あとは演算子5つを手に覚えさせれば、マークアップの下書き時間はそのまま短縮できます。