ゼロからウェブサイトを作るための勘所

ウェブサイトを作るアルバイトを1年ちょいやったので、そこで必要だった知識をメモ。

はじめに

この記事は、筆者がウェブサイト制作のアルバイトを1年ほど行った際にウェブサイトを制作するのに必要だった知識をまとめたものです。主にレスポンシブ対応のウェブサイトを作っていましたので、本記事もレスポンシブに対応する前提での説明になります。
今回は、htmlとcssをどのように書けば目的のレイアウトを作れるかということに重点を置いて解説します。ちなみに制作環境はMac + Google Chrome + Dreamweaver + Photoshop + Illustratorですが、今回はソフトウェアの使い方については解説しません。

対象読者

HTMLとCSSは触るが、レイアウトまでは作らないプログラマ寄りの人

ワイヤーフレームを作成する

まず初めに、ウェブサイトの構成を決めます。どのようなコンテンツが必要か、コンテンツをどのように配置するか、ウェブサイトのページ数、バックエンド(サーバー、プログラム、データベース)はどんなものが必要か、などを洗い出します。
実際に図に起こしておくと分かり易いかもしれません。大まかな構成さえ把握できるなら簡単なメモでも構いません。

デザインデータを作成する

ワイヤーフレームをもとに、Adobe Illustratorを使用してウェブサイトのデザインを作成します。デザインを作る段階で気を付けることは「コンテンツ幅の設計」と「オブジェクトの比率計算」と「キリの良い数値でオブジェクトを作成すること」です。

以下より、それぞれのポイントについて説明していきます。

コンテンツ幅の設計

まずはコンテンツを表示する幅を決めます。コンテンツ幅はブラウザの幅を変化させたときに、それ以上縮小(拡大)しない閾値であり、コンテンツが崩れて表示されないようにするためのものです。この閾値は全ページ共通になるので設計を始める段階で決めておくことが望ましいです。
2017年時点では、PCサイトの最小コンテンツ幅が1000px前後。スマートフォンサイトの最大コンテンツ幅が768pxというのが一般的になっています。これはiPadを縦持ちしたときの表示解像度が768pxということに起因しています。つまり、PC版のコンテンツ幅を1000px前後で作成し、スマートフォン用の表示に切り替わる閾値を768pxに設定することが基本になります。このように設定することで、PCで見たときはブラウザの横幅が769px以上になるのでPC用の表示が適用され、スマートフォンで見たときはブラウザの横幅が768px以下になるのでスマートフォン用の表示が適用されます。

ここで決めた閾値は、後でCSSのメディアクエリに設定します。メディアクエリとは、参照するCSSを画面サイズによって分岐する処理です。
また、HTMLにはビューポートを設定する必要があります。ビューポートとは表示領域のことで、この設定を書くことでデバイスごとの表示領域を制御することができます。

実際の記述例は以下になります。

HTML

<html>
<head>
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
</head>
<body>
  <div>
    コンテンツ
  </div>
</body>
</html>

<meta name="viewport" content="width=device-width,initial-scale=1.0">の部分がビューポートです。width=device-widthは、横幅がデバイスの横幅となるように指定しています。ピクセル値で指定しても良いのですが、スマートフォンなどのデバイスはそれぞれモニタサイズが異なるので、 そのデバイスの横幅になるように指定しておけば、全てのデバイスで原寸大でウェブページが表示されるようになります。initial-scale=1.0は、初期の表示倍率を指定しています。値に1.0を指定したので1倍、つまり、そのままの倍率で表示されることになります。

CSS

@media screen and (min-width:769px) {
  /* PC用表示 769px以上の画面幅に適用する */
  .content {
    color: #blue;
  }
}

@media screen and (max-width: 768px) { 
  /* スマートフォン用表示 768px以下の画面幅に適用する */
  .content {
    color: #red;
  }
}

@media screen and (条件) {}がメディアクエリです。「条件」にmin-width:769pxmax-width: 768pxのように書くことで、ユーザが使用する端末の画面幅によって、適用するCSSを分岐させることができます。

オブジェクトの比率計算

唐突ですが、ここでPC用サイトをスマートフォンで閲覧することをイメージしてみてください。多くのPC用サイトは画面幅を固定して作成されています。スマートフォンやタブレット端末のブラウザーは通常、ページ幅が固定されている場合、固定されたページ幅にフィットするように画面を縮小して表示するように動作します。このような理由からPC用サイトをスマートフォンで閲覧すると、かなり縮小された表示になってしまい、とても使いづらいものです。

これと同じ原理でiPhone Xなどの大型のスマートフォンに合わせて作られたウェブサイトをiPhone SEなどの比較的小型のスマートフォンで閲覧した場合、縮小された表示になってしまいます。

上記のようなことを避けるために、常に変化する画面サイズに対応する方法の一つとして「可変レイアウト」という手法があります。

可変レイアウトとはブラウザのサイズが変更されると、そのサイズに応じてサイトのページ幅も一緒に変化するようにレイアウトを作成する方法です。主にページ幅を「px」のような絶対指定ではなく「%」で相対指定することで、この可変レイアウトを再現することができます。

パソコンのように比較的ブラウザーの幅を広く取れる環境では固定幅を、スマートフォンやタブレット端末のように幅が広く取れず、一定ではない環境では可変レイアウトを利用します。

可変レイアウトを行う場合、コンテンツ幅はもちろんですが、コンテンツに含まれるオブジェクトの幅もパーセント(%)で記述しなければなりません。これはコーディングを始める前のデザインの段階でオブジェクトの比率を計算しておく必要があることを意味します。

例えば、2つのオブジェクトが並んでいる場合は「50%:50%」や「30%:70%」など、4つのオブジェクトが並んでいる場合は「25%:25%:25%:25%」のように比率を出しておきます。

キリの良い数値でオブジェクトを作成する

デザインをコードに落とし込む段階で、計算が面倒にならないように、ブロックレベル要素や画像などの幅と高さはキリの良い数値にします。キリの良い数値とは「248.6px」のようなものを「250px」にすることです。これは既に挙げたオブジェクトの比率計算が面倒にならないようにする意味もあります。

reset.cssを用意する

コーディングを始める前にreset.cssを用意します。ユーザが使用するブラウザに左右されずに、こちらが意図した表示を提供するためにはCSSのリセットが必要になります。以下のreset.cssはEric Meyer氏により考案されたもので、現在も広く使用されています。

reset.css

/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, a,
abbr, acronym, address, big, cite, code, del,
dfn, em, img, ins, kbd, q, s, samp, small, strike,
strong, sub, sup, tt, var, b, u, i, center,
dl, dt, dd, ol, ul, li, fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, figure,
figcaption, footer, header, hgroup, menu, nav,
output, ruby, section, summary, time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after, q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}

reset.cssは文字通り全ての要素の見た目をリセットして平等にします。例えば、h1要素とh2要素の見た目が全く同じになります。reset.cssを導入した場合、全ての要素の見た目を自身で定義し直さなければなりません。

また、HTML5ではブロックレベル・インラインに加えて、コンテンツモデルという考え方が導入されました(これについては後で解説します)。そのため、HTML5で追加された要素について、一部のブラウザーではインライン要素として表示される(ボックス形状にならない)場合があります。それを回避するために、reset.cssではボックス形状として使用されるケースの多い要素をdisplayプロパティを使ってブロックレベル要素に変換しています。

reset.css以外の選択肢

reset.cssに近い存在として、normalize.cssがあります。normalize.cssはブラウザごとの一貫性の無さやバグを修正しますが、全ての要素の見た目をリセットするわけではなく、有益な見た目は保持します。

また、2018年にはreboot.cssが登場しました。reboot.cssはbootstrapで使用されているCSSで、normalize.cssに似ています。クロスブラウザに対応した一貫したリセットを提供し、要素にシンプルで自然なベーススタイルを与えてくれます。

HTML5におけるウェブサイトの基本構造

HTMLには主に、HTML 4.01、XHTML、HTML5という3つのバージョンが存在し、一番新しい書き方がHTML5です。HTML5ではヘッダー、ナビゲーション、コンテンツ、サイドメニュー、フッターなどに対応する要素が追加されました。これらの要素はHTML5におけるウェブサイトの基本的な構造を作るのに役立ちます。

要素名 内容
header ページ最上部に配置したり、articleの上部に配置して、見出しやロゴなどを含めてヘッダー領域であることを示す。
nav サイト内をナビゲーションするリンクなどを挿入して利用する。
main そのページ内の主要なコンテンツを含めた領域で使用する。その特性上、1ページに1つしか使用しない。
article 文書内で一つの記事であることを示します。
section 文書内で一つのセクションであることを示します。
aside 補足説明や本文内容(article)と直接関連しない話題などを含め、主にサイドメニューなどで使用する。
footer ページ最下部に配置したり、articleの下部に配置して、ナビゲーションやコピーライト、更新日などを含めてフッター領域であることを示す。

配置イメージは次のようになります。
img-11-2-013

このように書くと各要素は1回しか使用できないように思われますが、実際は何回でも使用することができます。例えば、ブログサイトを例に挙げると以下のようになります。

<header>
  <h1>ブログタイトル</h1>
</header>

<article>
  <a href="#">
    <header>
      <h2>記事タイトル1</h2>
    </header>
    <section>
        <p>本文の要約1</p>
    </section>
  </a>
  <footer>執筆者名:執筆者名1</footer>
</article>

<article>
  <a href="#">
    <header>
      <h2>記事タイトル2</h2>
    </header>
    <section>
        <p>本文の要約2</p>
    </section>
  </a>
  <footer>執筆者名:執筆者名2</footer>
</article>

<footer>
  <small>Copyright (C) 〇〇〇〇 All Rights Reserved.</small>
</footer>

最初のheaderにブログタイトル、最後のfooterに著作権表示を記述しています。各記事へのリンクは独立したコンテンツなのでarticleで囲み、sectionでコンテンツの細分化を行っています。そして各記事のタイトルをheader、執筆者名をfooterで囲んでいます。今回のように独立したコンテンツがいくつもある場合はその内容に応じてheaderやfooterを必要なだけ使うことができます。今回の説明にはありませんが、navやasideも使い方が間違っていなければ、何回使っても大丈夫です。

HTML5の要素の中でも特に難しいのがarticleとsectionです。HTML5が登場するまでは、h1〜h6の見出し要素で暗黙的に階層をもたせていました。たとえば下記のような階層を表現する場合を例に解説します。

第1章:見出し1
    |
    |--第1節:見出し2-1
    |      |--第1項:見出し3-1
    |      |       |--本文1-1
    |      |
    |      |--第2項:見出し3-2
    |              |--本文1-2
    |
    |--第2節:見出し2-2
           |--第1項:見出し3-3
                   |--本文1-2

従来のHTMLでは、見出しタグを用いて以下のように記述していました。

<h1>第1章:見出し1</h1>
  <h2>第1節:見出し2-1</h2>
    <h3>第1項:見出し3-1</h3>
      <p>本文1-1</p>
    <h3>第2項:見出し3-2</h3>
      <p>本文1-2</p>
  <h2>第2節:見出し2-2</h2>
    <h3>第1項:見出し3-3</h3>
      <p>本文2-1</p>

このままでも問題はありませんが、より明確に文書構造を表現する場合、articleとsectionを使って以下のように記述します。

<article>
  <h1>第1章:見出し1</h1>
  <section>
    <h2>第1節:見出し2-1</h2>
      <h3>第1項:見出し3-1</h3>
        <p>本文1-1</p>
      <h3>第2項:見出し3-2</h3>
        <p>本文1-2</p>
  </section>
  <section>
    <h2>第2節:見出し2-2</h2>
      <h3>第1項:見出し3-3</h3>
        <p>本文2-1</p>
  </section>
</article>

それだけで1つの独立したページとして成り立つ内容であればarticleを使用し、それ以外でコンテンツを細分化したい場合はsectionを使用します。

このように書くと、articleの中にsectionを含めるという使い方しかできないように思われますが、sectionの中にarticleを含めるケースもあります。

ブログサイトを例にすると、以下のような場合です。

<article>
  <h1>「ブログの記事タイトル」</h1>
  <section>
    <h2>■関連記事</h2>
    <article>
      <h1>・関連記事名1</h1>
      <p>本文要約1</p>
    </article>
    <article>
      <h3>・関連記事名2</h3>
      <p>本文要約2</p>
    </article>
  </section>
  <section>
    <h2>■人気記事</h2>
    <article>
      <h3>・人気記事名1</h3>
      <p>本文要約1</p>
    </article>
    <article>
      <h3>・人気記事名2</h3>
      <p>本文要約2</p>
    </article>
  </section>
</article>

ブログ記事全体は一つの独立したコンテンツなのでarticleで囲んでいます。また、関連記事の一覧と人気記事の一覧をそれぞれ区切って細分化するためにsectionで囲んでいます。さらに関連記事と人気記事の中の各記事もそれぞれ独立したコンテンツとして成り立つのでarticleで囲むことができます。

基本形となるhtmlファイルを用意する

今回は前項で登場したHTML5の新要素を使い、HTML5におけるウェブサイトの基本形を作成しました。ここにidやclassなどのセレクタを追記しながらCSSにデザインを記述していくのが基本になります。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>タイトル</title>
<meta name="format-detection" content="telephone=no">
<link href="css/reset.css" rel="stylesheet" type="text/css">
<link href="css/style.css" rel="stylesheet" type="text/css">
</head>

<body>
<!-- ヘッダーここから -->
<div>
  <header>
    <p>キャッチコピー</p>
    <h1><a href="index.html"><img src="images/logo.png" width="314" height="50" alt="ロゴ"/></a></h1>
    <address>
    <p>電話番号:<span>0000-00-0000</span></p>
    </address>
  </header>
</div>
<!-- /ヘッダーここまで --> 

<!-- グローバルナビゲーションここから -->
<div>
  <nav>
    <ul>
      <li><a href="#">メニューA</a></li>
      <li><a href="#">メニューB</a></li>
      <li><a href="#">メニューC</a></li>
      <li><a href="#">メニューD</a></li>
      <li><a href="#">メニューE</a></li>
    </ul>
  </nav>
</div>
<!-- /グローバルナビゲーションここまで --> 

<!-- メインビジュアルここから -->
<div>
  <p><img src="images/mainvisual.jpg" width="" height="" alt=""/></p>
</div>
<!-- メインビジュアルここまで -->

<!-- mainここから -->
<div>
  <main> 
    <!-- メインコンテンツここから -->
    <article> 
      
      <!-- ここから下に記述します -->
      <h1>トップページ</h1>
      </div>
      <h2>新着情報</h2>
      <dl>
        <dt>0000/00/00:〇〇〇〇〇〇</dt>
        <dd>〇〇〇〇〇〇〇〇〇〇〇〇〇〇</dd>
        <dt>0000/00/00:〇〇〇〇〇〇</dt>
        <dd>〇〇〇〇〇〇〇〇〇〇〇〇〇〇</dd>
        <dt>0000/00/00:〇〇〇〇〇〇</dt>
        <dd>〇〇〇〇〇〇〇〇〇〇〇〇〇〇</dd>
        <dt>0000/00/00:〇〇〇〇〇〇</dt>
        <dd>〇〇〇〇〇〇〇〇〇〇〇〇〇〇</dd>
      </dl>
      <!-- ここから上に記述します --> 
      
    </article>
    <!-- /メインコンテンツここまで --> 
    
    <!-- サイドメニューここから -->
    <aside>
      <nav>
        <h2>サイドメニュー</h2>
        <ul>
          <li><a href="#">メニューF</a></li>
          <li><a href="#">メニューG</a></li>
          <li><a href="#">メニューH</a></li>
          <li><a href="#">メニューI</a></li>
        </ul>
      </nav>
      <section>
        <h2>お問い合わせ</h2>
        <address>
        <p>電話番号:<span>0000-00-0000</span></p>
        <p>メールアドレス:<span>〇〇〇〇@〇〇〇〇.com</span></p>
        </address>
      </section>
    </aside>
    <!-- /サイドメニューここまで --> 
  </main>
</div>
<!-- /mainここまで -->

<!-- フッターここから -->
<div>
  <footer>
    <p><small>Copyright (C) 〇〇〇〇 All Rights Reserved.</small></p>
  </footer>
</div>
<!-- /フッターここまで -->
</body>
</html>

今回はトップページを作成する想定なのでウェブサイトのロゴをh1要素でマークアップしていますが、ウェブサイトの考え方やページによってはロゴをh1要素でマークアップすることが適さない場合もあるので注意してください。

デザインデータをコードに落とし込む

ここまでの準備が終わったら、いよいよコーディングに入ります。デザインデータから画像やオブジェクトの横幅・縦幅を抽出し、htmlとcssに落とし込んでいく作業です。

ここからはデザインをコードに落とし込むためのテクニックを解説します。

  1. 必要な要素を考える
    • 廃止された要素や非推奨の要素に注意する
    • 必要な要素数を考える
    • ブロックレベル要素とインライン要素の違いを意識する
    • コンテンツモデルを意識する
  2. オブジェクトの配置方法を考える
    • ブロックレベル要素の水平方向中央寄せを覚える
    • 文字列(インライン要素)の水平方向中央寄せを覚える
    • 相対位置、絶対位置、固定位置への配置を覚える
    • ボックスモデルを覚える
    • マージンの相殺を覚える
    • ネガティブマージンによる配置方法を覚える
    • 要素の重なり順の変更方法を覚える
    • スタックコンテキストを覚える
    • 回り込みでの配置を覚える
    • 流れ込みでの配置を覚える

必要な要素を考える

この項では、どのような要素が何個あれば目的のレイアウトが実現できるかを考えます。

廃止された要素や非推奨の要素に注意する

HTMLには文書のマークアップのみを記述し、CSSにはデザインのみを記述するという一般的なルールがあります。

HTMLの歴史を見ていくと、かつてCSSが無かった時代にはfont要素やcenter要素など、HTMLだけでデザインを行うための要素が多く存在していました。しかし、CSSが登場してからしばらく経ち、これらの要素はHTML5で廃止されました。

ここで注意したいのは、ブラウザは現存している多くのウェブサイトを考慮して作られているため、HTML5で廃止されている要素も使おうと思えば使うことができてしまうということです。

必要な要素数を考える

ここでは以下のような「画面中央に背景が黒のブロックを配置し、中央に赤いラインが入っていて、その中央に文字が入っている」というデザインをコードに落とし込む場合を考えてみます。

center-three-div

このデザインを実現するためには最低でも2つのブロックレベル要素が必要です。(ブロックレベル要素については後で解説します。)

以下のように黒いブロックを作るのに1個、赤いブロックを作るのに1個使用します。

<div class="a">
    <p class="b">ここが中央</p>
</div>

説明を複雑にしたくないのでCSSの記述は省きますが、ここで重要なのはデザインを実現するために何個のブロックレベル要素が必要かを意識することです。

ブロックレベル要素とインライン要素の違いを意識する

要素は大きく分けて「ブロックレベル要素」と「インライン要素」の2つがあります。この2つの要素の違いを理解していないと正しいマークアップができないことに加えて、CSSのプロパティが動かないといったことが発生してしまいます。

  • ブロックレベル要素の特徴

    • 見出し・段落・表など、文書を構成する基本となる要素で、一つのブロックとして認識される。
    • 要素の前後には自動的に改行が入る。
    • 要素の中にはブロックレベル要素とインライン要素の両方を入れることができる。
    • width、height、margin、paddingなどのプロパティを持つことができる。
  • インライン要素の特徴

    • 主にブロックレベル要素の内容として用いられる要素で、文章の一部として扱われる。
    • インライン要素の中にはインライン要素のみを入れることができる(ブロックレベル要素は入らない)。
    • widthとheightのプロパティを持つことができず、垂直方向のmargin、paddingを設定することができない。

代表的なブロックレベル要素とインライン要素には以下のものがあります。

要素 要素の種類 意味
div ブロックレベル なし
p ブロックレベル 段落
h1〜h6 ブロックレベル 見出し(数値が小さいほど大見出しとなる)
ul ブロックレベル リストの種類
ol ブロックレベル リストの種類
li ブロックレベル リストアイテム
table ブロックレベル
span インライン なし
strong インライン 重要
em インライン アクセント(文脈の変化)
a インライン リンク

divとspanには要素の意味が割り当てられていません。divはブロックレベル要素、spanはインライン要素であり、この2つの要素はマークアップを気にせずに使用することができます。そのため、レイアウトを作る目的でこの2つの要素が頻繁に用いられます。

前項でマークアップとデザインはHTMLとCSSに分離するという話をしましたが、デザインのために意味を持たない要素を記述することはデザインをHTMLに含めることにならないのか、という疑問があります。しかし、他のどの要素も適切でない場合は実用の面から考えて、divやspanを使用せざるを得ないことがあります。

displayプロパティの使い方

CSSのdisplayプロパティを使用することで、ブロックレベル要素とインライン要素を切り替えることができます。

displayプロパティに指定できる値は以下になります。

説明
inline インライン要素に表示を変換する。
block ブロックレベル要素に表示を変換する。
inline-block 要素そのものはインラインだが、高さや幅が指定できるブロックの特徴も併せ持つ。
table テーブル(table)と同様の表示に変換する。display: table-cellの親要素。
table-cell テーブルのセル(td)と同様の表示に変換する。display: tableの子要素。
none 要素が非表示になる。

displayプロパティが主に使用されるのは、インライン要素をdisplay: blockもしくはdisplay: inline-blockにしたいときです。

以下の例ではインライン要素のspan要素に対してdisplay: blockを指定することで、span要素がブロックレベル要素になり、widthやheightなどのプロパティを持つことができるようになります。

HTML記述例

<p class="sample">2020年東京オリンピックまで<span>1000日</span></p>

CSS記述例

.sample span {
  display:block;
  height:50px;
  width:250px;
  margin-top:10px;
  font-size:36px;
  text-align:center;
  border:solid 1px #000;
  line-height:1.4
}

動作例

2020年東京オリンピックまで1000日

コンテンツモデルを意識する

HTML5から「ブロックレベル要素」と「インライン要素」に加えて、新たに「コンテンツモデル」という考え方が加わりました。この考え方は「ブロックレベル要素の中にインライン要素を配置する」という入れ子のルールを踏襲しつつ、HTML5から新たに追加や変更などが行われた要素を補完する目的があります。

分類名 意味
メタデータ・コンテンツ 主にhead内に記述する、HTML自体の情報を表現する要素。meta、title、style等。
フロー・コンテンツ 子孫にテキストなどを記述する要素。ほとんどのタグがここに含まれます。p、div等を始めとしたほぼ全てのタグと文字列。
セクショニング・コンテンツ 見出しや概要を記述する要素。article、aside、nav、section等。
ヘディング・コンテンツ セクションの見出しを記述する要素。h1~h6等。
フレージング・コンテンツ 段落などの中に含まれる文節や語句を記述する要素。strong、em、span等。
エンベッデッド・コンテンツ ドキュメント内に外部のリソースを組み込む要素。video、audio、img等。
インタラクティブ・コンテンツ ユーザーが何か操作できるコンテンツを記述する要素。button、input、label等。

contentsmodel

W3Cの創始者であるティム・バーナーズ・リーは、Webサイトの技術発展を目的に「セマンティック・ウェブ」というプロジェクトを提唱しています。「セマンティック」とは直訳すると「意味」や「意味論」を指す言葉です。Webサイトでのデータ交換において、より詳細な意味を伝えることを目的とした取り組みが「セマンティック・ウェブ」です。

これまでは、要素の分類がブロックレベル・インラインと2種類だったのが、HTML5で細分化されたのは、「セマンティック・ウェブ」という考え方に基づいたためです。

既に前述している内容ではありますが、コンテンツモデルにおいて、特に意識したいのはフロー・コンテンツにはほぼ全ての要素と文字列が含まれる点です。article、aside、nav、sectionなどはフロー・コンテンツであり、セクショニング・コンテンツでもあります。なので、articleやsectionなどをどんな順番にネストしたとしても内容が合っていれば、使い方に問題はありません。

オブジェクトの配置方法を考える

ここからはオブジェクトを配置するテクニックを説明します。ここで紹介するテクニックを覚えることで自由自在なオブジェクトの配置ができるようになります。

ブロックレベル要素の水平方向中央寄せを覚える

ブロックレベル要素を水平方向に対して中央寄せを行いたい場合、要素自身にmargin:0 autoを指定することで、水平方向のマージンを自動調整し、中央寄せにすることができます。また、必要条件として中央寄せにしたいブロックレベル要素が幅と高さを持っていなければなりません。

HTML

<div class="sample">中央寄せ</div>

CSS

.sample {
  margin: 0 auto;
  width: 200px;
  height: 200px;
  background-color: #f00;
}

文字列(インライン要素)の水平方向中央寄せを覚える

文字列やインライン要素を水平方向に対して中央寄せを行いたい場合、親のブロックレベル要素にtext-align: centerを指定することで、中央寄せにすることができます。

HTML

<div class="sample">中央寄せ</div>

CSS

.sample {
  width: 200px;
  height: 200px;
  text-align: center;
  background-color: #f00;
}

相対位置、絶対位置、固定位置への配置を覚える

positionプロパティを使用することで、要素を相対位置、絶対位置、固定位置に配置することができます。また、絶対位置、もしくは固定位置を指定したときはtop、right、bottom、leftプロパティで位置を指定することができます。

デフォルト値

positionプロパティのデフォルト値はstaticです。これはテーブル列とテーブル列グループを除くすべての要素に対して適用されています。

相対位置

position: relativeを指定することで要素を相対位置に配置することができます。このプロパティの用途として挙げられるのは、後で説明するz-indexとの組み合わせや、下記のposition: absoluteとの組み合わせです。

絶対位置

position: absoluteを指定することで要素を絶対位置に配置することができます。絶対位置を指定する際には、親要素にposition: relativeを指定すると、その親要素を基準にして位置が決定されるようになります。また、親要素にposition: relativeを指定しなかった場合は、body要素(ブラウザーの表示領域)が基準になります。

一般的なウェブサイトでposition: absoluteが頻繁に使用される箇所としては、トップページのロゴが挙げられます。他の要素との位置的な繋がりが無く独立していたり、ブラウザの幅や高さの変更の影響を受けない箇所に使用します。

以下の例では、div.sample_aを基準にして、div.sample_bを上から50px、左から50pxの絶対位置に配置しています。

HTML

<div class="sample_a">
    <div class="sample_b">絶対位置です。</div>
</div>

CSS

.sample_a {
  position: relative;
  width: 300px;
  height: 300px;
  margin: 200px;
  background-color: #000;
}

.sample_b {
  position: absolute;
  top: 50px;
  left: 50px;
  color: #fff;
}

固定位置

position: fixedを指定することで要素の位置を固定することができます。ブラウザのサイズを変えたり、スクロール操作を行っても位置が変わることがありません。

HTML

<div class="sample_a">固定します。</div>
<div class="sample_b"></div>

CSS

.sample_a {
  position: fixed;
  top: 10px;
  left: 10px;
}

.sample_b {
  /* スクロールして確認できるように縦長のdivを配置 */
  height: 3000px;
}

ボックスモデルを覚える

ボックスモデルとは、主にブロックレベル要素で使用する、width、height、margin、padding、borderなどの構造のことです。

box_model

ボックスモデルは内側から、コンテンツ、padding、border、marginの順番になっています。

  • 要素と要素の間に余白を作りたい場合はmarginを使用します。
  • 要素を囲む枠線を作りたい場合はborderを使用します。
  • borderの内側に余白を作りたい場合はpaddingを使用します。

上記の3点を覚えておきましょう。

要素と要素の間に余白を作りたい場合、marginを使用することになりますが、marginの仕様には落とし穴があります。水平方向のマージン(margin-left、margin-right)は問題ありませんが、垂直方向のマージン(margin-top、margin-bottom)を作るときにはマージンの相殺に注意しなければなりません。

マージンの相殺を覚える

マージンの相殺は、2つの要素が垂直方向に隣り合っている場合、先に宣言されている要素に後から宣言した要素のマージンが相殺されてしまうというブラウザの仕様です。

マージンの相殺が発生するのは以下の場合です。

  • 連続している2つの要素の間に垂直方向のマージンを作るとき
  • 親子関係(入れ子)の要素に垂直方向のマージンを作るとき

連続している2つの要素の間に垂直方向のマージンを作るとき

普通の感覚であれば、以下のようなコードを書いた場合、sample_aとsample_bの間に50pxのマージンが作られることを想像するはずです。

HTML

<div class="sample_a">サンプルA</div>
<div class="sample_b">サンプルB</div>

CSS

.sample_a {
  margin:20px 0;
}
.sample_b {
  margin:30px 0;
}

しかし、実際は30pxしかマージンが作られません。これはマージンの相殺によって、少ない方の数値が打ち消されているためです。この問題への対策としては「Single-direction margin declarations」に書かれている「マージンの指定は単一方向にする」に従うことが挙げられます。

親子関係(入れ子)の要素に垂直方向のマージンを作るとき

普通の感覚であれば、以下のようなコードを書いた場合、sample_bとsample_cの間のsample_cから見て上に30pxのマージンが作られることを想像するはずです。

HTML

<div class="sample_a">
    <div class="sample_b">
      <p class="sample_c">サンプル</p>
    </div>
</div>

CSS

.sample_a {
  background-color:#000;
  width:300px;
  height:300px;
}
.sample_b {
  background-color: #fff;
  width:200px;
  height:200px;
}
.sample_c {
  background-color:#f00;
  width:100px;
  height:100px;
  margin-top:30px;
  color:#fff;
}

しかし、実際はsample_aがsample_cのマージンを吸収してしまい、sample_aの上にマージンが作られてしまいます。
この厄介な問題は、オブジェクトのマージン同士が隣り合っているために発生しています。そのため、以下のようにborderやpaddingを使用し、子要素をマージンから隔離するための部屋を作ることでマージンの吸収を回避することができます。

CSS

.sample_a {
  background-color: #000;
  width: 300px;
  height: 300px;
  padding: 1px 0;
  box-sizing: border-box;
}
.sample_b {
  background-color: #f00;
  width: 200px;
  height: 200px;
  padding: 1px 0;
  box-sizing: border-box;
}
.sample_c {
  background-color: #0f0;
  width: 100px;
  height: 100px;
  margin-top: 30px;
}

上記の例では、マージンを隔離するための部屋をpadding: 1px 0で作成しています。また、部屋を作成するために用意したpaddingをheightに含めるためにbox-sizing: border-boxを指定しています。
box-sizing: border-boxについて詳しく説明すると、今回はオブジェクトの上と下に1px分の余白を取っているので、通常ではheightが302pxなどのキリの悪い数値になってしまいますが、このプロパティを使用することでpaddingをheightに含めることができるので、heightが300pxになります。

しかし、この方法ではpaddingやborderによって、垂直方向に2pxの空白が作られてしまうことは避けられません。そのため、場合によっては使用することが難しいことがあります。そこで、同様のレイアウトを実現するために、上記とは違うアプローチとしてネガティブマージンを使用する方法が挙げられます。

ネガティブマージンによる配置を覚える

marginプロパティにマイナス値を指定することで、要素の位置を調整することができます。
例えば、画像の上に文字を乗せたい場合は、以下のようにmargin-topにマイナス値を設定します。

HTML

<img src="https://www.google.co.jp/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" />
<p class="sample">上に重なる文字</p>

CSS

.sample {
  margin-top: -150px;
  color: #f00;
}

また、ネガティブマージンを使用することで、先の例で示した親子関係(入れ子)のように見えるレイアウトを作りたい場合、以下のコードで実現することができます。

HTML

<div class="sample_a"></div>
<div class="sample_b"></div>
<p class="sample_c">サンプル</p>

CSS

.sample_a {
  background-color: #000;
  width: 300px;
  height: 300px;
}
.sample_b {
  background-color: #fff;
  width: 200px;
  height: 200px;
  margin-top: -300px;
}
.sample_c {
  background-color: #f00;
  width: 100px;
  height: 100px;
  margin-top: -170px;
}

ネガティブマージンを利用して、下から黒いボックス、赤いボックス、緑のボックスの順に重ねて表示します。div.sample_bのマージンにはdiv.sample_a分の高さを引くように指定し、p.sample_cにはdiv.sample_b分の高さを引いた上でマージン分の30pxを足すのでmargin-top: -170pxを指定しています。

そして、ネガティブマージンを使っていると、どうしてもオブジェクトの重なり順を変更したいケースが出てきます。そういったときはz-indexプロパティを使用します。

要素の重なり順の変更を覚える

z-indexプロパティでは、要素の重なり順を変更することができます。通常は後から記述された要素ほど上に重なって表示されますが、z-indexはこの重なり順に変更を加えます。z-indexプロパティには数値を設定することができ、数値が一番低いオブジェクトが一番下に表示され、数値が一番高いオブジェクトが一番上に表示されます。

また、z-indexプロパティを使用するには、positionプロパティの値がrelative、absolute、fixedのいずれかである必要があります。

以下の例では、先に宣言した文字を後から宣言した画像の上に重ねて表示します。

HTML

<p class="sample_a">上に重なる文字</p>
<img class="sample_b" src="https://www.google.co.jp/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" />

CSS

.sample_a {
  position: relative;
  z-index: 1;
}
.sample_b {
  margin-top: -40px;
  position: relative;
  z-index: 0;
}

要素の重なり順を変更していると、意図した通りの重なり順にならないことがあります。これはスタックコンテキストと呼ばれる要素の重なり順を決める概念が影響しています。

スタックコンテキストを覚える

スタックコンテキストとは、要素の重なり順を決める概念です。この概念を正しく理解しないと要素の重なり順を正確に制御することができません。

初めに、最上位(ルート)のスタックコンテキストはhtml要素によって生成されます。要素が書かれた順番に重なり順が決定するのは、html要素がスタックコンテキストの最上位(ルート)という役割を持っているからです。

次に最上位(ルート)の中に、特定の要素によって、下位のスタックコンテキストが生成されます。スタックコンテキストを生成する要素は、いくつかあるのですが、重要なものを一つ挙げると以下の場合です。

  • positionの値がabsoluteまたはrelativeであり、かつz-indexの値がauto以外の要素

つまり、前項で説明したz-indexpositionの組み合わせによって、下位のスタックコンテキストが生成されます。

上記を理解するために、例えば、以下のような構造を持った要素の重なり順を制御する場合を考えてみます。

understanding_zindex_04

スタックコンテキストの階層構造が、次のように構成されます。

ルート要素
    DIV #1
    DIV #2
    DIV #3
        DIV #4
        DIV #5
        DIV #6

この例ではルート要素のスタックコンテキストを含めて、全部で7つのスタックコンテキストを生成します。ルート要素の中にDIV #1、DIV #2、DIV #3が配置され、DIV #3の子要素としてDIV #4、DIV #5、DIV #6が配置されています。

重要なのは、DIV #4、DIV #5、DIV #6はDIV #3の子要素なので、DIV #3の内側で重なり方が決まることです。DIV #3内部の重ね合わせが最優先で行われ、重ね合わせが終わったらDIV #3はルート要素に丸ごと渡され、兄弟要素(DIV #1、DIV #2)との重ね合わせ処理が行われます。

DIV #4がDIV #1の下に描画されることに注目してください。これは、DIV #1のz-index: 5はルート要素のスタックコンテキストでだけ有効な値で、DIV #4のz-index: 6はDIV #3のスタックコンテキストでだけ有効な値だからです。DIV #4はDIV #3の内部にあり、DIV #3は DIV #1よりも小さなz-index値を持っているので、DIV #4はDIV #1の下になります。

回り込みでの配置を覚える

floatプロパティを使用することで、要素を浮き上がらせ、回り込ませることができます。また、floatを使用した後には「floatを解除する」という操作が必要になります。

float:leftを指定すると左に回り込み、float:rightを指定すると右に回り込みます。floatを使用したあとには、親要素に対してclear fixと呼ばれるfloatを解除するためのクラスを指定します。

HTML

<div class="cf">
  <div class="sample_a">左回り込み</div>
  <div class="sample_b">右回り込み</div>
</div>

CSS

.cf:after {
    content: "";
    display: block;
    clear: both;
}
.sample_a {
  float: left;
}
.sample_b {
  float: right;
}

.cf:after {...}がclear fixです。floatを設定した要素を囲む親要素に対して、class="cf"を指定して、floatを解除します。clearプロパティは、直前に設定したfloatを打ち消す効果を持っています。疑似要素の:afterによって、親要素の要素の直後にclear:bothを持った要素を仕込んでいるというわけです。

floatプロパティが設定された要素は浮動している(ふわふわ浮き上がっている)状態になり、本来のブロックレベル要素の配置ルールから逸脱します。この仕様を理解するために例を交えて解説します。

mainとsideという2つのブロックレベル要素をfloatで回り込ませる場合を考えてみます。ブラウザで表示すると、初期状態では以下のような見た目とコードになります。

float-1

HTML

<div id="contents">
  <div id="main">メイン</div>
  <div id="side">サイド</div>
</div>

CSS

#contents {
  width: 700px;
  margin:0 auto;
  background: #CCCCCC;
}
#main {
  width: 300px;
  height: 300px;
  background: #333DFF;
}
#side {
  width: 300px;
  height: 300px;
  background: #27C42A;
}

ここでmainにfloat: leftを追加すると以下のようになります。

float-2

CSS

#contents {
  width: 700px;
  margin: 0 auto;
  background: #CCCCCC;
}
#main {
  width: 300px;
  height: 300px;
  background: #333DFF;
  float: left;
}
#side {
  width: 300px;
  height: 300px;
  background: #27C42A;
}

sideの要素が画面から消えて、「サイド」という文字列だけがmainの下に表示されています。どういうメカニズムでこのような表示になるのかというと、mainにfloat: leftを指定したことでmainが浮き上がった状態になり、その下に重なるようにsideの要素が流れ込んでしまっています。今は見えませんが、青いブロックの下に重なるように緑のブロックが存在しているということです。存在はしていてもスペースが無いので「サイド」という文字列は行き場を無くしてしまい、このような位置に退避しているのです。

続いて、sideにもfloat: leftを指定してみると、以下のようになります。

float-3

CSS

#contents {
  width: 700px;
  margin: 0 auto;
  background: #CCCCCC;
}
#main {
  width: 300px;
  height: 300px;
  background: #333DFF;
  float: left;
}
#side {
  width: 300px;
  height: 300px;
  background: #27C42A;
  float: left;
}

mainに重なるようにして隠れていたsideが見えるようになりました。しかし、ここで注目してほしいのは親要素のcontentsという灰色のブロックが見えなくなってしまったことです。これはcontentsには高さ(height)が指定されておらず、子要素(main, side)のheightに依存していることが原因です。contentsは、mainとsideが浮動状態になったことでmainとsideを認識することができなくなってしまったので、表示上は見えなくなってしまったということです。contentsを再び表示するにはcontentsに対してheightを指定する必要があります。

流れ込みでの配置を覚える

今回はfloatプロパティを扱います。floatの最大の特徴は、回り込んでいる連続した複数の要素がある場合、要素の合計の幅が親要素の幅に収まりきらない場合は、次の行に流れ込むという仕様です。
例えば、8つのブロック(要素)を4行2列にして並べたい場合、子要素の幅を20%、左右のmarginを2.5%にすれば、要素を4つ並べると100%になり、5つ目の要素が幅に収まりきらず自動的に2列目に流れ込むので、4行2列のレイアウトを実現することができます。

4行2列のレイアウトを作るときの記述例

HTML

<ul class="sample_a cf">
    <li class="sample_b"></li>
    <li class="sample_b"></li>
    <li class="sample_b"></li>
    <li class="sample_b"></li>
    <li class="sample_b"></li>
    <li class="sample_b"></li>
    <li class="sample_b"></li>
</ul>

CSS

.cf:after {
    content: "";
    display: block;
    clear: both;
}

.sample_a {
  width: 500px;
  height: 220px;
  list-style-type: none;
}

.sample_b {
  float: left;
  width: 20%;
  height: 100px;
  margin: 5px 2.5%;
  background-color: #000;
}

動作例

その他

知っておくと少し便利なものについて軽く紹介しておきます。

要素を横並びにする複数の方法

要素を横並びに配置する方法として、前項ではfloatによる回り込みを使用することを取り上げましたが、これも含めて要素を横並びに配置する方法が主に3つあります。

  • floatによる回り込み
  • display: inline-blockによる要素のインラインブロック化
  • display: table-cellによる要素のテーブルセル化

基本的にはfloatによる回り込みさえ覚えていれば、ほとんどの場合で自由な横並びを実現することができますが、display: inline-blockdisplay: table-cellを使ったほうが良いケースもあります。以下より、該当するケースについて軽く紹介します。

floatよりもdisplay: inline-blockを使った方が良いケース

高さが異なる複数のボックスを横並びにしたいときにはdisplay: inline-blockの方が便利なことがあります。また、display: inline-blockには親要素にclear fixを記述する必要が無いというメリットもあります。

次の例ではfloatを使うと、ボックス3の高さが他のボックスよりも大きいため、上手く次の行に流れ込めずにレイアウトが崩れてしまいます。

float-bad-sample

HTML

<div id="wrapper">
  <div class="box">ボックス1</div>
  <div class="box">ボックス2</div>
  <div class="box" id="test">ボックス3</div>
  <div class="box">ボックス4</div>
  <div class="box">ボックス5</div>
  <div class="box">ボックス6</div>
  <div class="box">ボックス7</div>
  <div class="box">ボックス8</div>
</div>

CSS

#wrapper {
  width: 500px;
}
.box {
  float: left;
  width: 125px;
  height: 100px;
  font-size: 14px;
  border: 1px solid #000;
  box-sizing: border-box;
}
#test {
  height: 150px;
}

display: inline-blockを使うことで一番高さがあるブロックに合わせて、次の行が作られるため、レイアウトが崩れません。

inline-block-layout

HTML

<div id="wrapper">
  <div class="box">ボックス1</div>
  <div class="box">ボックス2</div>
  <div class="box" id="test">ボックス3</div>
  <div class="box">ボックス4</div>
  <div class="box">ボックス5</div>
  <div class="box">ボックス6</div>
  <div class="box">ボックス7</div>
  <div class="box">ボックス8</div>
</div>

CSS

#wrapper {
  width: 500px;
  font-size: 0;
}
.box {
  display: inline-block;
  width: 125px;
  height: 100px;
  font-size: 14px;
  border: 1px solid #000;
  box-sizing: border-box;
}
#test {
  height: 150px;
}

display: inline-blockを使用する際に重要なのは、親要素のdiv#wrapperに対して、font-size: 0を指定することです。inline-blockはインライン要素とブロックレベル要素の両方の性質を持っています。このうちインライン要素の性質ではソースコード上の改行が空白と見做されるため、font-size: 0を指定していないとボックス間に小さな空白が生まれます。

さらにdisplay: inline-blockにはデメリットもあり、複数行のテキストを書くとレイアウトが崩れます。例えば、ボックス1のテキストを複数行にした場合は以下のようになります。

inline-block-bad-sample

以上を考慮すると、以下のケースにdisplay: inline-blockが向いていると思います。

  • clearfix用の親要素を作るまでも無い簡単な横並びを作りたいとき(ヘッダやフッタに会社名や電話番号を横並びで配置したいときなど)
  • サイズの異なる可能性のある画像を横並びにした画像ギャラリーを作りたいとき

floatよりもdisplay: table-cellを使った方が良いケース

display: table-cellでは、インライン要素のようにvertical-align: middleが使用できます。つまり、要素を垂直方向中央寄せにしたいときにpaddingの面倒な計算をしなくて済みます。

以下のようなデザインのグローバルナビゲーションを作りたい場合を例に考えてみます。
この画像では、ホーム(Home)のリンクにカーソルを置いた状態です。このグローバルナビゲーションを実装するにはa要素がwidthとheightを持っている必要があり、クリックできる判定を持っている範囲を広げなければなりません。

display-table-cell-sample

このデザインをfloatを使用して実装すると以下のようになります。

HTML

<div class="wrapper row">
  <nav id="g_navi">
    <ul class="clearfix">
      <li><a href="index.html">ホーム<br>
        <span>Home</span></a></li>
      <li><a href="service.html">サービス<br>
        <span>Service</span></a></li>
      <li><a href="works.html">制作実績<br>
        <span>Works</span></a></li>
      <li><a href="qa.html">よくあるご質問<br>
        <span>Q&amp;A</span></a></li>
      <li><a href="company.html">会社概要<br>
        <span>Company</span></a></li>
    </ul>
  </nav>
</div>

CSS

.clearfix:after {
  content: "";
  display: block;
  clear: both;
}
.wrapper {
  width: 100%;
  margin: 0;
}
.row {
  background: #263238;
}
#g_navi {
  width: 960px;
  margin: 0 auto;
}
#g_navi ul {
  list-style: none;
  margin: 0;
  padding: 3px 0;
}
#g_navi ul li {
  display: block;
  float: left;
}
#g_navi ul li a {
  display: inline-block;
  padding: 11px 0;
  box-sizing: border-box;
  width: 192px;
  height: 44px;
  text-align: center;
  line-height: 1;
  text-decoration: none;
  color: #FFF;
  font-size: 12px;
}
#g_navi ul li a span {
  font-size: 10px;
}
#g_navi ul li a:hover {
  background: #455A64;
  font-weight: bold;
}

重要なのは、#g_navi ul liより下のCSSです。li要素をブロックレベル要素に変更し、float: leftで横並びにします。li要素の子要素のa要素に対してdisplay: inline-blockを指定することで、改行無しでwidthとheightを持つことができるようにします。

ここで注目してほしいのが、a要素の中のメニュー文字列を垂直方向中央寄せにするためにpadding: 11px 0を指定している点です。この11pxという値は、(44px - (12px + 10px)) / 2という計算によって求められた値です。内訳としては、a要素の高さからa要素の文字サイズとspan要素の文字サイズを足したものを引いてから、padding-topとpadding-bottomに対してそれぞれ空白を確保するために2で割った値が11pxになります。ぴったりと垂直方向中央寄せにするにはこのような緻密な計算が必要です。

そもそもvertical-align: middleを使用することができれば、簡単に垂直方向中央寄せにすることができるため、このような面倒な計算は必要ありません。

display: table-cellを使用して実装すると以下のようになります。

HTML

<div class="wrapper row">
  <nav id="g_navi">
    <ul>
      <li><a href="index.html">ホーム<br>
        <span>Home</span></a></li>
      <li><a href="service.html">サービス<br>
        <span>Service</span></a></li>
      <li><a href="works.html">制作実績<br>
        <span>Works</span></a></li>
      <li><a href="qa.html">よくあるご質問<br>
        <span>Q&amp;A</span></a></li>
      <li><a href="company.html">会社概要<br>
        <span>Company</span></a></li>
    </ul>
  </nav>
</div>

CSS

.wrapper {
  width: 100%;
  margin: 0;
}
.row {
  background: #263238;
}
#g_navi {
  width: 960px;
  margin: 0 auto;
}
#g_navi ul {
  display: table;
  list-style: none;
  margin: 0;
  padding: 3px 0;
}
#g_navi ul li {
  display: table-cell;
}
#g_navi ul li a {
  display: table-cell;
  vertical-align: middle;
  width: 192px;
  height: 44px;
  text-align: center;
  line-height: 1;
  text-decoration: none;
  color: #FFF;
  font-size: 12px;
}
#g_navi ul li a span {
  font-size: 10px;
}
#g_navi ul li a:hover {
  background: #455A64;
  font-weight: bold;
}

重要なのは#g_navi ulより下の行です。ul要素をdisplay: tableでテーブル要素に変更し、子要素のliにdisplay: table-cellを指定して横並びにしています。li要素の子要素のa要素に対してdisplay: table-cellを指定することで、vertical-align: middleを使用できるようにします。

ここまでdisplay: table-cellの良い点を見てきましたが、ウェブサイトのレスポンシブ化を行う際には注意が必要です。その理由はdisplay: table-cellはHTMLとデザインの結合度が強く、レスポンシブ対応がしにくいためです。

例えば、table要素で作られた以下のような表をdisplay: table-cellで実装する場合を考えてみます。

HTML

<table>
  <tr>
    <td>チャッピー</td>
    <td>4歳</td>
  </tr>
  <tr>
    <td>ハナコ</td>
    <td>6歳</td>
  </tr>
</table>

display: table-cellで実装すると以下のようになります。

HTML

<div class="table">
  <div class="table-row">
    <p class="table-cell">チャッピー</p>
    <p class="table-cell">4歳</p>
  </div>
  <div class="table-row">
    <p class="table-cell">ハナコ</p>
    <p class="table-cell">6歳</p>
  </div>
</div>

CSS

.table {
  display: table;
}
.table-row {
  display: table-row;
}
.table-cell {
  display: table-cell;
}

上記のようにdisplay: table-cellは改行を行う場合にdisplay: table-rowが必須になります。レスポンシブ化でデバイスごとにデザインの変更を求められた場合、デザインがHTMLの構造に束縛されてしまい、柔軟なレイアウトを行うことができません。

上記について、もっと深く理解するために新たな例を交えて解説します。以下のようにulとli要素を使用してdisplay: table-cellで横並びにする場合を考えてみます。

HTML

<ul>
  <li><a href="#">テキスト</a></li>
  <li><a href="#">テキスト</a></li>
  <li><a href="#">テキスト</a></li>
  <li><a href="#">テキスト</a></li>
  <li><a href="#">テキスト</a></li>
</ul>

CSS

ul {
  display: table;
}
ul li {
  display: table-cell;
}

一行に並べるだけであれば問題ありませんが、レスポンシブ対応で2列3行や3列2行への変更が求められた場合、HTMLにdisplay: table-rowを持つ要素を作らなければ対応することができません。

このようにdisplay: table-cellはHTMLとデザインの結合が強いので、レスポンシブ対応がしにくいという欠点があります。

ブラウザで要素を検証する

Google Chrome(Firefox)に備え付けられているデベロッパーツールを使用することで、CSSが効かないときなどに素早く解決することができます。デベロッパーツールは、ブラウザ上で右クリックし、検証(Firefoxでは要素の調査)をクリックすると開くことができます。ショートカットキーはWindowsではCtrl-Shift-iで、MacではCmd-Opt-iとなっています。

基本的な使い方としては、Elements(Firefoxではインスペクタ)のタブを開くと、HTMLコードが表示されます。HTMLコードの要素をクリックすると、要素に適用されているCSSプロパティを見ることができます。

左上にあるマウスカーソルのアイコンをクリックすると要素選択モードになり、ページ内の要素にカーソルを合わせるとwidth、height、margin、padding、borderといったCSSプロパティが視覚的に色分けされて表示されます。そのままページ内の要素をクリックすると、コード上の一致する要素がElements(Firefoxならインスペクタ)に表示されます。

さらにStylesタブ(Firefoxではスタイル)を使用することで、リアルタイムにCSSを変更して変化を確認することができます。

また、ウェブサイトをレスポンシブ対応するときに非常に強力なツールも備わっています。Toggle device toolbar(Firefoxではレスポンシブデザインモード)のスマートフォンアイコンをクリックすると、PC表示モードとスマートフォン表示モードを切り替えることができます。

ブラウザをCSSエディタとして使用する

Google Chromeのデベロッパーツールに備わっているFilesystemsやOverridesを使用することで、ブラウザで調整したCSSを直にローカルファイルに保存することができます。

Filesystems

Filesystemsはローカルに保存されているファイルをGoogle Chromeから直接編集する機能です。

デベロッパーツールのSourcesタブ内にあるFilesystemsタブを選択します。ここでAdd folder to workspaceをクリックし、ワークスペース化したいフォルダを選択することで、そのフォルダ内のHTMLとCSSをFilesystemsタブ内から直接編集できるようになります。また、CSSに限り、Elementsタブ内で編集した内容がFilesystemsにも反映されるため、Ctrl-sやCmd-sなどの保存ショートカットを使用して簡単に保存することができます。

Overrides

OverridesはFilesystemsと非常に良く似た機能です。Filesystemsが直接ローカルファイルを編集するのに対し、Overridesはローカルファイルのコピーを作り出し、そのコピーをGoogle Chromeに参照させます。
通常、ElementsタブからCSSに変更を加える場合、ページを誤って更新してしまうと編集したCSSは消失してしまいますが、OverridesではCSSの変更を永続化することができます。

デベロッパーツールのSourcesタブ内にあるOverridesタブを選択します。ここでSelect folder for overridesをクリックし、ワークスペース化したいフォルダを選択することで、そのフォルダ内のHTMLとCSSのコピー(オーバーライド用のファイル)をOverridesタブ内から編集できるようになります。また、CSSに限り、Elementsタブ内で編集した内容が即座にOverridesに保存されます。保存の作業を行う必要はありません。

参考
meta要素でビューポートを指定する-ウェブ制作チュートリアル
3.2.5 Content models — HTML5
header 要素 - html5doctor - HTML5.JP
ブロックレベル要素とインライン要素
ボックスモデル|CSSの基本|CSS HappyLife ZERO
position:relativeの使いドコロ
入れ子状態のブロック要素の上下マージンの困った挙動(マージンの相殺) | IT工房|Webデザイン入門
marginの相殺を正しく理解しておこう!相殺はいつ起こるのか、相殺を回避するテクニック | コリス
CSSの【float】についてちょっと本気出して説明してみた。 | たねっぱ!
重ね合わせコンテキスト | MDN
[CSS] z-index とスタックコンテキスト - Qiita
display:table-cell;を安易に使うべきでない理由いろいろ - Qiita