おじさんが若者たちにモテるためのモダンなHTML/CSSマークアップ

  • 426
    Like
  • 3
    Comment

タイトルに含まれる語に関する補足

おじさん:
筆者の便宜上、30歳前後のフロントエンドエンジニア、マークアップエンジニア等を指す。性別は問わない。

なぜ「モテ」なければいけないのか

「モテる」とは、最先端の流行を知り取捨選択することで、自由意志を謳歌することで実現する。

PHPとjQueryの時代は廃れ始め、AngularやReactに代表されるUIフレームワーク、ES2015やTypeScriptを流暢に扱えることがフロントエンドの責務となり、HTMLやCSSも、EJSやPug・SassやPostCSSなどのトランスパイル言語を介すことがほぼ常識になってきた(と思う)。

ところが、HTMLやCSSを何の言語で書くか以前に、中身をどうするべきかはあまり議論されていないので、「モテる」ための方法をいくつかかいつまんでまとめてみた。

セマンティックなコーディングは、開発者の課題理解度を図り、意図を明確にするもの

正しくセマンティックなマークアップをする理由は、結局のところ、「命名規則や保守性のため」「開発者自身が自分が何を書いているのか理解・明確にするため」だと思う。1

文章を組んだエディトリアルライターや、レイアウトをしたデザイナーの意図を正確に汲み取れたら、コードを書く人間の責任として、その意図を精確にマークアップしてあげたい。

具体例

太字には意味がある

以下は、一般的に太字(斜体やハイライトが施される場合もある)で表現されるHTMLタグである。

  • <b> ⇒ 文書中のキーワードとして。文中で言及する主要なテーマとして。
  • <em> ⇒ 文のニュアンスを明示するための強調として。
  • <strong> ⇒ 重要事項であること、深刻な問題であることを示すための強調として。
  • <mark> ⇒ ユーザーがアクションを起こし、結果的に注目することになった部分として。
  • <dfn> ⇒ 固有名詞や専門用語、独自サービス名などの定義語として。

<span style="font-weight: bold;> でも見た目は同じだけど、それはただの「意味のない太字のテキスト」なのだ。

強調の対義語である「抑制」にあたるタグは存在しない

現状、テキストを抑制するタグは存在しないが、分類上下記がそれにあたる。

  • <small> ⇒ 免責事項、注釈など主文に対する副次的な内容のテキストとして。 非強調・非重要を示すものではない。
  • <del> ⇒ かつて記述していたが、もう参照する必要がないことを明示する場合のテキストとして。同じく、非強調・非重要を示すものではない。
  • <ins><del> で取り消された内容をアップデートしていることを明示する場合のテキストとして。情報が更新されたという意味であり、重要であると強調する意味は持たない。
  • <s> ⇒ すでに古い情報となったり、正確性が失われたことを明示する場合のテキストとして。最新の情報が判明している場合は <del> を用いる。

<small> と書いたら <p> より抑制している感じがするけど、特にそういう効果があるわけではないみたいだ。

文書中での感情・状態の区別は明確に

書き手の感情や、示す対象の状態を表すタグは複数ある。

  • <i> ⇒ 心中の声や、第二者のセリフ、慣用句・ことわざ、固有名詞などとして。アイコンを表示するために使うケースも多く見られる。
  • <q> ⇒ 引用文として。
  • <u> ⇒ 明瞭に発音できないテキスト(タイポやシンボルとしての文字など)として。
  • <time> ⇒ 時刻・日時を示すテキストとして。
  • <abbr> ⇒ 略語として。 title 属性でその略の元となっているテキストを明示する。
  • <cite> ⇒ 本や新聞・テレビ・歌・映画などの創作物から参照していることを、その題名や作者名・参照元URLなどで示すテキストとして。
  • <kbd> ⇒ ユーザに操作してほしいキーボードのキーを明示する場合のテキストとして。
  • <address> ⇒ 著作者や責任者などの個人・組織の連絡先情報を示すテキストとして。 「住所」ではない

<form>「ぼくは表じゃないよ」

慣習的に問い合わせフォームやログインフォームなどは表組み <table> で記述することがあるが、見た目が表っぽいだけで厳密には表ではない

フォームのマークアップをより専門的に行えるようなタグは、 <table> 以外にもすでに用意されているので、<table> は、本当の意味での「表組み」を示す場合にのみ用いられたい。(HTMLは、見た目ではなく意味を重要視する。)

Before

旧来の慣習的なマークアップ
<table>
  <tbody>
    <tr>
      <th></th>
      <td><input type="text" name="#" /></td>
    </tr>
    <tr>
      <th></th>
      <td><input type="text" name="#" /></td>
    </tr>
    <tr>
      <th>メールアドレス</th>
      <td><input type="email" name="#" /></td>
    </tr>
    <tr>
      <th>電話番号</th>
      <td><input type="tel" name="#" /></td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th></th>
      <td><button type="submit">送信</button></td>
    </tr>
  </tfoot>
</table>

After

HTML5でのマークアップの例
<section>
  <fieldset>
    <legend>氏名</legend>
    <span>
      <label></label>
      <input type="text" name="#" />
    </span>
    <span>
      <label></label>
      <input type="text" name="#" />
    </span>
  </fieldset>

  <fieldset>
    <legend>連絡先</legend>
    <span>
      <label>メールアドレス</label>
      <input type="email" name="#" />
    </span>
    <span>
      <label>電話番号</label>
      <input type="tel" name="#" />
    </span>
  </fieldset>

  <button type="submit">送信</button>
</section>

とはいえ、 実際は、項目名を <label> タグで記述したり、そもそも全部 <div> で書いてしまうケースのほうが多く、 なんとなく上記の書き方は浸透しない気がする。CSSを当てるのも結構めんどくさい。

追記と変更:20170610
@katatemadesuga 氏のコメント欄での指摘を受けて <fieldset> タグの用法についてあらためてW3Cのドキュメントを読んでみると、確かに意図がずれていたので修正。 <fieldset> タグはラベルと入力欄の関係性を示すものでなく、フォーム内の関連するDOMを包括するものであるようだ。
便宜上上記の After 例では <label> と併用したが、モダンな入力フォームであれば placeholder 属性で済ませてしまってよいだろう。なお、 <input type="checkbox | radio" /> の補助テキストとしての <label> は当然生き残るであろうと思われる。

フォームの各項目は名前が標準化されている

苗字と名前をそれぞれ入力させる <input> タグを用意する場合、 name 属性をどう決めるか? familyName / firstName とキャメルケースを使う? まさか myoji / namae なんてことは無いよね!

正解は family-namefirst-name

これは、 Mozillaのデベロッパガイド に、あらゆるフォーム項目の命名指針やその他属性の指定方法が記載されており、 name / autocomplete / inputmode など各種のフォーム要素の属性をグローバルスタンダードに揃えることで、命名規則や開発効率を向上させるだけではなく、キャッシュを活用したautofillなどの点でユーザにとってもメリットがある。 2

フレームワークを使ってDOMレンダリングするなら、 <template><details>

ユーザーの操作によってDOM操作し、要素を表示したり非表示にしたりテキストを書き換えたりといった場合、適当な <div> タグをtoggleしたりするのが一般的だが、実はHTMLにはそれ専用のタグがある。3

<template> は、中に何を入れてもよい。デフォルトで非表示になるので、DOM操作で子要素を完全に作り終わってからビューとして表れることを想定している。ハードコーディングできるものだけ先にHTMLとして用意してしまう場合などに使える。

templateタグを用いた例
<template id="jsi-hoge">
  <dl>
    <dt>まだddタグがないよ</dt>
  </dl>
</template>

<details> は、ユーザーがクリックしたら詳細を見せる、みたいな挙動を実装するためのタグだ。 <details> タグで概要と詳細を分類して記述すれば、ブラウザ側でそれを解釈してくれる。4

detailsタグを用いた例
<details id="jsi-hoge">
 <summary>つれづれなるまゝに <span>...詳細を見る</span></summary>
 <p>つれづれなるまゝに、日暮らし、硯にむかひて、心にうつりゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。</p>
</details>

ネイティブで用意されているインクリメンタルサーチ

インクリメンタルサーチ的なものが、実はHTMLネイティブで用意されている。

datalistタグを用いたインクリメンタルサーチ的なやつの実装例
<input type="text" list="example" />

<datalist id="example">
  <option>候補1</option>
  <option>候補2</option>
  <option>候補3</option>
</datalist>

モーダルウィンドウ専用タグ <dialog>

Google Material Design Lite のダイアログセクションでは、実際にこのタグによるマークアップが実装されている。(でも Chrome以外ほとんどサポートしてない ... )

以下は、Material Design Liteによる実装例である。

dialogタグによるモーダルウィンドウの実装例、MaterialDesignLiteより
<dialog class="mdl-dialog">
  <h4 class="mdl-dialog__title">Allow data collection?</h4>
  <div class="mdl-dialog__content">
    <p>Allowing us to collect data will let us get you the information you want faster.</p>
  </div>
  <div class="mdl-dialog__actions">
    <button type="button" class="mdl-button">Agree</button>
    <button type="button" class="mdl-button close">Disagree</button>
  </div>
</dialog>

アプリケーションにおける操作メニュー <menu> / <menulist>

以下は、よく引き合いに出される「テキストの左右中央寄せ」ポップアップメニューを実装する例だ。

menu/menuitemを用いたアプリケーション操作メニューの実装例
<button type="menu" menu="example">メニュー</button>

<menu type="popup" id="example">
  <menuitem type="radio" label="左寄せ" icon="left.png" onclick="setAlign('left')">
  <menuitem type="radio" label="中央寄せ" icon="center.png" onclick="setAlign('center')">
  <menuitem type="radio" label="右寄せ" icon="right.png" onclick="setAlign('right')">

  <hr />

  <menuitem type="command" label="適用" icon="decide.png" onclick="decide()">
</menu>

画像は美しく表示しよう、レスポンシブイメージで

Retinaディスプレイの登場によって、ウェブデザイナーは960pxのモックアップを1920pxで作らなければならなくなってしまった。ブラウザ幅とネットワーク環境は比例するという考えのもと、レスポンシブイメージをHTMLに組み込むと、よりきれいな画像を表示させられる。

以下は一例だ。

picture/sourceタグによるレスポンシブイメージの例
<picture>
  <source srcset="image@x2.png" media="(min-width: 641px)">
  <source srcset="image@x3.png" media="(min-width: 769px)">
  <source srcset="image@x4.png" media="(min-width: 961px)">
  <img src="image.png" alt="" />
</picture>

Landscape / Portraitの切り替えだって対応している。

picture/sourceタグによるレスポンシブイメージの例、media属性でorientationも判定
<picture>
  <source srcset="smaller_landscape.jpg" media="(max-width: 769px) and (orientation: landscape)">
  <source srcset="smaller_portrait.jpg" media="(max-width: 769px) and (orientation: portrait)">
  <source srcset="default_landscape.jpg" media="(min-width: 768px) and (orientation: landscape)">
  <source srcset="default_portrait.jpg" media="(min-width: 768px) and (orientation: portrait)">
  <img srcset="default_landscape.jpg" alt="">
</picture>

なお、実際にはmedia属性の値はHTMLトランスパイラの定数として持つのがよいだろう。

Flexbox / Grid Layout

レガシーIEのサポートなんかしなくていいという賢明な判断をしているみなさんにはもうおなじみだろうが、floatやinline-blockでの横並びは時代遅れのものとなり、Flexbox / Grid Layoutが次世代のウェブレイアウトフローとして広まった。

こちらについては以下のような素晴らしい記事がQiita上にもあるのでご参照いただきたい。

まとめ

ほかにもたくさん面白いタグやプロパティはあるが、この記事で言いたいのは最新のやつを知って使おうぜということだけではなく、上記で述べた以下の点だ。

  • 「命名規則や保守性のため」「開発者自身が自分が何を書いているのか理解・明確にするため」に常に最適なコーディングを心がけよう
  • 文章はエディトリアルライターが意図を持って作っている。デザインは、デザイナーが意図を持って作っている。コードには、見た目だけではなく「意図」も起こしてあげよう

ゼロから始めるWeb Accessibility入門:概要 みたいな記事も併せて理解すると最強ではなかろうか。


  1. 正直、大多数のユーザ(視覚障害者、音声読み上げソフトやリーダービュー機能を用いるユーザを除く)にはコーディングがどうだろうがほぼ関係ないし、SEOに効くとかいうやつもいるが、適当な単語で検索して一番上に表示されたサイトのソースコードを美しかった記憶がない(コンテンツ力のほうが大事)。 

  2. ただし、これを悪用したフィッシング的な手法がたびたび話題にあがることがあるので、その点は覚えておきたい。詳細はググると出てくると思う。 

  3. とはいえ、クロスブラウザ対応は、2017年4月時点では完全ではない。 

  4. 開閉のアニメーションやスクリプトをCSSやJavaScriptで実装しなければならないことには変わらないが。