まずは「もっと見る」ボタンの動きを確認する
Web制作の現場では、「最初は3件だけ表示して、ボタンをクリックしたら残りも見せたい」という要望がよくあります。
今回作るのは、このような「もっと見る」ボタンです。最初は一部のリストだけを表示し、ボタンをクリックすると非表示だった項目が見えるようになります。もう一度クリックすると閉じる、という基本形で作っていきます。
完成イメージ
- 制作メモ 01
- 制作メモ 02
- 制作メモ 03
- クリック後に続きを表示
この小さな実装の中に、Web制作でよく使うJavaScriptの考え方が入っています。ユーザーのクリックを受け取り、HTMLにクラスを付け外しし、見た目の変化はCSSに任せる。まずはこの流れを掴むことが目的です。
コピペから一歩先へ進むために
HTML/CSSやWordPressは触れるけれど、JavaScriptになると急に手が止まる。Web制作の現場では、そう感じる人は少なくありません。
ネットで見つけたコードを貼り付けて、動いたらそのまま使う。これも実務ではよくありますし、コピペ自体が悪いわけではありません。大切なのは、貼り付けたコードが何をしているのかを少しずつ理解して、案件に合わせて安全に調整できるようになることです。
そして、jQueryも否定しません。既存案件やWordPressテーマでは、すでにjQuery前提で作られていることも多く、その流れに合わせる判断が自然な場面もあります。
標準JavaScript、jQuery、CSSだけで済ませる方法、HTML標準機能。どれかひとつを正解にするのではなく、案件に合わせてちょうどよい方法を選べることを目指します。
- ユーザーのクリックを受け取る
- HTMLにクラスを付け外しする
- 見た目の変化はCSSに任せる
この記事で学べること
-
querySelectorでHTML要素を取得する方法 -
addEventListenerでクリックを検知する方法 -
classList.toggleでクラスを付け外しする方法 - ボタンの文言を切り替える方法
- JSを使わない代替案を知る
HTMLを書く
まずはリストとボタンを用意します。JavaScriptから見つけやすいように、対象のリストにはjs-more-list、ボタンにはjs-more-buttonというクラスを付けています。
<ul id="moreList" class="more-list js-more-list">
<li class="more-list__item">記事タイトル 01</li>
<li class="more-list__item">記事タイトル 02</li>
<li class="more-list__item">記事タイトル 03</li>
<li class="more-list__item more-list__item--hidden">記事タイトル 04</li>
<li class="more-list__item more-list__item--hidden">記事タイトル 05</li>
<li class="more-list__item more-list__item--hidden">記事タイトル 06</li>
</ul>
<button
class="more-button js-more-button"
type="button"
aria-expanded="false"
aria-controls="moreList"
>
もっと見る
</button>
ポイント:装飾用のクラスとJS用のクラスを分けておくと、CSS変更の影響でJavaScriptが動かなくなる事故を減らせます。
CSSを書く
CSSでは、閉じている状態と開いている状態を用意します。JavaScriptはis-openを付け外しするだけにして、見た目の変化はCSSに任せます。
.more-list__item--hidden {
display: none;
}
.more-list.is-open .more-list__item--hidden {
display: list-item;
}
.more-button {
border: 0;
border-radius: 999px;
background: #2563EB;
color: #fff;
padding: 12px 20px;
font-weight: 700;
}
CSSだけでできる場合:開閉だけならdetailsとsummaryで実装できるケースもあります。デザインや挙動の要件が少ないときは、JavaScriptなしの選択肢も検討できます。
JavaScriptを書く
JavaScriptでは、ボタンがクリックされたらリストにis-openを付け外しします。あわせてボタンの文言とaria-expandedも切り替えます。
const moreList = document.querySelector('.js-more-list');
const moreButton = document.querySelector('.js-more-button');
moreButton.addEventListener('click', () => {
moreList.classList.toggle('is-open');
const isOpen = moreList.classList.contains('is-open');
moreButton.textContent = isOpen ? '閉じる' : 'もっと見る';
moreButton.setAttribute('aria-expanded', String(isOpen));
});
完成コード
ここまでのHTML、CSS、JavaScriptを組み合わせると、クリックで表示範囲を切り替える基本形ができます。
<ul id="moreList" class="more-list js-more-list">
<li class="more-list__item">記事タイトル 01</li>
<li class="more-list__item">記事タイトル 02</li>
<li class="more-list__item">記事タイトル 03</li>
<li class="more-list__item more-list__item--hidden">記事タイトル 04</li>
<li class="more-list__item more-list__item--hidden">記事タイトル 05</li>
<li class="more-list__item more-list__item--hidden">記事タイトル 06</li>
</ul>
<button
class="more-button js-more-button"
type="button"
aria-expanded="false"
aria-controls="moreList"
>
もっと見る
</button>
.more-list__item--hidden {
display: none;
}
.more-list.is-open .more-list__item--hidden {
display: list-item;
}
.more-button {
border: 0;
border-radius: 999px;
background: #2563EB;
color: #fff;
padding: 12px 20px;
font-weight: 700;
}
const moreList = document.querySelector('.js-more-list');
const moreButton = document.querySelector('.js-more-button');
if (moreList && moreButton) {
moreButton.addEventListener('click', () => {
moreList.classList.toggle('is-open');
const isOpen = moreList.classList.contains('is-open');
moreButton.textContent = isOpen ? '閉じる' : 'もっと見る';
moreButton.setAttribute('aria-expanded', String(isOpen));
});
}
最低限の考え方
大事なのは、JavaScriptで直接displayを書き換えすぎないことです。状態を表すクラスを付け、CSSで見た目を決めると、後からアニメーションやレイアウトを変更しやすくなります。
案件では「最初に何件見せるか」「一度開いたら閉じられるようにするか」「ボタンを消すか」を先に決めておくと、実装の迷いが減ります。
実際に触ってみよう
完成コードは下のCodePenでも確認できます。HTML、CSS、JavaScriptを切り替えながら、ボタンを押したときにどこが変わるのか見てみてください。
See the Pen Web制作JS|もっと見るボタン|基本サンプル by WebToolGen (@webtoolgen) on CodePen.
コードの意味を1行ずつ見る
document.querySelector('.js-more-list')
document.querySelector('.js-more-list')は、HTMLの中から最初に見つかった.js-more-listを取得します。CSSセレクタと同じ書き方で指定できるので、HTML/CSSに慣れている人にもつながりやすい書き方です。
ここで取得しているのは、開閉したいリスト全体です。あとでこのリストにis-openを付け外しして、CSS側の表示状態を切り替えます。
document.querySelector('.js-more-button')
こちらはクリックされるボタンを取得しています。リストとボタンを別々に取得しておくことで、「クリックされたらリストを開く」という関係をJavaScriptで作れるようになります。
js-で始まるクラスは、JavaScriptから探すための目印として使っています。見た目を変えるためのクラスと分けておくと、後からCSSを変更してもJSが壊れにくくなります。
addEventListener('click', ...)
addEventListener('click', ...)は、「クリックされたら、この処理を実行してね」と登録するための書き方です。
clickの部分を変えるとどうなる?
clickを別のイベント名に変えると、反応するきっかけも変わります。例えば入力欄ならinput、キーボード操作ならkeydownなどを使います。
classList.toggle('is-open')
classList.toggle('is-open')は、指定したクラスがなければ付け、すでにあれば外します。今回なら、閉じているときはis-openが付き、開いているときにもう一度押すとis-openが外れます。
JavaScriptで直接「4件目を表示する」と命令するのではなく、HTMLに状態を表すクラスを付けるだけにしているのがポイントです。実際にどう見せるかはCSSが担当します。
classList.contains('is-open')
classList.contains('is-open')は、その要素がis-openを持っているかどうかを調べます。持っていればtrue、持っていなければfalseです。
この結果をisOpenという変数に入れて、ボタンの文言やaria-expandedの切り替えに使っています。
textContent
textContentは、要素の中のテキストを読み書きするためのプロパティです。今回は、開いているときは「閉じる」、閉じているときは「もっと見る」に変えています。
moreButton.textContent = isOpen ? '閉じる' : 'もっと見る';
この書き方は三項演算子と呼ばれます。短く書けて便利ですが、読みづらい場合はif文で書いても大丈夫です。
if (isOpen) {
moreButton.textContent = '閉じる';
} else {
moreButton.textContent = 'もっと見る';
}
setAttribute('aria-expanded',
String(isOpen))
aria-expandedは、そのボタンが操作する領域が開いているかどうかを伝えるための属性です。画面上の見た目だけでなく、支援技術にも状態が伝わるように更新します。
setAttributeで属性値を変更できます。isOpenは真偽値なので、String(isOpen)で"true"または"false"の文字列にしてから入れています。
よくある失敗と解決法
id名・class名が違う
HTMLではjs-more-buttonなのに、JSでjs-more-btnと書くと取得できません。まず名前を揃えましょう。
// HTML
class="js-more-button"
// JS
document.querySelector('.js-more-btn');
セレクタの記号を忘れている
クラスを探すときは先頭に.が必要です。querySelector('js-more-button')ではなくquerySelector('.js-more-button')です。
// NG
document.querySelector('js-more-button');
// OK
document.querySelector('.js-more-button');
CSS側の指定が足りない
is-openは付いているのに見た目が変わらない場合、CSSの開いた状態の指定を確認します。JSが動いていても、CSSがなければ見た目は変わりません。
.more-list.is-open .more-list__item--hidden {
display: list-item;
}
JSファイルの読み込み位置が悪い
HTMLより先にJSが実行されると、要素がまだ存在せず取得できないことがあります。まずは</body>直前で読み込みましょう。
<script src="script.js"></script>
</body>
注意:本番では対象要素が存在しないページでも同じJSを読み込むことがあります。必要に応じて、要素があるか確認してから処理を書くと安全です。
カスタマイズして使ってみよう
基本形が分かれば、案件に合わせた調整もしやすくなります。例えば「開いたらボタンを非表示にする」「最初は6件、追加で6件ずつ表示する」「スクロール位置を少し戻す」といった変更が考えられます。
ボタンの文言を変える
サイトの雰囲気に合わせて、「もっと見る」を「続きを読む」「一覧を開く」「すべて表示」などに変えても構いません。閉じる動きが不要なら、開いたあとにボタンを消す設計もあります。
moreButton.textContent = isOpen ? '閉じる' : '続きを読む';
見た目を変える
ボタンの色、角丸、余白はCSS側で変更します。JavaScriptは状態を切り替えるだけにしておくと、デザイン調整のたびにJSを触らずに済みます。
.more-button {
background: #0F172A;
border-radius: 8px;
padding: 14px 24px;
}
フワッと表示させたい場合
display: none;とdisplay: block;の切り替えはシンプルですが、そのままではアニメーションしにくい性質があります。フワッと表示したい場合は、opacityやmax-heightを使う方法を検討します。
.more-list__item--hidden {
max-height: 0;
opacity: 0;
overflow: hidden;
transition: max-height 0.3s ease, opacity 0.3s ease;
}
.more-list.is-open .more-list__item--hidden {
max-height: 80px;
opacity: 1;
}
max-heightは中身の高さに合わせて調整が必要です。記事カードやFAQのように高さが大きく変わるUIでは、無理にアニメーションさせない判断も実務では自然です。
ボタンを消すパターン
1回だけ続きを表示できればよい場合は、開いたあとにボタンへhiddenを付ける方法もあります。
JSを使わない方法
開閉UIはJavaScriptだけが正解ではありません。説明文やFAQのようにシンプルな開閉なら、HTMLのdetailsとsummaryで十分なこともあります。
<details>
<summary>もっと見る</summary>
<p>ここに追加で見せたい内容を入れます。</p>
</details>
details {
border: 1px solid #E5EAF0;
border-radius: 8px;
padding: 16px;
}
summary {
color: #2563EB;
cursor: pointer;
font-weight: 700;
}
選び方:自由なデザインや複雑な状態管理が必要ならJavaScript、シンプルな開閉だけならHTML標準機能も候補に入れる、くらいで考えると実務で選びやすくなります。
JavaScriptを書くこと自体が目的ではありません。目的は、ユーザーにとって分かりやすく、運用する人にとって直しやすいUIを作ることです。状況に合わせて、JavaScript、CSS、HTML標準機能を選べるようになると、実装の引き出しがぐっと増えていきます。
次回は複数対応へ
今回は1つのボタンと1つのリストを扱いました。次回はFAQアコーディオンのように、同じ開閉UIが複数ある場合の書き方を見ていきます。