【初心者向け】HTML+CSSの練習に最適!KROWLコーディング課題「ツールの紹介サイト」 – 解説編 その4

本記事では前回に続き、HTML / CSSの練習用にKROWLサイトで配布している、KROWLコーディング課題「ツールの紹介サイト」のコード解説をしていきたいと思います。

まだ「その1」「その2」「その3」を読んでいない方は、ぜひそちらからお読みください。

ぜひKROWLサイトから課題をダウンロードし、同梱されているサンプルコードを見ながらお読みください!

本シリーズも今回でいよいよ大詰め。
「お客様の声」セクションと「お問い合わせ」を攻略し、完成させましょう!

※本記事に掲載されているコードはあくまでも一例です。絶対的な正解というわけではありませんので、予めご了承ください。

工程その11 「お客様の声」セクションを実装する

まずは1ブロック分作ってしまう

とにもかくにもhtmlです。
今回も例に漏れず、.voice-blockというかたまりと.voice-listというリストに分けました。

<!-- お客様の声 -->
<section id="client-voice" class="section">
  <div class="common-inner">
    <h2 class="section__title typo-bold"><span>お客様の声</span></h2>
    <ul class="voice-list">
      <li class="voice-list__item voice-block">
        <figure class="voice-block__client-image">
          <img src="assets/images/photo-mr_okochi.jpg" alt="株式会社グローバルマーケティングジャパン ダイレクトソリューション2部 大河内様">
          <figcaption>株式会社グローバルマーケティングジャパン<br>ダイレクトソリューション2部 大河内様</figcaption>
        </figure>
        <p class="voice-block__message">Data Maniaを導入する前は、全てのデータひとつひとつ集め、それを分析し、レポートするまでを全て手作業で行っていました。<br>この工程で膨大な時間を使ってしまい、肝心のマーケティング施策を考える時間がどんどん削られていましたが、Data Mania導入後はそういった作業を一切しなくて済むようになりました。<br>これからもきっと我が社には欠かせないツールであり続けると確信しています。</p>
      </li>
    </ul>
  </div>
</section>
<!-- お客様の声 -->
.voice-block {
 border: 1px solid #ddd;
 box-sizing: border-box;
 /* 「3つの強み」の画像で使ったパターンを応用し、border-radius + overflow: hiddenで角丸を作る */
 border-radius: 10px;
 overflow: hidden;
}

.voice-block__client-image figcaption {
 /* 高さの最低値を { フォントサイズ×行高×2行分 } + { 上下のpaddingの合計 } で設定する */
 min-height: calc((1em * 1.75 * 2) + 28px);
 padding: 14px 20px;
 box-sizing: border-box;
 background-color: #008DD5;
 font-size: 1.6rem;
 line-height: 1.75;
 color: #fff;
}

.voice-block__message {
 padding: 20px;
 font-size: 1.6rem;
 line-height: 1.75;
}

やや長い気もしますが、内容としてはパッと見た印象より難しくありません。
ただひとつだけ見逃してはいけない部分があります。それが、.voice-block__client-image figcaptionmin-heightです。

ここには基本的に「会社名+所属名+お名前」という要素を2行に分けて入れていますが、「株式会社山月堂 中島様」のように行だけのパターンもあります。
そこで「よしじゃあ高さを84pxで指定してやろう」と考える方もいらっしゃると思いますがちょっと待ってください
もしかしたら将来的には「株式会社スーパーハイパーテクノロジー未来ブラウザ研究所」のようなとても長い会社名を掲載することになり、3行になる可能性もあります。
もし高さを固定値で置いてしまったら、そういう場合に文字が溢れてしまいます。

エンジニアであればこの程度のことはきちんと予想した上で実装しなければなりません。
そこで今回は以下の2点を満たした実装する必要があります。

  • 最低でも2行分の高さを確保する
  • 3行以上になっても崩れない

これを実現するためにmin-heightで最小の高さを確保するという手段が有効なわけですね。
今回はコンテンツの中身が書き換わらない「静的Webサイト」ですが、データベースからデータを引っ張ってきて表示する「動的Webサイト」では、こうした「デザインデータでは想定されていない表示のされ方」が往々にして出てきます。
こういうこともきちんと考えて実装するのがプロの仕事と言えるでしょう。

作ったブロック4つ分を並べる

このセクションは高さの異なる「お客様の画像+コメント」というブロックが、2カラムの横並びレイアウトで存在しています。
ここは前回のようにFlexboxで実現でき…ないこともないのですが、ちょっと面倒なのでやめておきます。
というのも、今回のデザインは以下のように2段目のグループの上辺の位置が異なっており、さらに右側のブロックに関しては1段目に少し食い込んでいるのです。

そこで今回はfloatプロパティを使っていきます。
まずはhtmlを書いていきますが、ブロックの順番に気をつけましょう。

<ul class="voice-list">
  <li class="voice-list__item voice-block">
    <figure class="voice-block__client-image">
      <img src="assets/images/photo-mr_okochi.jpg" alt="株式会社グローバルマーケティングジャパン ダイレクトソリューション2部 大河内様">
      <figcaption>株式会社グローバルマーケティングジャパン<br>ダイレクトソリューション2部 大河内様</figcaption>
    </figure>
    <p class="voice-block__message">...省略...</p>
  </li>
  <li class="voice-list__item voice-block">
    <figure class="voice-block__client-image">
      <img src="assets/images/photo-ms_kagari.jpg" alt="株式会社キャトルミューティレーション アカウントセールス事業部 篝様">
      <figcaption>株式会社キャトルミューティレーション<br>アカウントセールス事業部 篝様</figcaption>
    </figure>
    <p class="voice-block__message">...省略...</p>
  </li>
  <li class="voice-list__item voice-block">
    <figure class="voice-block__client-image">
      <img src="assets/images/photo-mr_davis.jpg" alt="株式会社Greeeeed コンサルティングチーム Mike Davis様">
      <figcaption>株式会社Greeeeed<br>コンサルティングチーム Mike Davis様</figcaption>
    </figure>
    <p class="voice-block__message">...省略...</p>
  </li>
  <li class="voice-list__item voice-block">
    <figure class="voice-block__client-image">
      <img src="assets/images/photo-mr_nakajima.jpg" alt="株式会社山月堂 中島様">
      <figcaption>株式会社山月堂 中島様</figcaption>
    </figure>
    <p class="voice-block__message">...省略...</p>
  </li>
</ul>

通常横並びのレイアウトは左にあるものから先に書くと思いますが、今回はfloatを使う関係で「Mike Davis様」と「中島様」が逆になっています。
それでは実際やってこのレイアウトを実現していくのか、CSSを見てみましょう。

/* セクション自体の背景色に水色を設定 */
#client-voice {
 background-color: #E6F6FF;
}

.voice-list {
 padding: 60px;
 background-color: #fff;
}

/* clearfixという手法で回り込みを解除 */
.voice-list::after {
 display: block;
 clear: both;
 content: '';
}

/* 他の場所で使うことも考慮し、.voice-block自体には幅を持たせず.voice-list__itemに幅を持たせる */
.voice-list__item {
 width: 400px;
}

/* 大河内様&中島様 */
.voice-list__item:nth-child(1), .voice-list__item:nth-child(4) {
 float: left;
}

/* 篝様&Mike Davis様 */
.voice-list__item:nth-child(2), .voice-list__item:nth-child(3) {
 float: right;
}

/* 3つ目以降、つまり2段目以降の要素には上方向に対して80pxの余白を設ける */
.voice-list__item:nth-child(n+3) {
 margin-top: 80px;
}

実は「左にあるものはfloat: left」「右にあるものはfloat: right」としただけだったりします。
Flexboxの登場によってあまり使われなくなってきたfloatプロパティも、それでなければできないことがあります。
似たような効果を持つプロパティでも、それぞれの性質をきちんと理解して最適な利用を心がけましょう。

工程その12 「お問い合わせ」を実装する

いよいよ最後です。
ここまで大量のコードを書いてきて疲れていると思いますが、解説を書いている僕も疲れています。あとひと踏ん張りなので一緒にがんばりましょう!

まずは外側を作っておく

とりあえずフォーム自体の外側を作っておくことにします。
form要素には通常action属性にデータの送信先を指定しますが、本課題はあくまでも見た目を作ることが目的なので、今回は指定しないでおきます。
実際にフォームとして使用するためにはPHPやJavaといったサーバーサイド言語を用いてその仕組を作る必要がありますが、今回はあくまでもHTMLとCSSでできる範囲に留めておきます。

<!-- お問い合わせ -->
<section id="contact" class="section">
  <div class="common-inner">
    <h2 class="section__title typo-bold"><span>お問い合わせ</span></h2>
    <form action="#" method="POST" class="contact-form">
    </form>
  </div>
</section>
<!-- お問い合わせ -->

フォーム自体の横幅は600pxで固定です。

.contact-form {
 width: 600px;
 margin: 0 auto;
}

「お名前」と「メールアドレス」を実装する。

複雑なものも含まれるので分けて進めていきます。
今回は以下の2つの要素を.form-partsというグループとして扱い、label要素で包んでいます。

  • 「お名前」や「メールアドレス」といった項目名
  • inputやselectといったフォーム部品自体

label要素で包むことによって、内包される子要素のどこをクリック(タップ)してもフォームの入力にフォーカスされるようになり、UXの向上に繋がります。

<form action="#" method="POST" class="contact-form">
  <!-- ↓追加↓ -->
  <label class="form-parts">
    <span class="form-parts__label typo-bold">お名前</span>
    <input type="text" name="your-name">
  </label>
  <label class="form-parts">
    <span class="form-parts__label typo-bold">メールアドレス</span>
    <input type="email" name="your-email">
  </label>
  <!-- ↑追加↑ -->
</form>
/* 項目名+フォーム部品 */
.form-parts {
 display: block;
 margin-bottom: 30px;
}
/* 項目名のスタイル */
.form-parts__label {
 display: block;
 margin-bottom: 10px;
 font-size: 1.6rem;
 line-height: 1;
}
/* お名前とメールアドレスを入力するための部品 */
input[type=text],
input[type=email] {
 display: block;
 width: 100%;
 padding: 10px;
 box-sizing: border-box;
 border: 1px solid #000;
 border-radius: 4px;
 font-size: 1.6rem;
}

「お問い合わせ種別」を実装する

さて、ここからちょっと難易度が上がります。

<form action="#" method="POST" class="contact-form">
  ...省略...
  <label class="form-parts">
    <span class="form-parts__label typo-bold">お問い合わせ種別</span>
    <span class="select-wrapper">
      <select name="subject">
        <option value="選択肢1">選択肢1</option>
        <option value="選択肢2">選択肢2</option>
        <option value="選択肢3">選択肢3</option>
        <option value="選択肢4">選択肢4</option>
        <option value="選択肢5">選択肢5</option>
      </select>
    </span>
  </label>
</form>

見たところ、select要素が.select-wrapperというクラス名を持つspan要素で囲われています。
これが今回のフォームの一番のミソになります。
CSSを確認し、その謎を解き明かしましょう。

.select-wrapper {
 display: block;
 width: 200px;
 height: 40px;
 border: 1px solid #000;
 border-radius: 4px;
 box-sizing: border-box;
 position: relative;
}

/*
  select要素自体をcustom_reset.cssで不可視の状態にした上で幅・高さを親要素に対して100%にすることで、select要素自体の見た目は無視し機能だけを使うことができる
*/
.select-wrapper select {
 width: 100%;
 height: 100%;
 padding-left: 10px;
 box-sizing: border-box;
 font-size: 1.6rem;
}

/* 三角アイコンを.select-wrapperのafter疑似要素として設置する */
.select-wrapper::after {
 content: '';
 display: block;
 width: 12px;
 height: 9px;
 background: url(../images/icon-triangle.png) left top no-repeat;
 position: absolute;
 top: 50%;
 right: 10px;
 z-index: 1;
 transform: translateY(-50%);
}

一番注目すべき点は.select-wrapper::afterです。
今回はプルダウンメニューであることを示す三角形のアイコンを、この疑似要素として設置しています。
いやいやそんな面倒なことしなくてもselect要素自体の子要素として置いてしまえば、わざわざ.select-wrapperなんてものをを使わなくても済むんじゃ…と思う方もいらっしゃるかもしれません。
ところがhtml5の仕様では、select要素は基本的にoption要素もしくはoptgroup要素しか子要素として内包できません。
(※script要素やtemplate要素は除きます)

また、疑似要素をあてることもできないので、select要素自体を他の要素で包み、それの子要素もしくは疑似要素としてアイコンを設定してあげる必要があるわけです。

「お問い合わせ内容」を実装する

ここについては、ここまでできた方には物足りないくらい簡単でしょう。
ただ一点だけ、resize: noneという指定をすることで、ユーザーによるリサイズを抑止している点について注意してください。

<form action="#" method="POST" class="contact-form">
  ...省略...
  <label class="form-parts">
    <span class="form-parts__label typo-bold">お問い合わせ内容</span>
    <textarea name="body"></textarea>
  </label>
</form>
textarea {
 width: 600px;
 height: 200px;
 padding: 10px;
 box-sizing: border-box;
 border: 1px solid #000;
 border-radius: 4px;
 font-size: 1.6em;
 line-height: 1.75;
 resize: none;
}

「送信ボタン」を実装する

さあいよいよ最後です。フォームがあるならそこには送信ボタンが存在するはずです。
しかもこれは「その2」で既に作成済みです。サクッと書いてしまいましょう。
一点注意していただきたいのがonclick=”return false;”です。
本章の最初でも述べましたが、今回は送信する先がない(=あくまでも見た目を作るのが課題の目的)ので、送信ボタンをクリックしたこと自体を無効化しておきます。

<form action="#" method="POST" class="contact-form">
  ...省略...
  <button type="submit" class="contact-form__send-button primary-button primary-button--monochrome typo-bold" onclick="return false;">送信</button>
</form>

ボタン自体の見た目はもうできているので、あとは配置の問題ですね。
.primary-button, .primary-button–monochromeの他に、.contact-form__send-buttonという、このフォームでのみ使う固有のクラス名を付与しておきます。

.contact-form__send-button {
 margin: 50px auto 0;
}

そしてその固有のクラス名に対して余白を設定します。
「お問い合わせ内容」の方にもmargin-bottom: 30pxが指定されていますが、以下の画像のようにマージンの相殺が発生するため、.contact-form__send-buttonに設定された50pxの方が優先されます。

さて、フォームはこれで全て完了です!
フォーム部品で言うとチェックボックスやラジオボタンなど、他にもまだまだよく使うものはありますが、それらはまた別の課題としてご用意できればと思います。

まとめ

今回のポイントはこちらです。

  • とにもかくにも「デザインの外側」を意識する
  • Flexboxとfloatの違いをきちんと理解する
  • プルダウンメニューのカスタマイズはselect要素の親要素を使う
  • マージンの相殺を忘れずに!

全4回に渡って解説してきたKROWLコーディング課題「ツールの紹介サイト」ですが、これを自力でクリアできた方は十分「初心者」の域を脱していると思います。
恐らく、今回は特に「自分の書き方と違った…」と感じる部分が多かったという方もいらっしゃると思いますが、コーディングに絶対的な正解という書き方はありません。
本解説はあくまでも「一例」として参考にしていただけると幸いです。
(「もっとクールなやり方を発見したぜ!」という方は是非教えてください)

▼イベント情報はこちら

▼前の記事はこちら

HTMLやCSS、JavaScriptの学習をしている方に向けて無料のコーディング課題をKROWLサイトで配布中!
難易度別に用意してあるサンプルサイトのデザインデータを元に、サイト制作のスキルを磨こう!

関連記事