今回実装するセクションはこちらです!
管理画面で設定可能な項目は以下になります
- ブロック単位で画像の増減可能
- 見出しの編集
- 上下の余白(PC、SP個別に)
モーダルセクションのコード
早速ですが今回のコードはこちらです
LIquid(c_modal.liquid)
{{ 'c_modal.css' | asset_url | stylesheet_tag }}
{%- style -%}
.section-{{ section.id }}-padding {
padding-top: {{ section.settings.padding_top }}px;
padding-bottom: {{ section.settings.padding_bottom }}px;
}
@media screen and (min-width: 750px) {
.section-{{ section.id }}-padding {
padding-top: {{ section.settings.padding_top-pc }}px;
padding-bottom: {{ section.settings.padding_bottom-pc }}px;
}
}
{%- endstyle -%}
<div class="c_modal page-width section-{{ section.id }}-padding">
<h2 class="section-title">{{ section.settings.title }}</h2>
<ul class="c_modal__lists">
{% for block in section.blocks %}
<li class="c_modal__list js-modal">
<div class="c_modal__inner">
<div class="c_modal__thumbnail">
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
</div>
<h3 class="c_modal__title">{{ block.settings.title }}</h3>
</div>
<div class="c_modal__image--wrapper js-modal__content">
<div class="c_modal__image">
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const modalTrigger = document.querySelectorAll(".js-modal");
modalTrigger.forEach(function (element, index) {
const modalContent = element.querySelector(".js-modal__content");
element.addEventListener("click", function (el) {
modalContent.classList.toggle('is-open');
document.body.classList.toggle("no-scroll");
});
});
});
</script>
{% schema %}
{
"name": "モーダル",
"settings": [
{
"type": "text",
"id": "title",
"label": "見出し",
"default": "モーダル"
},
{
"type": "header",
"content": "上下の余白"
},
{
"type": "range",
"id": "padding_top-pc",
"min": 0,
"max": 100,
"step": 1,
"unit": "px",
"label": "上部の余白(pc)",
"default": 32
},
{
"type": "range",
"id": "padding_bottom-pc",
"min": 0,
"max": 100,
"step": 1,
"unit": "px",
"label": "下部の余白(PC)",
"default": 32
},
{
"type": "range",
"id": "padding_top",
"min": 0,
"max": 100,
"step": 1,
"unit": "px",
"label": "上部の余白",
"default": 32
},
{
"type": "range",
"id": "padding_bottom",
"min": 0,
"max": 100,
"step": 1,
"unit": "px",
"label": "下部の余白",
"default": 32
}
],
"blocks" : [
{
"type": "image",
"name": "画像",
"settings": [
{
"type": "image_picker",
"id": "image",
"label": "画像"
},
{
"type": "text",
"id": "title",
"label": "見出し"
}
]
}
],
"presets":[
{
"name" : "モーダル",
"category": "カスタムパーツ"
}
]
}
{% endschema %}
CSS(c_modal.css)
/* リセット */
.c_modal img {
width: 100%;
height: auto;
vertical-align: bottom;
}
.c_modal ul {
margin: 0;
padding: 0;
}
.c_modal li {
list-style: none;
}
.c_modal a {
text-decoration: none;
}
.no-scroll {
overflow: hidden;
}
.c_modal__lists {
display: flex;
gap: 16px
}
.c_modal__list {
width: calc(100% / 4 - 16px * 3 / 4)
}
/* モーダル */
.c_modal__image--wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgb(0, 0, 0, .8);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease;
}
.c_modal__image--wrapper.is-open {
display: block;
opacity: 1;
visibility: visible;
}
.c_modal__image {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
コードの解説
モーダルの部分のみ解説します
簡単に説明すると以下のロジックで制御しています
- js-modalクラスを持った要素をクリック
- クリックした要素にis-openクラスが付与される
- モーダル画像が表示される
ブロック単位で画像を出力
以下のコードがブロック単位で画像を表示しています
<div class="c_modal page-width section-{{ section.id }}-padding">
<h2 class="section-title">{{ section.settings.title }}</h2>
<ul class="c_modal__lists">
{% for block in section.blocks %}
<li class="c_modal__list js-modal">
<div class="c_modal__inner">
<div class="c_modal__thumbnail">
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
</div>
<h3 class="c_modal__title">{{ block.settings.title }}</h3>
</div>
<div class="c_modal__image--wrapper js-modal__content">
<div class="c_modal__image">
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const modalTrigger = document.querySelectorAll(".js-modal");
modalTrigger.forEach(function (element, index) {
const modalContent = element.querySelector(".js-modal__content");
element.addEventListener("click", function (el) {
modalContent.classList.toggle('is-open');
document.body.classList.toggle("no-scroll");
});
});
});
</script>
ブロックで画像を読み込んでいるのでfor文の中に書いていきます!
{% for block in section.blocks %}
<!-- ココに書いていく -->
{% endfor %}
block.settings.imageで画像が読み込めるのでimage_urlフィルターとimage_tagフィルターを使って画像を出力していきます!
※block.settings.imageはブロックで読み込んでいるので必ずfor文の中に書いてくださいね!
では次に画像の出力部分のについて解説します!
サムネイルとモーダルの画像は同じもの
①あらかじめ表示されている画像(サムネイル)のコード
<div class="c_modal__thumbnail">
<!-- サムネイル -->
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
</div>
②モーダルで出力される画像のコード
<div class="c_modal__image--wrapper js-modal__content">
<div class="c_modal__image">
<!-- モーダル -->
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
</div>
</div>
見比べてもらうとわかるんですが以下のコードは①と②で同じコードを書いています!
※正確にはサムネイルのwidth部分は1920よりも小さくて良いがわかりやすくする為同じにしてます
サムネイル画像とモーダル画像は同じ画像なので以下の同じコードになります!
{% if block.settings.image %}
{{ block.settings.image | image_url: width: 1920 | image_tag: alt: block.settings.image.alt, loading: "lazy" }}
{% endif %}
モーダル画像はあらかじめCSSで非表示に
.c_modal__image--wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgb(0, 0, 0, .8);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease;
}
.c_modal__image--wrapper.is-open {
display: block;
opacity: 1;
visibility: visible;
}
c_modal__image--wrapperをあらかじめ非表示にしておいて
is-openがつくと表示される仕組みです!
以下が非表示にしているコードです
opacity: 0;
visibility: hidden;
要素の非表示によく使われるdisplay:noneを使っていないのは
transitionが効かない為使っていません(フェードインで表示をしたいので)
モーダルのJavaScript
<script>
document.addEventListener("DOMContentLoaded", function () {
const modalTrigger = document.querySelectorAll(".js-modal");
modalTrigger.forEach(function (element, index) {
const modalContent = element.querySelector(".js-modal__content");
element.addEventListener("click", function (el) {
modalContent.classList.toggle('is-open');
document.body.classList.toggle("no-scroll");
});
});
});
</script>
①modalTrigger変数にjs-modalクラスを持った要素を格納
const modalTrigger = document.querySelectorAll(".js-modal");
②modalTrigger変数は配列になるのでforEachを使ってループを回す
modalTrigger.forEach(function (element, index) {});
③addEventListenerを使ってクリックイベントに対してクラスのつけ外しを実行
- クリックされた要素にis-openクラスをつけてモーダルを表示
- モーダル表示の際はスクロールされないようにno-scrollクラスをbodyタグに付与
element.addEventListener("click", function (el) {
modalContent.classList.toggle('is-open');
document.body.classList.toggle("no-scroll");
});
まとめ
今回のセクションはスキーマのブロックを使った実装になります
スキーマのブロックを使って構築すると何がいいかというと
サイト公開後、
画像を変更したい、順序を入れ替えたいってのはもちろんですが
画像増やしたい、もしくは減らしたいって要望があるかと思います
その度に毎回コード触るのは大変ですよね。。
こちらが全て管理画面でできるようになります!!!
便利ですよねー
ぜひ一度実装して見てください!