以前作った「ボタンをクリックしてコンテンツを展開」するスニペットでは、展開した後に任意で閉じることはできない使用でしたが、この記事ではもっと見る・閉じるを任意でできるようにしてみます。
JavaScriptの.previousElementSiblingでボタンをクリックしてコンテンツを展開長文のコンテンツにピッタリなスニペットです。
是非、参考にしてみてください。
.scrollHeight
JavaScriptの .scrollHeight
は、あふれて画面上に表示されない部分を含めた、要素の中身の高さの寸法を測るプロパティです。
element.style.height = content.scrollHeight + 'px';
.scrollHeight
は、垂直スクロールバーを使用せずにすべてのコンテンツをビューポート内に収めるために要素に必要な最小の高さに等しくなり、値を返します。
.scrollHeight
の詳しくは、おなじみ「mdn web doc」をご覧ください。
もっと見る・閉じるで開閉するサンプル
早速サンプルです。2つのカラム落ちさせたレイアウトで、ブロックそれぞれの下部に「もっと見る」ボタンが設置されています。
ボタンをクリックすると下部に展開しながらブロックの文章が全て表示され、表示後は「閉じる」をクリックすると、また非表示になります。
日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は国民の厳粛な信託によるものであって、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基づくものである。われらはこれに反する一切の憲法、法令及び詔勅を排除する。
日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風。
メディア系のサイトでよく見る仕様ですね。
実装の手順と方法
コードの解説の前に、実装の手順と方法について解説します。
まずはじめに、HTMLを記述します。
<div id="readMoreBlock">
<div class="readMoreInner">
<div class="readMoreContainer">
<p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は国民の厳粛な信託によるものであって、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基づくものである。われらはこれに反する一切の憲法、法令及び詔勅を排除する。</p>
<p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。</p>
</div>
<button class="readMoreBtn">もっと見る</button>
</div>
<div class="readMoreInner">
<div class="readMoreContainer">
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。</p>
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風。</p>
</div>
<button class="readMoreBtn">もっと見る</button>
</div>
</div>
次にJavaScriptのコードをページに記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
const readmore = document.querySelectorAll('.readMoreInner');
Array.from(readmore).forEach(function(more){
const btn = more.querySelector('.readMoreBtn');
const content = more.querySelector('.readMoreContainer');
// ボタンクリックでイベント処理
btn.addEventListener('click', () => {
if(!content.classList.contains('show')){
content.style.maxHeight = content.scrollHeight + 'px';
content.classList.add('show');
btn.innerText = '閉じる';
} else {
content.style.maxHeight = '250px';
content.classList.remove('show');
btn.innerText = 'もっと見る';
}
});
});
最後に、CSSを記述して見た目を整えて完了です。
#readMoreBlock {
display: flex;
flex-wrap: wrap;
width: 100%;
margin: 0 auto;
padding: 0;
gap: 35px;
}
.readMoreInner {
width: 100%;
margin: 0 auto;
padding: 25px 30px;
border-radius: 3px;
box-sizing: border-box;
background: #FFF;
}
.readMoreContainer {
position: relative;
height: auto;
max-height: 250px;
overflow: hidden;
transition: max-height 0.6s;
}
.readMoreContainer::after {
content: "";
position: absolute;
top: 0;
left: 0;
z-index: 0;
display: block;
width: 100%;
height: 100%;
transition: 1s;
background: linear-gradient(to bottom, transparent 40%, #ffffff 100%);
pointer-events: none;
}
.readMoreContainer.show:after {
z-index: -1;
opacity: 0;
}
.readMoreBtn {
display: block;
margin: 0 auto;
padding: 8px 40px;
border: 0;
color: #ffffff;
background-color: #00c2bc;
cursor: pointer;
}
.readMoreContainer p:last-child {
margin-bottom: 10px;
}
これで完成です!
ざっくりとしたコードの解説
コードはHTML・JavaScript・CSSの3種です。順に解説していきます。
HTML
HTMLは、id名「readMoreBlock」の要素が親要素で、「readMoreInner」が各ブロックで、その中にコンテナの「readMoreContainer」に p
タグで文字を格納しています。
<div id="readMoreBlock">
<div class="readMoreInner">
<div class="readMoreContainer">
<p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は国民の厳粛な信託によるものであって、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基づくものである。われらはこれに反する一切の憲法、法令及び詔勅を排除する。</p>
<p>日本国民は正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民と協和による成果と、わが国全土にわたって自由のもたらす恵沢を確保し、政府の行為によって再び戦争の惨禍が起こることのないようにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。</p>
</div>
<button class="readMoreBtn">もっと見る</button>
</div>
<div class="readMoreInner">
<div class="readMoreContainer">
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。</p>
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。あのイーハトーヴォのすきとおった風。</p>
</div>
<button class="readMoreBtn">もっと見る</button>
</div>
</div>
「readMoreBtn」のclassのつく button
タグが「コンテンツをもっと見る・閉じる」のトリガーになる要素です。
JavaScript
JavaScriptは、冒頭でボタンやコンテンツを格納している要素をそれぞれ取得して、「もっと見る・閉じる」ボタンがクリックされると処理を行う .addEventListener
のクリックを使用します。
const readmore = document.querySelectorAll('.readMoreInner');
Array.from(readmore).forEach(function(more){
const btn = more.querySelector('.readMoreBtn');
const content = more.querySelector('.readMoreContainer');
// ボタンクリックでイベント処理
btn.addEventListener('click', () => {
if(!content.classList.contains('show')){
content.style.maxHeight = content.scrollHeight + 'px';
content.classList.add('show');
btn.innerText = '閉じる';
} else {
content.style.maxHeight = '250px';
content.classList.remove('show');
btn.innerText = 'もっと見る';
}
});
});
クリック後は、if
で分岐させながら、コンテンツ部分の高さの調節とCSSクラス名の追加・削除を行い、コンテンツの展開を制御しています。
CSS
CSSは、親要素にあたるid名「readMoreBlock」の要素にflexboxで並べます。
そして、その子要素の「readMoreInner」の中にコンテンツを設置して、「readMoreContainer」のclass名を持つ要素に after
の疑似要素を使って非表示状態で覆い隠すオーバーレイを作ります。
#readMoreBlock {
display: flex;
flex-wrap: wrap;
width: 100%;
margin: 0 auto;
padding: 0;
gap: 35px;
}
.readMoreInner {
width: 100%;
margin: 0 auto;
padding: 25px 30px;
border-radius: 3px;
box-sizing: border-box;
background: #FFF;
}
.readMoreContainer {
position: relative;
height: auto;
max-height: 250px;
overflow: hidden;
transition: max-height 0.6s;
}
.readMoreContainer::after {
content: "";
position: absolute;
top: 0;
left: 0;
z-index: 0;
display: block;
width: 100%;
height: 100%;
transition: 1s;
background: linear-gradient(to bottom, transparent 40%, #ffffff 100%);
pointer-events: none;
}
.readMoreContainer.show:after {
z-index: -1;
opacity: 0;
}
.readMoreBtn {
display: block;
margin: 0 auto;
padding: 8px 40px;
border: 0;
color: #ffffff;
background-color: #00c2bc;
cursor: pointer;
}
.readMoreContainer p:last-child {
margin-bottom: 10px;
}
ボタンのデザインであてているスタイルのコードは、上記に含まれません。ので、上記のコードにボタン用のコードを別途追記するようにしてください。
さいごに
いかがでしたでしょうか?
この記事のサンプル程度の文字数なら「もっと見る」クリックでコンテンツを展開しても問題ありませんが、文字数が多い場合、下に大きく展開してしまうことで「閉じる」のボタンが大きく離れてしまい、使い勝手が悪くなります。
ので、文字数には気をつけながら、参考にして使ってみてください。