モーダルは、表示内容に従うか、モーダルウィンドウを閉じる必要のある強制力が強めのUIですが、特定のタスクに集中できる環境を提供することが可能なUIです。
この記事は、そんなモーダルに記事のh2
・h3
の見出しタグを取得して、表示させるスニペットについて解説しています。
極力プラグインを使いたくない方や、記事の目次をメインのエリア以外に表示させたい方は、この記事を参考にしてみてください。
目次
デザインと表示のサンプル
早速、デザインのサンプルです。以下のボタンか、このページの右下に固定表示させているメニューアイコンをクリックしてみてください。
クリックで目次のモーダル が表示されます。
実装の手順と方法
実装の手順と方法について解説していきます。全部で4つのSTEPで完了です。
この記事のスニペットは、jQuery本体の組み込みが必要です。ない場合、jQuery本体を設置します。
固定のメニューアイコンと、モーダルのHTMLをページ内に設置します。
表示されるオブジェクトの見た目を整える為、CSSをコピペします。
モーダルや、目次生成などを行うjQueryをコピペします。
これで完了です。ここからは、それぞれ詳細の手順について解説していきます。
jQuery本体の設置
この記事のスニペットの利用は、jQuery本体の組み込みが必要です。
jQueryは既に<head>〜</head>
の中で読み込まれていれば問題ありませんが、ない場合は以下の記事を参考にして、jQuery本体をHTMLファイルに書き込みましょう。
関連記事 jQueryのインストール方法
HTMLを設置
次に、モーダルを表示させるページのHTMLファイルへ、以下のコードをコピペします。
場所は、<body>〜</body>
の中ならどこでも大丈夫ですが、モーダル を表示させるメニューボタンを下部に固定表示させるので、下の方がいいかもしれません。
コードを表示する
<div class="modaltoc">
<a class="js-modal-open" href=""><i class="fas fa-list-ul"></i></a>
</div>
<div class="modal js-modal" style="display: none;">
<div class="modal__bg js-modal-close"></div>
<div class="modal__content">
<a class="modal__closebutton js-modal-close"><i class="far fa-times-circle"></i></a>
<dl id="index">
<dt>目次</dt>
</dl>
</div><!--modal__inner-->
</div><!--modal-->
CSSをコピペ
次に、CSSをコピペします。
このコードで見た目を整えます。全体の色味は、当サイトの色に合わせてるので、好みに応じて変更ください。
コードを表示する
/* modal */
.modal{
display: none;
height: 100vh;
position: fixed;
top: 0;
width: 100%;
}
.modal__bg {
background: rgba(0,0,0,0.8);
height: 100vh;
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 100;
}
.modal__content {
background: #e5f2ff;
left: 50%;
padding: 25px 30px;
position: fixed;
top: 50%;
transform: translate(-50%,-50%);
width: 60%;
z-index: 100;
border-radius: 3px;
}
a.modal__closebutton.js-modal-close {
position: absolute;
top: -10px;
right: -10px;
}
a.modal__closebutton.js-modal-close i {
font-size: 2.3rem;
padding: 3px;
background: #FFF;
border-radius: 50px;
}
/* toc */
dl#index {
position: relative;
width: 100% !important;
border-top: solid 5px;
font-size: 0.95em;
background: #f9f9f9;
box-shadow: 0 1.5px 2.4px rgb(0 0 0 / 15%);
border-color: #6bb6ff;
margin: 20px auto 30px;
box-sizing: border-box;
padding: 25px 32px;
display: table;
min-width: 68%;
counter-reset: li;
}
dl#index dt {
font-weight: bold;
font-size: 118%;
padding: 0;
color: #6bb6ff;
}
dl#index dt:before {
font-family: "Font Awesome 5 Free" !important;
font-weight: 900;
background-color: #6bb6ff;
position: relative;
display: inline-block;
margin-right: 8px;
border-radius: 50%;
vertical-align: baseline;
speak: none;
-webkit-font-smoothing: antialiased;
color: #fff;
content: "\f0ca";
width: 50px;
height: 50px;
font-size: 20px;
text-align: center;
line-height: 50px;
}
dl#index dt {
padding: 0 0 20px;
margin: 0 0 20px;
border-bottom: 1px solid rgba(0,0,0,.1);
list-style: none;
}
dd.lv_h2 {
position: relative;
margin: 0;
}
dd.lv_h2 a {
position: relative;
text-decoration: none;
display: inline-block;
line-height: 1.6;
padding: 3px 0;
margin: 5px 0;
transition: all .3s ease;
font-size: 1.05rem;
font-weight: bold;
margin-left: 42px;
color: #5f7b96;
}
dd.lv_h2:before {
content: '';
display: inline-block;
vertical-align: bottom;
width: 32px;
height: 32px;
margin-right: 7px;
border-radius: 16px;
background-color: #6bb6ff;
position: absolute;
top: 5px;
left: 0;
}
dd.lv_h2:after {
counter-increment: li;
content: counter(li);
width: 32px;
line-height: 32px;
font-family: 'Avenir Next', 'Helvetica Neue', Arial, 'Meiryo','Yu Gothic', san-serif;
font-weight: 400;
text-align: center;
color: #fff;
position: absolute;
top: 5px;
left: 0;
}
dd.lv_h2 a:hover {
text-decoration: none;
box-shadow: 0 2px;
}
dd.lv_h3 {
margin: 0;
font-size: 0.95em;
font-weight: normal;
}
dd.lv_h3 a {
position: relative;
font-size: 94%;
font-weight: normal;
text-decoration: none;
display: inline-block;
line-height: 1.6;
padding: 3px 0;
margin: 5px 0;
transition: all .3s ease;
margin-left: 40px;
text-decoration: none;
color: #5f7b96;
}
dd.lv_h3 a:before {
position: relative;
content: '\2023';
display: inline-block;
width: 14px;
height: 28px;
line-height: 28px;
font-size: 40px;
color: #c8e4ff;
vertical-align: middle;
margin-right: 7px;
}
dd.lv_h3 a:hover {
text-decoration: none;
box-shadow: 0 2px;
padding-right: 4px;
}
.modaltoc {
background: #5ba9f7;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: fixed;
bottom: 90px;
right: 18px;
z-index: 90;
border-radius: 50px;
opacity: 0.6;
}
.modaltoc:hover {
opacity: 0.8;
}
.modaltoc i {
width: 54px;
height: 54px;
line-height: 54px;
text-align: center;
font-size: 1.6rem;
color: #FFF;
}
dl#index::-webkit-scrollbar {
width: 10px;
}
dl#index::-webkit-scrollbar-track {
background: #fff;
border-radius: 0px;
box-shadow: inset 0 0 1px #999;
}
dl#index::-webkit-scrollbar-thumb {
background: #FDEE7490;
border-radius: 0px;
box-shadow: none;
}
dl#index {
counter-reset: li;
height: 500px;
overflow-y: scroll;
border: solid 2px #063c71;
margin: 0;
background: #FFF;
padding: 20px 25px;
}
@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
.modal__content {
width: 92%;
padding: 10px 10px;
background: #d9ecff;
}
a.modal__closebutton.js-modal-close {
top: -30px;
}
dl#index {
height: 450px;
overflow-y: scroll;
background: #FFF;
padding: 10px 15px;
border: solid 2px #063c71;
margin: 0;
}
dl#index dt {
padding: 0 0 10px;
margin: 0 0 10px;
}
.modaltoc {
bottom: 80px;
right: 10px;
}
}
jQueryをコピペ
最後に、jQueryをコピペします。以下のコードを、<body>〜</body>
をのクロージングタグ直前に記述して完了です。
コードを表示する
// toc
$(function(){
var countId = 1
$("#content h2,#content h3").each(function(){
var ttl = $(this).text();
var lv = this.nodeName.toLowerCase();
this.id = 'ttl-' + countId;
countId ++;
$("#index").append('<dd class="lv_'+lv+'"><a href="#'+this.id+'" class="js-modal-close">'+ttl+'</a></dd>');
});
});
// modal
$(function(){
$('.js-modal-open').on('click',function(){
$('.js-modal').fadeIn();
return false;
});
$('.js-modal-close').on('click',function(){
$('.js-modal').fadeOut();
return false;
});
});
//スクロールしたら目次
jQuery(function() {
var pagetop = $('.modaltoc');
pagetop.hide();
$(window).scroll(function () {
if ($(this).scrollTop() > 700) { //700pxスクロールしたら表示
pagetop.fadeIn();
} else {
pagetop.fadeOut();
}
});
pagetop.click(function () {
$('body,html').animate({
scrollTop: 0
}, 100); //0.1秒かけてトップへ移動
return false;
});
});
コピペ用コード一式
スニペットのまとめ的な一式です。全部のコード内容は、上述のコードと同じです。
コードを表示する
<div class="modaltoc">
<a class="js-modal-open" href=""><i class="fas fa-list-ul"></i></a>
</div>
<div class="modal js-modal" style="display: none;">
<div class="modal__bg js-modal-close"></div>
<div class="modal__content">
<a class="modal__closebutton js-modal-close"><i class="far fa-times-circle"></i></a>
<dl id="index">
<dt>目次</dt>
</dl>
</div><!--modal__inner-->
</div><!--modal-->
/* modal */
.modal{
display: none;
height: 100vh;
position: fixed;
top: 0;
width: 100%;
}
.modal__bg {
background: rgba(0,0,0,0.8);
height: 100vh;
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 100;
}
.modal__content {
background: #e5f2ff;
left: 50%;
padding: 25px 30px;
position: fixed;
top: 50%;
transform: translate(-50%,-50%);
width: 60%;
z-index: 100;
border-radius: 3px;
}
a.modal__closebutton.js-modal-close {
position: absolute;
top: -10px;
right: -10px;
}
a.modal__closebutton.js-modal-close i {
font-size: 2.3rem;
padding: 3px;
background: #FFF;
border-radius: 50px;
}
/* toc */
dl#index {
position: relative;
width: 100% !important;
border-top: solid 5px;
font-size: 0.95em;
background: #f9f9f9;
box-shadow: 0 1.5px 2.4px rgb(0 0 0 / 15%);
border-color: #6bb6ff;
margin: 20px auto 30px;
box-sizing: border-box;
padding: 25px 32px;
display: table;
min-width: 68%;
counter-reset: li;
}
dl#index dt {
font-weight: bold;
font-size: 118%;
padding: 0;
color: #6bb6ff;
}
dl#index dt:before {
font-family: "Font Awesome 5 Free" !important;
font-weight: 900;
background-color: #6bb6ff;
position: relative;
display: inline-block;
margin-right: 8px;
border-radius: 50%;
vertical-align: baseline;
speak: none;
-webkit-font-smoothing: antialiased;
color: #fff;
content: "\f0ca";
width: 50px;
height: 50px;
font-size: 20px;
text-align: center;
line-height: 50px;
}
dl#index dt {
padding: 0 0 20px;
margin: 0 0 20px;
border-bottom: 1px solid rgba(0,0,0,.1);
list-style: none;
}
dd.lv_h2 {
position: relative;
margin: 0;
}
dd.lv_h2 a {
position: relative;
text-decoration: none;
display: inline-block;
line-height: 1.6;
padding: 3px 0;
margin: 5px 0;
transition: all .3s ease;
font-size: 1.05rem;
font-weight: bold;
margin-left: 42px;
color: #5f7b96;
}
dd.lv_h2:before {
content: '';
display: inline-block;
vertical-align: bottom;
width: 32px;
height: 32px;
margin-right: 7px;
border-radius: 16px;
background-color: #6bb6ff;
position: absolute;
top: 5px;
left: 0;
}
dd.lv_h2:after {
counter-increment: li;
content: counter(li);
width: 32px;
line-height: 32px;
font-family: 'Avenir Next', 'Helvetica Neue', Arial, 'Meiryo','Yu Gothic', san-serif;
font-weight: 400;
text-align: center;
color: #fff;
position: absolute;
top: 5px;
left: 0;
}
dd.lv_h2 a:hover {
text-decoration: none;
box-shadow: 0 2px;
}
dd.lv_h3 {
margin: 0;
font-size: 0.95em;
font-weight: normal;
}
dd.lv_h3 a {
position: relative;
font-size: 94%;
font-weight: normal;
text-decoration: none;
display: inline-block;
line-height: 1.6;
padding: 3px 0;
margin: 5px 0;
transition: all .3s ease;
margin-left: 40px;
text-decoration: none;
color: #5f7b96;
}
dd.lv_h3 a:before {
position: relative;
content: '\2023';
display: inline-block;
width: 14px;
height: 28px;
line-height: 28px;
font-size: 40px;
color: #c8e4ff;
vertical-align: middle;
margin-right: 7px;
}
dd.lv_h3 a:hover {
text-decoration: none;
box-shadow: 0 2px;
padding-right: 4px;
}
.modaltoc {
background: #5ba9f7;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: fixed;
bottom: 90px;
right: 18px;
z-index: 90;
border-radius: 50px;
opacity: 0.6;
}
.modaltoc:hover {
opacity: 0.8;
}
.modaltoc i {
width: 54px;
height: 54px;
line-height: 54px;
text-align: center;
font-size: 1.6rem;
color: #FFF;
}
dl#index::-webkit-scrollbar {
width: 10px;
}
dl#index::-webkit-scrollbar-track {
background: #fff;
border-radius: 0px;
box-shadow: inset 0 0 1px #999;
}
dl#index::-webkit-scrollbar-thumb {
background: #FDEE7490;
border-radius: 0px;
box-shadow: none;
}
dl#index {
counter-reset: li;
height: 500px;
overflow-y: scroll;
border: solid 2px #063c71;
margin: 0;
background: #FFF;
padding: 20px 25px;
}
@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
.modal__content {
width: 92%;
padding: 10px 10px;
background: #d9ecff;
}
a.modal__closebutton.js-modal-close {
top: -30px;
}
dl#index {
height: 450px;
overflow-y: scroll;
background: #FFF;
padding: 10px 15px;
border: solid 2px #063c71;
margin: 0;
}
dl#index dt {
padding: 0 0 10px;
margin: 0 0 10px;
}
.modaltoc {
bottom: 80px;
right: 10px;
}
}
// toc
$(function(){
var countId = 1
$("#content h2,#content h3").each(function(){
var ttl = $(this).text();
var lv = this.nodeName.toLowerCase();
this.id = 'ttl-' + countId;
countId ++;
$("#index").append('<dd class="lv_'+lv+'"><a href="#'+this.id+'" class="js-modal-close">'+ttl+'</a></dd>');
});
});
// modal
$(function(){
$('.js-modal-open').on('click',function(){
$('.js-modal').fadeIn();
return false;
});
$('.js-modal-close').on('click',function(){
$('.js-modal').fadeOut();
return false;
});
});
//スクロールしたら目次
jQuery(function() {
var pagetop = $('.modaltoc');
pagetop.hide();
$(window).scroll(function () {
if ($(this).scrollTop() > 700) { //700pxスクロールしたら表示
pagetop.fadeIn();
} else {
pagetop.fadeOut();
}
});
pagetop.click(function () {
$('body,html').animate({
scrollTop: 0
}, 100); //0.1秒かけてトップへ移動
return false;
});
});
ざっくりとしたコードの解説
コピペ用のコードのざっくりとした解説です。
HTML:modal
のdisplay: none;
display: none;
モーダルの表示・非表示はjQueryで制御します。その為、classのmodal js-modal
には、 style="display: none;"
を直接書き込み、一番最初は非表示にしておきます。
<div class="modal js-modal" style="display: none;">
こうすることで、ページロードが完了しても勝手にモーダルが表示されません。
jQuery:目次とモーダルなど
使っているjQueryは、主に3つです。
- 目次生成
- 下にスクロールすると表示
- モーダル
目次作成のjQueryは、指定した h2〜h3
タグを取得して、目次を作ってくれる仕様です。
このスニペットでは、$("#content h2,#content h3")
の見出しタグを取得して、モーダルウィンドウの中に設置した<dl id="index"> <dt>目次</dt> </dl>
に、その見出しのテキストを出力させます。
// toc
$(function(){
var countId = 1
$("#content h2,#content h3").each(function(){
var ttl = $(this).text();
var lv = this.nodeName.toLowerCase();
this.id = 'ttl-' + countId;
countId ++;
$("#index").append('<dd class="lv_'+lv+'"><a href="#'+this.id+'" class="js-modal-close">'+ttl+'</a></dd>');
});
});
そして、目次のa
タグに js-modal-close
をつけて、クリックした時に、モーダルが非表示になるようにしています。
静的なページでもなんでも出力できるので、便利なjQueryです。
右下のメニューアイコンには、modaltoc
のclassを付けて、ページを700px下にスクロールすると表示させて、トップへ戻りボタンがスッと消える仕様です。
//スクロールしたら目次
jQuery(function() {
var pagetop = $('.modaltoc');
pagetop.hide();
$(window).scroll(function () {
if ($(this).scrollTop() > 700) { //700pxスクロールしたら表示
pagetop.fadeIn();
} else {
pagetop.fadeOut();
}
});
pagetop.click(function () {
$('body,html').animate({
scrollTop: 0
}, 100); //0.1秒かけてトップへ移動
return false;
});
});
モーダルのjQueryは、シンプルです。
a
タグのclass js-modal-open
をクリックしたら、fadeIn
でモーダルウィンドウを表示します。そして、js-modal-close
のクリックで、 fadeOut
しながら非表示になります。
// modal
$(function(){
$('.js-modal-open').on('click',function(){
$('.js-modal').fadeIn();
return false;
});
$('.js-modal-close').on('click',function(){
$('.js-modal').fadeOut();
return false;
});
});