Emmetを活用してコーディングのパフォーマンスを向上させよう

EmmetはHTMLやCSSを省略記法で記述できるようにプラグイン・拡張機能です。

最近Youtube動画で、Beginner/JuniorエンジニアとPro/Seniorエンジニアのコーディングの仕方についた動画がよく流れてきたので、使い方をまとめてみました。

Emmetの使い方

Emmetの省略記法からHTMLのタグやCSSのプロパティを作成するにはENTER/RETURNまたはTABを使用します。どちらが使用するかはエディタによって異なっており、Visual Studio CodeはENTER/RETURNTABのどちらでも変換できますが、WebStormでは[TAB]のみで変換します。

例えば、<div></div>タグを作成するには

div[ENTER/RETURN or TAB]

のように入力します。

HTMLのタグの作成

主にEmmetが使用されるのはHTMLのタグを記述する場合です。少ないタイピング量で素早くタグを作成できます。

よく使われる省略記法について見ていきます。

空タグを作成

単に空タグを作成したい場合はタグ名を入力後、[ENTER/RETURN or TAB]を入力します。

h2[ENTER/RETURN or TAB]
->
<h2></h2>

空タグを作成するとカーソルは<h2></h2>の間にあるので、十字キーやマウスでカーソル位置を変えることなくタグ内に入力することができるようになります。

id属性付きの空タグを作成

実際にコーディングしていると、単純に空タグを作成するということはid属性やclass属性がついたタグを作成することがほとんどだと思います。id属性がついた空タグを作成するには、タグ名に続いて#を入力してid属性の名称を入力し、[ENTER/RETURN or TAB]を入力します。

h2#title[ENTER/RETURN or TAB]
->
<h2 id="title"></h2>

ここではHTMLファイル内で一意になるtitleというid属性をもったh2タグを作成しました。

クラス属性付きの空タグを作成

class属性をついた空タグを作成するにはタグ名に続いて.を入力してclass属性の名称を入力し、[ENTER/RETURN or TAB]を入力します。

div.sidebar[ENTER/RETURN or TAB]
->
<div class="sidebar"></div>

2つ以上のクラスを定義したい場合は、.class名を繰り返します。

div.sidebar.active[ENTER/RETURN or TAB]
->
<div class="sidebar active"></div>

BootstrapやTailwind CSSなどのCSSフレームワークを使っている場合はタグにいくつものクラスを定義することになるため、Emmetを使った省略記法でのコーディングは生産性に大きな影響を与えます。

div.mb-3.row[ENTER/RETURN or TAB]
->
<div class="mb-3 row"></div>

子要素をまとめて作成

例えば、ulタグの中にliタグがあるような構造をまとめて作成するには、>を使用します。

ul>li[ENTER/RETURN or TAB]
->
<ul>
  <li></li>
</ul>

作成後のカーソル位置は<li></li>の間にあります。

要素を複数まとめて作成

同じタグを複数個まとめて作成したい場合は*に続いて繰り返し回数を入力することでまとめて作成できます。

前述の例で、子要素のliタグをまとめて3個作成したい場合は

ul>li*3[ENTER/RETURN or TAB]
->
<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>

のようにします。作成後のカーソル位置は一番最初のliタグの<li></li>の間にあり、[TAB]で次のliタグの<li></li>の間に移動できるので、

ul>li*3[ENTER/RETURN or TAB]
->
<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>

abc[TAB]
->
<ul>
  <li>abc</li>
  <li></li>
  <li></li>
</ul>

def[TAB]
->
<ul>
  <li>abc</li>
  <li>def</li>
  <li></li>
</ul>

ghi[TAB]
->
<ul>
  <li>abc</li>
  <li>def</li>
  <li>ghi</li>
</ul>

のように十字キーやマウスを使うことなく効率的にコーディングすることができます。

テキスト付きの要素を作成

前述ではh2タグを空タグで作成して、その後にテキストを入力していました。Emmetではテキスト付きの要素を作成することもできます。

h2#title.text-5xl.font-semibold{タイトル}
->
<h2 id="title" class="text-5xl font-semibold">タイトル</h2>

少し注意点すべき点があるとすれば、Copilotなどが有効になっていると、{を入力したあと、CSSのプロパティを候補として提示することがあり、何も考えずに[TAB]を押すと変換できない場合がある点です。初めての場合になりやすいので注意しましょう。

ダミーテキストを作成

デザインを確認するために実際のコンテンツの代わりにダミーテキストを挿入したいということがあります。

このような場合にはloremを入力して[ENTER/RETURN or TAB]を入力すると、

lorem[ENTER/RETURN or TAB]
Lorem ipsum dolor sit amet consectetur adipisicing elit. Architecto nisi facere, velit facilis quo rerum quae eveniet animi alias, voluptate rem, tempora placeat ut. Voluptates saepe earum nesciunt! Repudiandae, earum.

のようにダミーテキストが作成されます。

独自の属性付きの要素を作成

ピュアなHTMLのタグしか生成できないというわけではなく、独自の属性をつけることもできます。

例えば、Vue.jsのv-ifディレクティブをもったdivタグを作成するとします。v-ifディレクティブが真になる条件はisShowtrueになる場合とします。

div[v-if="isShow"]
->
<div v-if="isShow"></div>

今回はVueのディレクティブの例を示しましたが、aria-*属性などにも使用できるため、利用シーンは多いと思います。

CSSプロパティの作成

あまり知られていないかもしれませんが、CSSのプロパティを省略記法で作成することもできます。

.title {

}

というセレクタがあるとき、

.title {
  mb10[ENTER/RETURN or TAB]
}

のように省略記法をでプロパティを書くと、

.title {
  margin-bottom: 10px;
}

のようにプロパティが作成されます。

HTMLの場合と異なり、省略記法を覚えていないと使えませんが、ある程度法則性があり、Tailwind CSSのクラス名と同じようなルールのものもあるので、よく使うものから覚えていくのがよいと思います。

Emmetチートシート

Emmetの使い方をまとめたチートシートが公開されています。

HTMLとCSSの両方をサポートしていますので、是非ご活用ください。

EmmetとCopilotの使い分け

少ないタイピング量でコードを生成するといえば、CopilotやTabnineなどの生成AIがあります。

生成量という意味では生成AIに軍配が上がりますが、必ずしも意図した内容が生成されるとは限りません。同じような内容を何度も生成する場合、定石のような内容を生成する場合、どう書けばいいかわからない場合などは生成AIを使用し、何を出力したいのかがはっきりしている場合は生成AIが提示する候補を[ESC]でキャンセルしてEmmetの省略記法を使うのがよいと思います。

どちらか一方だけを使うのではなく、それぞれの長所と短所を理解し、適したツールを選択していくことを大切です。

コーディング時の意識をアップデートする

HTMLのコーディング時にEmmetを活用する場合、コーディング時の意識をアップデートするようにしていくことが必要かもしれません。

Emmetを使わないときは、タグの構造だけに着目してタグを作成し、その後にデザインを整えるためにクラスをどこにつけようか、といった流れで書くことができます。

例えば、3つの列を持つテーブルを作成する場合、

<table>
  <thead>
    <th>
      <td></td>
      <td></td>
      <td></td>
    </th>
  </thead>
  <tbody>
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
</table>

のようにタグの構造を作成してから、テーブル全体をデザインするためにdata-tableクラスをtableタグにつけて、ヘッダー部分をデザインするためにtheadtable-headerをつけて、ボディ部分をデザインするためにtbodytable-bodyクラスをつけて、といったように後からつけていくことができます。

<table class="data-table">
  <thead class="table-header">
    <th>
      <td></td>
      <td></td>
      <td></td>
    </th>
  </thead>
  <tbody class="table-body">
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
</table>

一方、Emmetを活用しようとすると、タグの構造を考えるときにそのタグにどんな意味を持たせるかということを考えながらやった方が効率的に生成できます。

// データテーブルを意味するtableを用意して、
table.data-table
↓
// その中にヘッダーを意味するtheadを用意して、
table.data-table>thead.table-header
↓
// ヘッダータイトルはまだ決めていないけど、3列用意しよう
table.data-table>thead.table-header>tr>td*3
↓
// さらにボディ部分を意味するtbodyを用意して、
table.data-table>thead.table-header>tr>td*3^tbody.table-body
↓
// 同じように3列用意しよう
table.data-table>thead.table-header>tr>td*3^^tbody.table-body>tr>td*3[ENTER/RETURN or TAB]
->
<table class="data-table">
  <thead class="table-header">
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </thead>
  <tbody class="table-body">
    <tr>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>
</table>

思考の順序と省略記法の書く順序が一致すると、もっとも自然にもっとも効率的にコーディングすることができます。これは慣れが必要となるので、最初は声に出しながら何度もトレーニングするのがよいでしょう。

まとめ

Emmetを活用することで効率的にHTMLやCSSを効率的にコーディングできるようになります。ただし、効率性を高めるにはCopilotとの使い分けをうまくやったり、コーディング時の意識をアップデートする必要があります。

Emmet以外にも効率的にコーディングを効率化するためのプラグイン・拡張機能やツールがあります。少しずつ活用できる幅を広げてコーディングを爆速にしていくのがよいと思います。

参考文献

[CSS]疑似クラス:first-child、:last-child、:nth-childを活用して特定の要素にスタイルを適用しよう

ウェブサイト制作をしていると、繰り返し登場する任意の要素にスタイルを適用したい場面が多々あります。特に、リストやテーブルの特定の項目に異なるデザインを施す際に便利なのがCSSの疑似クラスです。この記事では、:first-child:last-child:nth-childの疑似クラスを活用し、特定の要素にスタイルを適用する方法を学びます。

疑似クラスとは

疑似クラスは、CSSでHTML要素に追加のクラスを付けなくても特定の条件に基づいてスタイルを適用するためのものです。これにより、HTMLを変更せずにスタイル制御が可能になります。例えば、リスト項目の最初や最後の要素に特別なスタイルを適用することができます。

疑似クラスを使うとコードが簡潔になり、HTMLとCSSの分離が保たれるため、メンテナンス性が向上します。

:first-child疑似クラス

:first-child疑似クラスは、親要素の中で最初の子要素を選択するための擬似クラスです。

.container :first-child {
  ...
}

このように書くことで、containerクラスの子要素のうち、最初の子要素を選択することができます。

:last-child疑似クラス

:last-child疑似クラスは、親要素の中で最後の子要素を選択するための擬似クラスです。

.container :last-child {
   ...
}

このように書くことで、containerクラスの子要素のうち、最後の子要素を選択することができます。

:nth-child疑似クラス

:nth-child疑似クラスは、親要素の中でn番目の子要素を選択するための擬似クラスです。nの部分には、数字やキーワード、または数式が入ります。

.container :nth-child(2) {
  ...
}

このように書くことで、containerクラスの子要素のうち、2番目の子要素を選択することができます。

:nth-last-child疑似クラス

:nth-child疑似クラスは、:nth-childの逆順で選択するための疑似クラスです。

.container :nth-last-child(2) {
  ...
}

このように書くことで、containerクラスの子要素のうち、最後から2番目の子要素を選択することができます。

:not疑似クラス

:first-child疑似クラス、:last-child疑似クラス、:nth-child疑似クラス、:nth-last-child疑似クラスの選択を否定したい場合、:not疑似クラスを使用します。

.container :not(:first-child) {
  ...
}

このように書くことで、containerクラスの子要素のうち、最初の要素以外を選択することができます。

要素の適用に対する注意点

疑似クラスの適用範囲について、気をつけておいた方がよい点が2つあります。

親要素と子要素の関係性

例えば、次のようなHTMLを考えてみます。

<div class="container">
  <div class="item">1-1</item>
  <div class="item">1-2</item>
  <div class="item">1-3</item>
</div>
<div class="container">
  <div class="item">2-1</item>
  <div class="item">2-2</item>
  <div class="item">2-3</item>
</div>
<div class="container">
  <div class="item">3-1</item>
  <div class="item">3-2</item>
  <div class="item">3-3</item>
</div>

このHTMLに対して、

.item:nth-child(odd) {
  color: red;
}

を適用すると、どの文字が赤字になるでしょうか?

実際にやってみると一目瞭然ですが、

のように親要素.containerごとに子要素.itemの奇数番目の要素が赤字になることを確認することができます。同じ子要素の指定だとしても親要素を超えて処理されないという点に注意が必要なため、誤解や誤認を避けるために

.item:nth-child(odd) {
  color: red;
}

のように子要素だけ定義するのではなく、

.container .item:nth-child(odd) {
  color: red;
}

のように、親要素 子要素:疑似クラスのように必ず親要素をつけて定義する方がよいと思います。

以降の説明でも、親要素をつけて定義する形式でスタイルを定義するようにしています。

複数種類の子要素が混在している場合

テーブルのように単一の子要素のみで構成される場合は問題ありませんが、複数種類の子要素が混在している状況では期待したとおりにスタイルが適用されない場合があります。

例えば、次のようなHTMLを考えてみます。

<div class="container">
  <h2>タイトル</h2>
  <p class="phrase">1行目</p>
  <p class="phrase">2行目</p>
  <p class="phrase">3行目</p>
  <p class="phrase">4行目</p>
  <p class="phrase">5行目</p>
</div>

phaseクラスが定義されたp要素以外にh2要素があります。

このHTMLに対して次のスタイルを適用します。

.container .phrase:nth-child(2n) {
  color: red;
}

このスタイルでは、phaseクラスが適用された要素の偶数行目の文字を赤字にします。

実際にやってみると、期待したとおりの結果になりませんでした。疑似クラスを使用したとき、その要素が何個目であるかは指定したクラス(今回はphraseクラス)の中で何個目かではなく、親要素から見たときに何個目の要素かで決まります。

すなわち、タイトルが1個目、1行目が2個目、2行目が3個目、・・・という風に数えられ、その中で指定したクラス(今回はphraseクラス)にのみスタイルが適用されます。

このことを確認するために、:first-child疑似クラスを適用してみて色が変わらないこと、:last-child疑似クラスを適用してみて色が変わることを確認しましょう。

まずは、:first-child疑似クラスを確認します。

.pattern .phrase:first-child {
  color: red;
}

:first-child疑似クラスで指しているのはタイトルで、phaseクラスが適用されていないため、色は変わりませんでした。

次に、:last-child疑似クラスを確認します。

.pattern .phrase:last-child {
  color: red;
}

:last-child疑似クラスで指しているのは4行目で、phaseクラスが適用されているため、色は変わりました。

1つの親要素の中に複数種類の子要素が混在する場合、何個目かは要素の種類に関係なく親要素から見て何個目かで数える点に留意してください。

パターン別

今回はすべて、以下のHTMLに対して適用するパターンで説明します。

<!DOCTYPE html>
<html lang="en">
  <body>
    <div class="container">
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
    </div>
  </body>
</html>

スタイルが適用されている要素はアクアで色づけし、スタイルが適用されていない要素はグレーのままになるようにします。

最初の要素にのみ適用

最初の要素にのみ適用したい場合は、:first-child疑似クラスを使用します。

.container .item:first-child {
  background-color: aqua;
}

最後の要素にのみ適用

最後の要素にのみスタイルを適用したい場合は、:last-child疑似クラスを使用します。

.container .item:last-child {
  background-color: aqua;
}

最初と最後の要素に適用

:first-child疑似クラスと:last-child疑似クラスを組み合わせることで、最初と最後のようにスタイルを適用することができます。

.container .item:first-child,
.container .item:last-child {
  background-color: aqua;
}

最初の要素以外に適用

最初の要素以外にスタイルを適用したい場合、:first-child疑似クラスとそれを否定する:not疑似クラスを組み合わせることで実現できます。

.container .item:not(:first-child) {
  background-color: aqua;
}

最後の要素以外に適用

最後の要素以外にスタイルを適用したい場合は、:last-child疑似クラスとそれを否定する:not疑似クラスを組み合わせることで実現できます。

.container .item:not(:last-child) {
  background-color: aqua;
}

最初と最後の要素以外に適用

最初と最後の要素以外にスタイルを適用したい場合、:first-child疑似クラス、:last-child疑似クラス、:not疑似クラスを組み合わせて実現します。こちらは最初の要素以外 かつ 最後の要素以外というAND条件になりますので、OR条件の場合とは書き方が異なります。

.container .item:not(:first-child):not(:last-child) {
  background-color: aqua;
}

偶数個目の要素に適用

テーブルの行をストライプにするときによく使われるのが偶数個目または奇数個目の要素にスタイルを適用する方法です。これには:nth-child疑似クラスを使用します。この書き方には2つあるのでそれぞれ説明します。

まずはnを使って書く方法です。nを使って偶数をあらわすためには2nと書きます。

.container .item:nth-child(2n) {
  background-color: aqua;
}

もう少し簡単に書く方法があります。偶数をあらわすevenを使います。

.container .item:nth-child(even) {
  background-color: aqua;
}

奇数個目の要素に適用

奇数個目の要素に適用する方法も2つあります。

まずはnを使って書く方法です。nを使って奇数をあらわすには2n+1と書きます。

.container .item:nth-child(2n+1) {
  background-color: aqua;
}

偶数のときと同じように簡単に書く方法があります。奇数をあらわすoddを使います。

.container .item:nth-child(odd) {
  background-color: aqua;
}

特定の要素に適用

:nth-child疑似クラスを使うことで特定の要素にスタイルを適用することができます。

一例として、3個目の要素にのみ適用する場合を考えてみます。:nth-child疑似クラスに3を指定します。

.container .item:nth-child(3) {
  background-color: aqua;
}

ただし、:nth-child疑似クラスは万能ではありません。書けないケースや書き方に工夫が必要なケースもあります。

以下のようなことは:nth-child疑似クラスで実現可能です。

  1. 特定の順序の要素を選択
    • :nth-child(2)は、親の中で2番目に位置する子要素を選択します
  2. 特定のパターンに基づく要素を選択
    • :nth-child(odd)または:nth-child(2n+1)は、奇数番目の要素を選択します
    • :nth-child(even)または:nth-child(2n)は、偶数番目の要素を選択します
    • :nth-child(3n)は、3番目、6番目、9番目など、3の倍数の位置にある要素を選択します
  3. 複雑なパターンで要素を選択
    • :nth-child(3n+1)は、1番目、4番目、7番目など、3つおきに要素を選択します
    • :nth-child(-n+3)は、最初の3つの要素(1番目、2番目、3番目)を選択します
  4. 他の疑似クラスとの組み合わせ
    • :nth-child(2):hoverのように、特定の順序にある要素がホバーされたときのスタイルを指定できます
  5. 特定のタグに対して使用
    • p:nth-child(3)のように、特定のタグ(例えばp要素)が兄弟要素の中で指定された順序に位置する場合にスタイルを適用できます

一方で以下のようなことは:nth-child疑似クラスではで実現できません。

  1. 特定のクラスや属性を持つ要素を選択
    • 前述の注意点でも挙げたとおり、:nth-child疑似クラスは要素の順序に基づいているため、クラス名や属性を無視します。例えば、p.special:nth-child(2)のように、特定のクラスを持つ2番目の要素を選択することはできません
  2. 逆順の選択
    • :nth-child疑似クラスは要素の逆順での選択はできません。例えば、末尾から2番目の要素を選択することはできません。ただし、:nth-last-child疑似クラスを使用することで実現可能です
  3. 特定の要素タイプに対してだけの選択
    • :nth-child疑似クラスは指定された順序にあるすべての子要素を対象とするため、特定の要素タイプだけを選択することはできません。例えば、特定の順序にある div要素だけを選択することはできません。div:nth-child(2)は、2番目の子要素がdiv要素である場合にのみ適用されます
  4. an+bの形式であらわせない要素を選択
    • :nth-child疑似要素では、2などの特定値での指定、evenまたはoddan+bの形式(abは省略可)のいずれかの方法でしか指定できません。そのため、可変個数の要素のちょうど真ん中の要素に対してスタイルを適用するということはできません

an+bの形式であらわせない形式であっても工夫によって表現可能な場合があります。例えば、1番目と4番目の要素に対してスタイルを適用したい場合、

.container .item:nth-child(1,4) {
  background-color: aqua;
}

とは書けませんが、

.container .item:nth-child(1),
.container .item:nth-child(4) {
  background-color: aqua;
}

と書くことで実現できます。

まとめ

:first-child疑似クラス、:last-child疑似クラス、:nth-child疑似クラス(または:nth-last-child疑似クラス)および:not疑似クラスを使用することで、一部制約はあるものの様々要素を指定することができるようになります。

テーブルをストライプ模様にする以外にも、最初と最後の要素以外にマージンを設けたり、最初の要素だけデザインを変えたりなど、工夫によって様々なことができるようになります。

指定方法には少し注意すべき点がありますが、活用することでデザインの幅はさらに広がることでしょう。

テキストの改行処理は多くの場合デフォルトでいいかもしれない

ここ最近、テキストが折り返されずにはみ出るとかテキストが折り返されるがエリアからはみ出るといった不具合に関わることが多かったので、少し調べてみました。

結論

比較検証を色々してもよかったのですが、結論がかなりシンプルなので結論だけ書いていきます。

基本的にはoverflow-wrapword-breakは不要

多くのケースではoverflow-wrapword-breakによる改行処理は不要だと思います。親要素で幅を制限し、データ量に応じて高さが変わるようになっているのであれば、自然に改行してくれます。

対象が文章であっても禁則処理まで求められるケースは多くない印象です。

テストデータやダミーデータには注意が必要

abc...」のような英字の羅列は1つの単語と見なして途中では折り返されません。テスト時やダミーデータを登録する場合などにこのような文字列を設定しがちですが、想定外の文字列を設定しているのであればバグではないため、設定する文字列を見直しましょう。

コードやIDには注意

コードやIDが固定長であれば折り返さずに表示できる幅を確保するようにデザインすることを検討してください。コードやIDの視認性を考えると折り返さない方が読みやすくなります。

一方で、コードやIDが可変長であったり、複数のコードやIDが同じエリア内に混在するような場合、一部のコードやIDが想定した幅を超えることがあります。このような場合、折り返しを実現する方法として、word-break: break-allの使用を検討してください。break-allを指定した場合、単語の途中でも折り返しますが、コードやIDであれば機械的に端で折り返す方が適していると思います。

複数のシステムと関連していたり、歴史的な理由でコードなのに可変ということは結構あります。現行システムのデータなどを分析して複数の桁のデータが存在していることが確認できた場合は、何桁までを折り返さずに表示できるようにするとよいのか確認した方がよいと思います。

利用者の特性によっては一部の項目にword-break: break-allの使用を検討する

利用者によっては一部の項目にword-break: break-allの使用を検討しなければならないかもしれません。業種、企業風土、利用者のWebリテラシーなど様々な要因によって決まるため一概には言えませんが、主に備考欄や特記事項欄のようなフリー入力欄ではテストデータやダミーデータで入力されがちな自然に折り返すことができないテキストを入力する場合がありますので、word-break: break-allの使用可否を検討することをおすすめします。

テキストの省略には注意が必要

すべての文字がエリア内に収まらない場合、CSSを使って「...」で省略することができます。ただし、省略することで区別不可能になる場合があるため、使いどころには注意が必要です。

例えば、「東京都中央区第一支社」「東京都中央区第二支社」という文字列がある場合に、これを幅の問題で「東京都中央区第…」のように省略しなくてはならないケースを考えてみます。この場合、省略されていると「第一支社」なのか「第二支社」なのか区別がつきません。テキストにマウスカーソルを当てるとすべてのテキストがツールチップで表示する場合もありますが、想定内の操作をしているだけで、マウスカーソルを当てるという余計な操作を余儀なくされるのは、利用者にとっては有益なことではないと思います。

省略する場合、JavaScriptなどで「東京都…第一支社」のように省略する方法も検討した方がよいかもしれません。

まとめ

テキストが折り返されずにエリアを貫通する問題はほとんど問題にならないと考えてよさそうですが、テスト時やダミーデータ設定時には正しくデータを想定して設定することが重要です。

また、一部の状況においてはword-break: break-allの使用を検討する必要がありますが、とりあえず設定するのではなく、十分検討した上で設定するようにするとよいでしょう。

モバイルバージョンを終了