コーディングにおいて横並びのレイアウトは必ずと言っても良いほど登場します。
基本的にはdisplayプロパティを使えば簡単に横並びにすることはできます。
しかしWordPress化などで実際に文章が挿入されたときにレイアウト崩れが起きることがありませんか?
コーディングしていたときに想定していた文章量と、実際にブログサイトを運営したときの文章量が違うことはよくあります。
「基本的なレイアウトは作れるけど応用ができない」
「ググってやってもレイアウトが綺麗に揃わない」
「いざアップしてみると思ってた感じと違う。。。」
本日はそんな横並びレイアウトに関する内容です。
さらにJavaScriptを使わずにきれいに作る方法に絞って紹介するので、コーディング初心者でも活用して頂けると思います。
またいろんなパターンがありますので該当する部分だけ読んでもらっても良いかもしれません。
今回紹介する横並びレイアウトのパターンは以下の通りです。
①文章の行数で高さを揃えるパターン
②文章量によって変わる余白を調整することで高さを揃えるパターン
③ボタンをクリックすると非表示になっている文章が表示されるパターン
④抜粋文の1行だけを表示するパターン
それぞれのパターンについて動画も用意しているので適宜で使ってみてください。
①文章の行数で高さを揃えるパターンの動画
②文章量によって変わる余白を調整することで高さを揃えるパターンの動画
③ボタンをクリックすると非表示になっている文章が表示されるパターンの動画
④抜粋文の1行だけを表示するパターンの動画
一番カンタンに横並びの高さを揃える方法
今回はホームページにおけるニュース機能を想定して作ってみました。
HTMLについては以下の通りです。
<section class="card-group">
      <article class="card">
        <h2>2022年4月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等
        </p>
      </article>
      <article class="card">
        <h2>2022年5月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認する
        </p>
      </article>
      <article class="card">
        <h2>2022年6月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れ
        </p>
      </article>
</section>特に難しいことはしていません。
3個のニュース記事を並べている形になっています。
続いてCSSはこちらになります。
* {
  box-sizing: border-box;
}
body {
  background: #fff;
  overflow: hidden;
}
.card-group {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
  align-items: flex-start;
}
.card {
  background: #fff;
  padding: 1rem;
  border: 1px solid #333;
  border-radius: 0.25rem;
}
h2,
p {
  margin: 0;
}
h2 {
  margin-bottom: 1rem;
}
.text {
  --max-lines: 3;
  display: -webkit-box;
  -webkit-line-clamp: var(--max-lines);
  overflow: hidden;
  -webkit-box-orient: vertical;
}注目してもらいたいのは、pタグになる「.text」の部分です。
こちらはコピペでも問題ないです。
簡単に説明すると「3行目まで表示して、それ以降は非表示にする」ということをしているので、結果的に高さが揃う形になっています。
こちらで以下のように簡単に高さを揃えることが出来ました。

ちなみに「.text」の「- -max-lines」についてはCSS変数になります。
「- -」を先頭につけるとCSSのなかで変数として使い回すことが出来ます。
「- -max-lines」に「3」を入れているので3行目で留めることになっていますので、例えば「5」を入力すると5行目までにすることも出来ます。

「CSSで変数なんて使ったことない」という方は多いと思いますが、このようにコードの使い回しは後々の修正や追加作業で自分を楽にすることになるので積極的に使っていきましょう。
行数ではない揃え方
続いて行数ではなく「コンテンツのサイズ」で揃える方法を紹介します。
少し書く量が増えますが、実際の開発現場でも使われるテクニックなので知っておくだけでも全然違ってきます。
HTMLは特に変更ないので、CSSを以下のように書き換えてみます。
* {
  box-sizing: border-box;
}
body {
  overflow: hidden;
  margin: 0;
  padding: 0;
}
.card-group {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
  align-items: flex-start;
}
.card {
  padding: 16px;
  border: 1px solid #333;
  border-radius: 0.5rem;
}
.text {
  --max-lines: 5;
  --line-height: 1.7;
  max-height: calc(var(--max-lines) * 1em * var(--line-height));
  overflow: hidden;
  position: relative;
}
.text::before {
  content: "";
  position: absolute;
  height: calc(1em * var(--line-height));
  width: 100%;
  bottom: 0;
  pointer-events: none;
}こちらもpタグの「.text」に注目します。
疑似要素とセットで高さを計算されたものにしています。
「- – line-height」というものがありますが、先ほど同様にCSS変数になります。
「- -max-lines」「- -line-height」を掛け合わせることで「行数×行間」という計算をしているのです。
これにより行数ではなく「コンテンツのサイズ」を起点にして高さ調整が可能になりました。
表示内容としては先ほどと変わりません。

ボタンを使った表示、非表示を作る
今回の記事としては以上になるのですが、せっかくなのでボタンを使ったコンテンツの表示、非表示の切り替えまで紹介します。
実際には「高さを揃えるだけ」で完成になることはないですよね。
最終的なゴールとしては各コンテンツの表示まで求められます。
ボタンについてはHTMLでinputタグを使って実装してみます。
<section class="card-group">
      <article class="card">
        <h2>2022年4月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等
        </p>
        <input type="checkbox" class="btn" />
      </article>
      <article class="card">
        <h2>2022年5月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認する
        </p>
        <input type="checkbox" class="btn" />
      </article>
      <article class="card">
        <h2>2022年6月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れ
        </p>
        <input type="checkbox" class="btn" />
      </article>
</section>inputタグのtype属性を「checkbox」にしておくのを忘れないでください。
今回はチェックボッスを使ったボタンになります。
「なぜチェックボックスなのか?」は後々に説明します。

現状はチェックボックスが表示されているので、こちらのチェックボックスにCSSを当てていきます。
* {
  box-sizing: border-box;
}
body {
  background: #fff;
  overflow: hidden;
}
.card-group {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
  align-items: flex-start;
}
.card {
  background: #fff;
  padding: 1rem;
  border: 1px solid #333;
  border-radius: 0.25rem;
}
h2,
p {
  margin: 0;
}
h2 {
  margin-bottom: 1rem;
}
.text {
  --max-lines: 5;
  --line-height: 1.4;
  max-height: calc(var(--max-lines) * 1em * var(--line-height));
  line-height: var(--line-height);
  overflow: hidden;
  position: relative;
}
.text:has(+ .btn:not(:checked))::before {
  content: "";
  position: absolute;
  height: calc(1em * var(--line-height));
  width: 100%;
  bottom: 0;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, #fff);
}
.btn {
  appearance: none;
  border: 1px solid #333;
  padding: 0.5em;
  border-radius: 0.25em;
  cursor: pointer;
  margin-top: 1rem;
}
.btn::hover {
  background: #ccc;
}
.btn::before {
  content: "もっと見る";
}
.btn:checked::before {
  content: "閉じる";
}
.text:has(+ .btn:checked) {
  max-height: none;
}inputタグが「.btn」になるので、こちらにスタイルを書きました。
ボタンの文字は疑似要素のcontentプロパティに「もっと見る」「閉じる」を指定しています。
表示内容はこのようになっています。

ボタンが表示されていて、「もっと見る」という文字になっています。
さらに文章の部分にも注目してみてください。
5行目がうっすら非表示になっていますね、これが先ほどからお話している「コンテンツの高さ」で揃えている効果です。
行数ではなくコンテンツの高さで揃えることで、今回のようにボタンを後から追加しても全体のサイズは変わりません。
コーディングをしているとデザイナーさんから「これも追加で!」と追加の表示内容をもらうことがあります。
追加の依頼が来てもサイズが変わらないような組み方をすることを意識できるようになるとレベルアップしたと言っても良いでしょう。
少し脱線しましたがボタンについて、クリックすると以下のように動作します。

ボタンの文字が「閉じる」に切り替わって、文章が全体まで表示されています。
これらを実現しているのは主に以下の部分です。
.text:has(+ .btn:not(:checked))::before {
  content: "";
  position: absolute;
  height: calc(1em * var(--line-height));
  width: 100%;
  bottom: 0;
  pointer-events: none;
}.text:has(+ .btn:checked) {
  max-height: none;
}「has」という文法を使うことで「.textの直後にある.btn」という意味になります。
HTMLを見返してみましょう。
<article class="card">
        <h2>2022年4月1日</h2>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等
        </p>
        <input type="checkbox" class="btn" />
</article>「.text」のすぐ次に「.btn」が存在していますね。
さらにinputタグをチェックボックスにしていることで、「チェック(クリック)」を利用できるようになっています。
「チェック(クリック)されていなければ高さを揃えておく」が以下の部分です。
.text:has(+ .btn:not(:checked))::before {
  content: "";
  position: absolute;
  height: calc(1em * var(--line-height));
  width: 100%;
  bottom: 0;
  pointer-events: none;
}「チェック(クリック)されたら高さを揃えずに全て表示」が以下の部分です。
.text:has(+ .btn:checked) {
  max-height: none;
}これがinputタグでチェックボックスをあえて使っていた理由になります。
チェックボックスは今回のように違う用途にも利用できるので、日々のコーディングでチェックボックスが使えそうな部分が無いか探してみるのも良いかもしれませんね。
文章量が違う時の余白を調整する方法
ここまでは余白はないものとして高さを揃えてきましたが、デザインによっては余白を表示したい時もあります。
そのような場合もCSSで余白を調整することで高さを揃えつつ、文章量が違うときに余白を動的に変化させることができます。
例えばカードによって文章量が違う以下のような料金プランのデザインがあったとします。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./script.js" defer></script>
  </head>
  <body>
    <div class="container">
      <h1>プラン</h1>
      <ul>
        <li>
          <h2>ライトプラン</h2>
          <p>
            この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーで
          </p>
          <a href="">詳しく見る</a>
        </li>
        <li>
          <h2>ベーシックプラン</h2>
          <p>
            この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、
          </p>
          <a href="">詳しく見る</a>
        </li>
        <li>
          <h2>プレミアムプラン</h2>
          <p>
            この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を
          </p>
          <a href="">詳しく見る</a>
        </li>
      </ul>
    </div>
  </body>
</html>* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.container {
  width: 80%;
  margin: 0 auto;
}
ul {
  display: flex;
  list-style: none;
}
li {
  flex: 0 0 33.33%;
  display: flex;
  flex-flow: column;
  border: 1px solid #666;
  padding: 8px;
}
p {
  margin-top: 8px;
}
a {
  display: inline-block;
  text-decoration: none;
  text-align: center;
  background: #333;
  color: #fff;
}
カード自体の高さは揃っていますが文章量が違うために「詳しく見る」のボタンの位置がバラバラですね。
こちらは文章とボタンの間に余白を入れることで解決できます。
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.container {
  width: 80%;
  margin: 0 auto;
}
ul {
  display: flex;
  list-style: none;
}
li {
  flex: 0 0 33.33%;
  display: flex;
  flex-flow: column;
  border: 1px solid #666;
  padding: 8px;
}
p {
  margin-top: 8px;
}
a {
  display: inline-block;
  /* ここを追加 */
  margin-top: auto;
  text-decoration: none;
  text-align: center;
  background: #333;
  color: #fff;
}aタグ(ボタン)に対してmargin-top: auto;を追加しました。

これでボタンの位置が揃って綺麗な横並びカードになりましたね。
文章とボタンの間に余白を追加しただけなのですがポイントは値をautoにしたことです。
autoは自動計算という意味になっていて今回のような文章量が違って余白の値を固定にできないときに使用すると良いです。

抜粋文を1行だけ表示するパターン
最後に抜粋文を1行だけ表示するパターンで高さを揃える方法も紹介します。
これまでのパターンは何行か残す方法でしたが、1行だけ表示する抜粋文のような見せ方もデザインとしてあります。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./script.js" defer></script>
  </head>
  <body>
    <div class="news">
      <article>
        <p class="date">2023.01.01</p>
        <p class="text">この文章はダミーです。</p>
      </article>
      <article>
        <p class="date">2023.01.02</p>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。
        </p>
      </article>
      <article>
        <p class="date">2023.01.03</p>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。
        </p>
      </article>
    </div>
  </body>
</html>* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.news {
  width: 1000px;
  display: flex;
}
article {
  width: 33.33%;
  border: 1px solid #333;
  padding: 8px;
}
p {
  font-size: 20px;
}
.date {
  font-weight: bold;
  color: #000;
}
.text {
  color: #666;
  height: 30px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
やっていることはまず高さをheightで指定して、その高さを超える部分をoverflow: hidden;で非表示にします。
また通常であれば文章は自動的に折り返しされるのですがwhite-space: nowrap;で折り返しせずに1行にしています。
white-space: nowrap;だけ指定した場合は↓のようになるわけです。

そして最後にtext-transform: ellipsis;というものを使うことで収まらない部分を「…」で省略する抜粋文のような見せ方をしています。
とても簡単なコードだけで抜粋文は作れるんですね、初心者でもすぐに真似できます。
ちなみに抜粋文ではなく、1行にして収まらない部分を「…」ではなくアニメーションで表示することもできます。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./script.js" defer></script>
  </head>
  <body>
    <div class="news">
      <article>
        <p class="date">2023.01.01</p>
        <p class="text">この文章はダミーです。</p>
      </article>
      <article>
        <p class="date">2023.01.02</p>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。
        </p>
      </article>
      <article>
        <p class="date">2023.01.03</p>
        <p class="text">
          この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。
        </p>
      </article>
    </div>
  </body>
</html>* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.news {
  width: 1000px;
  display: flex;
}
article {
  width: 33.33%;
  border: 1px solid #333;
  padding: 8px;
  overflow: hidden;
}
p {
  font-size: 20px;
}
.date {
  font-weight: bold;
  color: #000;
}
.text {
  color: #666;
  height: 30px;
  white-space: nowrap;
  animation: slide 8s linear infinite;
}
@keyframes slide {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-100%);
  }
}こちらはkeyframesというアニメーションを取り入れています。
ただやっていることはtransformでtranslateX(-100%)からtranslateX(0)にして横にゆっくり移動させているだけです。
keyframesについては別の動画で詳しく使い方を解説しているので興味がある方はどうぞ。

