Emmet: プロジェクト1 — Emmetで完全なログインページを一気に書く(第1〜16回の組み合わせ)

第1〜16回を通じて、あなたはEmmetの8大構文カテゴリ、3つのコアアクション、5つの編集高速化アクションを学びました — しかしすべては孤立した「断片」の例でした。このレッスンは最初の総合ハンズオンプロジェクトです:1行のEmmet省略記法で完全な70行のログインページHTMLを書きます。アリスはフォーム全体を10秒で書きます — 手打ちより10倍高速です。

1. 学習内容


2. あるフロントエンド開発者の実話

(1) 課題:3入力 + 2ボタン + 3リンク + タイトル — 手打ちで10分

アリスはSaaSプラットフォームのフロントエンド開発者です。2026年7月、プロダクトマネージャーが緊急通知を出しました:今週中に管理ダッシュボードにログインページを追加、来週月曜日にローンチ。Figmaデザインには5セクションがあります:

セクション 要素チェックリスト
1. ブランドヘッダー 製品名「CLOUDFLOW」を表示する<span>
2. タイトルエリア <h1> Welcome Back + <p> サブタイトル
3. フォーム ユーザー名 / パスワード 2入力 + ラベル + チェックボックス + パスワード忘れリンク
4. 送信ボタン プライマリ「Sign In」ボタン + セカンダリ「Google」/「GitHub」ソーシャルログインボタン
5. サインアップ案内 下部「Don't have an account? Sign Up Now」リンク

合計:1 <span>、1 <h1>、1 <p>、2 <input>、2 <label>、1 <button>、パスワード忘れ用1 <a>、ソーシャルログイン用2 <button>、サインアップ用1 <a> = 11フォーム要素 + 1ブランドスパン。手打ちHTML:

HTML
<span class="brand-name">CLOUDFLOW</span>
<h1 class="title">Welcome Back</h1>
<p class="subtitle">Continue with your account</p>
<form id="loginForm" action="/login" method="post">
  <div class="field">
    <label for="user">Username</label>
    <input id="user" class="input" type="text" name="user" placeholder="Enter your username" required>
  </div>
  <div class="field">
    <label for="pwd">Password</label>
    <input id="pwd" class="input" type="password" name="pwd" placeholder="Enter your password" required>
  </div>
  <div class="field-row">
    <label class="checkbox">
      <input type="checkbox" name="remember"> Remember me
    </label>
    <a class="help" href="/forgot">Forgot Password?</a>
  </div>
  <button type="submit" class="btn btn-primary">Sign In</button>
</form>
<div class="divider"><span>or</span></div>
<div class="social">
  <button class="social-btn" type="button">Google</button>
  <button class="social-btn" type="button">GitHub</button>
</div>
<p class="footer">Don't have an account? <a href="/signup">Sign Up Now</a></p>

合計32行の手打ちHTML、さらにすべての属性詳細(id / class / type / name / placeholder / required / for / action / method)。アリスは8〜10分かかると見積もりました — そして属性の欠落(requiredを忘れてフォームバリデーションが壊れるなど)が起こりやすいです。

(2) Emmet一発解決策

アリスはVSCodeを開き、!を押してHTMLスケルトンを展開し、<body>に移動して1行の省略記法を入力します:

HTML
div.login-container>div.login-card>(.brand>span.brand-name{CLOUDFLOW})+h1.title{Welcome Back}+p.subtitle{Continue with your account}+form#loginForm[action=/login method=post]>(.field>label[for=user]{Username}+input#user.input[type=text name=user placeholder="Enter your username" required])+(.field>label[for=pwd]{Password}+input#pwd.input[type=password name=pwd placeholder="Enter your password" required])+(.field-row>(label.checkbox>input[type=checkbox name=remember]{Remember me})+a.help[href="/forgot"]{Forgot Password?})+button[type=submit].btn.btn-primary{Sign In}+.divider{or}+.social>(button.social-btn{Google})+(button.social-btn{GitHub})+p.footer{Don't have an account?}+a[href="/signup"]{Sign Up Now}

Tabを押すと、32行のHTMLが一気に表示されます。アリスはわずか10秒しか費やしませんでした — 手打ちより48〜60倍高速です。さらに重要なのは:属性の欠落ゼロrequired / placeholder / forがすべて含まれている)、タイプミスゼロ。

(3) メリット

アリスは「プロジェクト1」をフォーム部分10秒で完了しました — 手打ちより48〜60倍高速で、属性欠落ゼロ、タイプミスゼロ。最大の利点は速度ではなく「属性欠落」バグの80%を排除することです — 手打ちではrequiredforを忘れがちですが、Emmet省略記法ではこれらの詳細は省略記法の不可欠な「コンポーネント」であり、見逃せません。来週月曜のローンチ前にQAが一発で合格、リグレッションゼロ。


3. ログインページ要素チェックリスト:5セクションをEmmet演算子にマッピング

以下の表は5つのセクションすべてを特定のEmmet演算子にマッピングします — これは重要な「要件分解」ステップです。

セクション 要素 Emmet省略記法 対象構文(レッスン)
1. ブランドヘッダー <span class="brand-name">CLOUDFLOW</span> span.brand-name{CLOUDFLOW} 第3回 暗黙的タグ + 第9回 テキスト
2. タイトルエリア <h1 class="title"> + <p class="subtitle"> h1.title{...}+p.subtitle{...} 第4回 兄弟 + 第3回 クラス + 第9回 テキスト
3. フォーム <form id="loginForm" action="..." method="...">が複数の<div class="field">をネスト form#loginForm[action=/login method=post]>(.field>...) 第4回 子 + 第7回 ID + 第8回 カスタム属性 + 第6回 グループ化 + 暗黙的タグ
4. 送信ボタン <button type="submit" class="btn btn-primary">Sign In</button> button[type=submit].btn.btn-primary{Sign In} 第8回 カスタム属性 + 第7回 複数クラス + 第9回 テキスト
5. ソーシャルログイン <div class="social">内に2つの<button> .social>(button.social-btn{Google})+(button.social-btn{GitHub}) 第6回 グループ化 + 第5回 乗算(*2も使用可)+ 暗黙的タグ
📌 ポイント:この表は「Emmetハンズオン実践のコアメソッド」です — まずページ��セクションに分解し、次にセクションを要素に分解し、最後に要素をEmmet省略記法に変換する。この3ステップの思考チェーンが「Emmet初心者」から「Emmetエキスパート」への鍵です。


4. 一括Emmet省略記法(コア)

以下の3つの例が最小単位から完全なフォームまで構築します — 「一発」思考プロセスを示します。

(1) ▶ サンプル: タイトルブロック h1.title{Welcome Back}(難易度:★)

最小単位:クラスとテキストを持つ単一の<h1>

省略記法:

HTML
h1.title{Welcome Back}

展開結果:

HTML
<h1 class="title">Welcome Back</h1>

出力:<h1>見出しとしてレンダリングされます。class="title"はCSSセレクタでターゲットにできます(例:.title { font-size: 28px; })。

TEXT 📖 参照専用
分解:`h1`は要素名(HTML第3回)、`.title`はクラス(第7回)、`{Welcome Back}`はテキストコンテンツ(第9回)。3つの構文ポイ��トが組み合わさっています — これがEmmetの「最小完全単位」です。

(2) ▶ サンプル: フォームフィールドペア label[for=user]{Username}+input#user.input[type=text name=user placeholder="Enter your username" required](難易度:★★)

1つのフォームフィールド:<label> + <input>、for/id関連付け + 複数属性付き。

省略記法:

HTML
label[for=user]{Username}+input#user.input[type=text name=user placeholder="Enter your username" required]

展開結果:

HTML
<label for="user">Username</label>
<input id="user" class="input" type="text" name="user" placeholder="Enter your username" required>

出力:1 <label> + 1 <input>としてレンダリングされます。<label for="user">id="user"経由で<input>と関連付けられます(ラベルをクリックすると入力にフォーカス)。<input>は6つの属性を持ちます:id / class / type / name / placeholder / required

TEXT 📖 参照専用
分解:省略記法の「情報密度」は手打ちをはるかに超えています —
- 3構文ポイント:`#user`(id)、`.input`(クラス)、`[type=text]`(属性)
- 5つの属性キーバリューペア:`type=text` / `name=user` / `placeholder="Enter your username"` / `required`(ブール属性、値なし)
- 1テキスト:`{Username}`
合計:9つのHTML要素属性、省略記法はわずか95文字 — 同じ属性を手打ちすると200文字以上になります。

(3) ▶ サンプル: 完全なログインフォーム(コア1行省略記法)(難易度:★★)

完全なフォーム:1 <form> + 2 <div class="field">(各々label+input付き)+ 1 <div class="field-row">(checkbox+link付き)+ 1 <button>

省略記法:

HTML
form#loginForm[action=/login method=post]>(.field>label[for=user]{Username}+input#user.input[type=text name=user placeholder="Enter your username" required])+(.field>label[for=pwd]{Password}+input#pwd.input[type=password name=pwd placeholder="Enter your password" required])+(.field-row>(label.checkbox>input[type=checkbox name=remember]{Remember me})+a.help[href="/forgot"]{Forgot Password?})+button[type=submit].btn.btn-primary{Sign In}

展開結果:

HTML
<form id="loginForm" action="/login" method="post">
  <div class="field">
    <label for="user">Username</label>
    <input id="user" class="input" type="text" name="user" placeholder="Enter your username" required>
  </div>
  <div class="field">
    <label for="pwd">Password</label>
    <input id="pwd" class="input" type="password" name="pwd" placeholder="Enter your password" required>
  </div>
  <div class="field-row">
    <label class="checkbox"><input type="checkbox" name="remember">Remember me</label>
    <a class="help" href="/forgot">Forgot Password?</a>
  </div>
  <button type="submit" class="btn btn-primary">Sign In</button>
</form>

出力:2つの入力フィールド(Username / Password)+ 1チェックボックス(Remember me)+ 1パスワード忘れリンク + 1 Sign Inボタンを持つ完全なログインフォームとしてレンダリングされます。

TEXT 📖 参照専用
分解:この省略記法は第1〜16回のすべてのコア構文を連結しています —
- `form#loginForm`:要素名 + ID(第3回 + 第7回)
- `[action=/login method=post]`:2つのカスタム属性(第8回)
- `>(...)`:子ネスト + グループ化(第4回 + 第6回)
- `.field` / `.field-row`:暗黙的`div`タグ(第3回)
- `label[for=user]{Username}`:要素 + カスタム属性 + テキスト(第8回 + 第9回)
- `input#user.input[type=text ...]`:ID + 複数クラス + 複数属性(第7回 + 第8回)
- `+`:兄弟ノード(第4回)
- `button[type=submit].btn.btn-primary{Sign In}`:複数属性 + 複数クラス + テキスト(第7回 + 第8回 + 第9回)
合計:14 HTMLタグ、35以上の属性 — 手打ち200文字以上、省略記法270文字が14タグに展開、すべての属性付き。

5. 省略記法の分解:すべての記号の構文意味

前セクションの「完全なフォーム」省略記法は270文字あり、一見すると圧倒されます。5セグメントに分解してすべての記号を説明しま��ょう:

セグメント 省略記法断片 構文���イント 意味
1 form#loginForm[action=/login method=post] 要素 + ID + カスタム属性(第3+7+8回) <form id="loginForm" action="/login" method="post">
2 >(...) 子 + グループ化(第4+6回) フォーム内部に入り、グループとしてラップ
3 (.field>label[for=user]{Username}+input#user.input[type=text name=user placeholder="Enter your username" required]) 暗黙的div + 子 + 要素 + 属性 + ID + クラス + テキスト(第3+4+7+8+9回) 1つの.fieldグループ:label + inputを含む
4 +(.field>label[for=pwd]{Password}+input#pwd.input[type=password name=pwd placeholder="Enter your password" required]) 兄弟ノード + セグメント3構造の繰り返し 2つ目の.field(パスワードフィールド)、セグメント3の兄弟
5 +(.field-row>(label.checkbox>input[type=checkbox name=remember]{Remember me})+a.help[href="/forgot"]{Forgot Password?})+button[type=submit].btn.btn-primary{Sign In} 兄弟ノード + 多層グループ化 + 複数属性ボタン チェックボックス + パスワード忘れ + Sign Inボタン
📌 ポイント:セグメント5が最も複雑です — .field-rowは2つの兄弟(label.checkbox + a.help)をネストし、その後+button[type=submit]を追加。多層グループ化 + 兄弟ネストが上級Emmetのコアです — 習得すれば「1行 = 20行のHTML」を書けるようになります。


6. 完全な例:ログインページ一発 — 70行

上記のコア省略記法を完全なHTMLページ(<!DOCTYPE> / <head> / <style> / <body>ラッパー + 完全なCSSスタイルを含む)に埋め込むと、70行の完全なログインページが得られます。この例がこのレッスンのコアです — 「試す」ボタンはありません(仕様v2.5ゲート#26により、総合例はエディタでプレビューされません)。

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>管理者ダッシュボード - サインイン</title>
  <meta name="description" content="SaaS管理者ダッシュボード ログインページ">
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: system-ui, -apple-system, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }
    .login-container { width: 100%; max-width: 420px; }
    .login-card { background: #fff; padding: 40px; border-radius: 12px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); }
    .brand { text-align: center; margin-bottom: 24px; }
    .brand-name { font-size: 18px; font-weight: 700; color: #2c3e50; letter-spacing: 1px; }
    .title { font-size: 28px; color: #2c3e50; text-align: center; margin-bottom: 8px; font-weight: 700; }
    .subtitle { color: #7f8c8d; text-align: center; margin-bottom: 32px; font-size: 14px; }
    .field { margin-bottom: 20px; }
    label { display: block; color: #34495e; margin-bottom: 8px; font-size: 14px; font-weight: 500; }
    .input { width: 100%; padding: 12px 16px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; transition: border-color 0.2s; }
    .input:focus { outline: none; border-color: #3498db; box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.15); }
    .field-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; font-size: 14px; }
    .checkbox { display: flex; align-items: center; gap: 8px; color: #7f8c8d; cursor: pointer; }
    .checkbox input { margin: 0; cursor: pointer; }
    .help { color: #3498db; text-decoration: none; }
    .help:hover { text-decoration: underline; }
    .btn { width: 100%; padding: 14px; border: none; border-radius: 8px; font-size: 16px; font-weight: 600; cursor: pointer; transition: background 0.2s; }
    .btn-primary { background: #3498db; color: #fff; }
    .btn-primary:hover { background: #2980b9; }
    .divider { display: flex; align-items: center; margin: 24px 0; color: #95a5a6; font-size: 13px; }
    .divider::before, .divider::after { content: ''; flex: 1; height: 1px; background: #ddd; }
    .divider span { padding: 0 16px; }
    .social { display: flex; gap: 12px; }
    .social-btn { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 8px; background: #fff; cursor: pointer; font-size: 14px; }
    .social-btn:hover { background: #f8f9fa; }
    .footer { text-align: center; margin-top: 24px; color: #7f8c8d; font-size: 14px; }
    .footer a { color: #3498db; text-decoration: none; font-weight: 500; }
  </style>
</head>
<body>
  <main class="login-container">
    <div class="login-card">
      <div class="brand">
        <span class="brand-name">CLOUDFLOW</span>
      </div>
      <h1 class="title">Welcome Back</h1>
      <p class="subtitle">Continue with your account</p>
      <form id="loginForm" action="/login" method="post">
        <div class="field">
          <label for="user">Username</label>
          <input id="user" class="input" type="text" name="user" placeholder="Enter your username" required>
        </div>
        <div class="field">
          <label for="pwd">Password</label>
          <input id="pwd" class="input" type="password" name="pwd" placeholder="Enter your password" required>
        </div>
        <div class="field-row">
          <label class="checkbox">
            <input type="checkbox" name="remember"> Remember me
          </label>
          <a class="help" href="/forgot">Forgot Password?</a>
        </div>
        <button type="submit" class="btn btn-primary">Sign In</button>
      </form>
      <div class="divider"><span>or</span></div>
      <div class="social">
        <button class="social-btn" type="button">Google</button>
        <button class="social-btn" type="button">GitHub</button>
      </div>
      <p class="footer">Don't have an account? <a href="/signup">Sign Up Now</a></p>
    </div>
  </main>
</body>
</html>

出力:ブラウザは完全なSaaS管理者ログインページをレンダリングします — 紫色グラデーション背景、中央の白カード、ブランド名「CLOUDFLOW」、Welcome Backタイトル、ユーザー名/パスワードフォーム(ラベル関連付けとrequired検証付き)、Remember meチェックボックス、Forgot Passwordリンク、青いSign Inボタン、「or」区切り線、Google/GitHubソーシャルログイン、下部のサインアップ��内。すべてのスタイルは<style>��インライン化され、外部依存ゼロ、サードパーティライブラリゼロ。

TEXT 📖 参照専用
分解:このレッスンの70行のHTMLは第1〜16回のすべてのHTML省略記法構文を連結し��います —
- `<style>`ブロック(25行のCSS)は手打ちまたはCSS省略記法(第11〜13回)で書かれます。このレッスンではHTML部分に焦点を当てます
- `<body>`内部の`<main class="login-container">`から`</main>`までの32行のHTMLは1回のEmmet省略記法展開で生成されます
- 行数比較:32行のHTMLを手打ちすると8分。Emmet省略記法270文字 + Tab展開で10秒。**48倍の速度向上、属性欠落率が20%から0%に**

🌐 自分で試す:このレッスンのコア省略記法form#loginForm[action=/login method=post]>(.field>label[for=user]{Username}+input#user.input[type=text name=user placeholder="Enter your username" required])+(.field>label[for=pwd]{Password}+input#pwd.input[type=password name=pwd placeholder="Enter your password" required])+button[type=submit].btn.btn-primary{Sign In}Emmet Live Demoに入力し、Tabを押してリアルタイム展開を確認してください。


❓ よくある質問

Q Emmet省略記法で英語以外のテキストを使用できますか?
A はい、制限付きで可能です。テキストコンテンツ({text}内)には任意の文字を含めることができます — 中国語、絵文字、スペースを含みます。ただし、スペースを含む属性値([attr=val]内)は引用符で囲む必要があります(例:[placeholder="Enter your username"])。ID/クラスに非英文字を使用することは避けてください — CSSセレクタの非英文字ID/クラスとの互換性が低いためです(古いIEバージョンではサポートされません)。ID/クラスには英語の使用を強く推奨します。
Q placeholderのような長い属性名は完全に書く必要がありますか?
A Emmetは属性名の省略記法をサポートしていません — [placeholder=...]は完全に書く必要があります。ただし、スペースがない場合、属性値の引用符は省略できます:[type=text][type="text"]と同等です。[placeholder=Enter your username]のようにスペースを含む属性値には引用符が必要です:[placeholder="Enter your username"]。さもないとEmmetのパーサーがエラーになります。
Q フォームはどこに送信されますか?
A このレッスンの例では、action="/login"はバックエンドの/loginエンドポイントに送信することを意味します。実際の開発では、actionは通常バックエンドルートです(例:Express app.post('/login', ...)、Django path('login/', views.login))。このレッスンではHTML部分に焦点を当てています。バックエンド処理はカバーしていません。純粋なフロントエンドモックが必要な場合は、<form>action="javascript:void(0)"を使用し、JSでsubmitイベントをリッスンしてください。
Q ログインフォームにrequired属性が必要なのはなぜですか?
A requiredはHTML5の「必須検証」属性です — ブラウザがネイティブに入力が空かどうかをチェックし、空の場合は送信をブロックして「このフィールドを入力してください」と表示します。このレッスンの例では、UsernameとPasswordの両方の入力にrequiredがあります。Forgot Passwordリンクには不要です(フォームフィールドではないため)。これは「ゼロJSフロントエンド検証」のキー属性であり、すべての必須フィールドに強く推奨されます。手打ちでは忘れがちですが、Emmet省略記法では省略記法の構造的コンポーネントであるため見逃す可能性はゼロです。

📖 まとめ


📝 練習問題

  1. 基本(難易度:★):1行のEmmet省略記法でシンプルなログインページスケルトンを書いてください — 1 <h1 class="title">User Login</h1>、1 ユーザー名<input>id="email"type="email"name="email"required付き)、1 パスワード<input>id="pwd"type="password"name="pwd"required付き)、1 <button type="submit">Sign In</button>を含めます。展開後、以下を確認してください:(a) <input>type属性が正しい、(b) フォーム内の<button type="submit">がフォーム送信をトリガーする、(c) 両方のrequired属性が有効(フィールドが空の場合ブラウザが送信をブロックする)。

  2. 中級(難易度:★★):このレッスンの70行の完全な例のEmmet省略記法を書き直してください — アリスのものと完全に一致する必要はありませんが、機能的に同等でなければなりません:少なくとも1フォーム、2入力、1チェックボックス、1パスワード忘れリンク、1 Sign Inボタン、1サインアップ��ンク。2つのソーシャルログインボタン(Google、GitHub)を追加してください。あなたの省略記法とアリスの省略記法を比較し、どちらがより簡潔(文字数が少ない)かを確認してください。あなたの省略記法と展開されたHTMLの両方をスクリーンショットしてください。

  3. 応用(難易度:★★★):このレッスンの70行のログインペー��を完全な登録ページに拡張してください。ログインページのフィールドに加えて、電話番号(type="tel")、メール(type="email")、確認コード(type="text" + 右側に「コードを取得」ボタン)、利用規約チェックボックス(チェック必須)を追加してください。要件:(a) 完全なページHTMLを一発で(body部分を1つのEmmet省略記法で)、(b) 省略記法の文字数 ≤ 400(超える場合は*乗算の使用や構造の簡略化を検討)、(c) すべての入力にrequired、(d) 利用規約チェックボックスは送信前にチェック必須(ネイティブブラウザ検証に<input type="checkbox" required>を使用)。最後に、手打ち vs. Emmetの文字数と時間差を集計し、「Emmetハンズオン利点」レポートを書いてください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%