アクセシビリティのことも考えると、作成が難しいUIがモーダルです。Twitterなどでは「無理に自作せずライブラリに頼ったほうがいい」という声を見かけることが多くなりました。
そこで今回はかんたんにアクセシビリティ対応のモーダルウインドウが実装できる、jQuery非依存の超軽量ライブラリ「Micromodal.js」について詳しく解説します!
特徴やできること、動く仕組みや各オプション、動かない場合のトラブルシューティングなどを網羅的に紹介します。
Micromodal.jsを使ってみようかな…と考えていた方は必見!ぜひ最後までご覧くださいね。
※jQueryでモーダルUIを作る方法についてはこちらで解説してます。
>> 【jQuery】モーダルウィンドウの作り方を解説(コピペ可)
モーダルとは
モーダルウィンドウとは、操作が完了するまで親ウィンドウへの操作を受け付けなくさせるタイプのウィンドウのことである。
モーダルウィンドウが表示されると、その中で指定された操作を完了するかキャンセルするかして、そのウィンドウを閉じない限り、親ウィンドウ側に対する操作ができないようになる。このため、モーダルウィンドウはユーザーに特定の操作をさせたり、確認を促したりといった目的で用いられることが多い。
Weblio 辞書 > コンピュータ > IT用語辞典 > モーダルウィンドウの意味・解説
下の例のように特定の要素をクリックやタップすると、別のコンテンツが浮かび上がって表示されるUI。一度は実装したことある方も多いと思います。
Micromodal.jsとは?
Micromodal.jsは、Webアクセビリティ(a11y)に対応したJavaScript製モーダルライブラリです。
身体的および技術的な制約によらず、Webサイトを使いやすく保つためのベストプラクティスです。
非営利団体W3C(World Wide Web Consortium)が行っているWAI(Web Accessibility Initiative)という取り組みの中で日々議論されています。
※ a11y:AccessibilityのAからYまでの間に11文字が挟まれているため、このように略します。
Micromodal.jsの主な特徴
主な特徴は以下のとおりです。
- ファイルサイズが軽量(1.9kb)
- WAI-ARIAガイドラインに準拠
- jQueryに依存しないピュアなJavaScriptで書かれている
- キーボード操作が可能
- 余計なスタイルがあたっていない
- MITライセンス
Micromodal.jsはWAI-ARIAガイドラインに準拠しているため、Webアクセビリティ(a11y)が保証されています。
CSSが付属されていないのでカスタマイズ性が高く、非常に使いやすいライブラリになっています。
使用する際は、MITライセンスのため無料で自由に利用できますが、著作権を放棄されたわけではありませんので注意しましょう。
MIT ライセンスとは、マサチューセッツ工科大学で作成された代表的なオープンソースライセンスで、無料で自由に使用できます。
使用条件として、再頒布時に著作権表示とライセンス表示を含めることと、作者や著作権者はいかなる責任も負わないことを定めています。
Micromodal.jsで出来ること
一部ですが、Micromodal.jsができることは以下のようなものがあります。
- 背景クリックするとモーダルを閉じる
esc
ボタンを押すとモーダルを閉じる- モーダルの
aria-hidden
属性の切り替え - モーダル外はTab移動の対象から外す
- モーダル内の最初のフォーカス可能な要素にフォーカスする
- モーダルが開いている間は後ろのコンテンツを操作出来ないように背景スクロールを固定する
- モーダルを閉じた時に、ダイアログを呼び出した要素にフォーカスを戻す
これだけの処理を手軽に実装できる点はとても便利ですね!
Micromodal.jsの読み込み
最初にインストール方法をご紹介します。
npmまたはyarnでインストールする場合は以下のコマンドを入力して下さい。
npm
npm install micromodal --save
yarn
yarn add micromodal --save
CDN
CDNの場合は<head>
の中、もしくは</body>
の前に以下を記述してください。
<script src="https://cdn.jsdelivr.net/npm/micromodal/dist/micromodal.min.js"></script>
Vue.jsの場合
Micromodal.jsをインストールしたあと、micromodal.js
のようなファイルを作成し、以下のようにimport文を記述してください。
import Vue from 'vue'
import * as MicroModal from 'micromodal'
Vue.use(MicroModal)
IE11対応
Micromodal.jsはES6記法で書かれており、IE 11 には定義されていないメソッドであるArray.from
とObject.assign
を使用しています。IE11で使用するにはES6のPolyfillを導入する必要があります。
以下がそれぞれのpolyfillを読み込むコードになります。Micromodal.jsを読み込むよりも前に記述して下さい。
<script src="https://polyfill.io/v3/polyfill.min.js?features=Array.from%2CObject.assign"></script>
<script script src="https://unpkg.com/micromodal/dist/micromodal.min.js"></script>
直接ソースコードに記述したい方は、公式のIssuesをご参照下さい。
Micromodal.jsを使う準備ができたところで、以下からは実際の使い方を解説していきます。
Micromodal.jsの使い方
基本的なHTML構造はこちらです。
<button data-micromodal-trigger="モーダルのid" role="button">モーダルを開く</button>
<div id="modal-1" class="modal" aria-hidden="true"> <!-- ① -->
<div class="overlay" tabindex="-1" data-micromodal-close> <!-- ② -->
<div role="dialog" aria-modal="true" aria-labelledby="modal-1-title"> <!-- ③ -->
<div role="document"><!-- ④ -->
<header>
<h2 id="modal-1-title">モーダルタイトル</h2>
<button aria-label="Close modal" data-micromodal-close></button><!-- ⑤ -->
</header>
<div id="modal-1-content">モーダルコンテンツ</div>
</div>
</div>
</div>
</div>
モーダルを開くボタン(data-micromodal-trigger)
<button data-micromodal-trigger="モーダルのid" role="button">モーダルを開く</button>
モーダルを開くトリガー要素(ボタンやリンク)に、data-micromodal-trigger
を付与し、値として対象のモーダルを指定します。
また、モーダルコンテンツの構造には以下の5つのポイントがあります。
- モーダル外側のコンテナ要素
- モーダルのオーバーレイ
- モーダルコンテンツ
- モーダルコンテンツのスクリーンリーダー対応
- モーダル内の閉じるボタン
①モーダル外側のコンテナ要素(aria-hidden=”true”)
<div id="modal-1" class="modal" aria-hidden="true"></div>
モーダルの最も外側のコンテナ要素です。固有のidとaria-hidden=”true”を付与します。
②モーダルのオーバーレイ(data-micromodal-close)
<div class="overlay" tabindex="-1" data-micromodal-close></div>
モーダルのオーバーレイとして機能する要素です。不要な場合は削除してください。data-micromodal-closeを付与することでモーダルを閉じるトリガー要素になります。
③モーダルコンテンツの独立性を主張(role=”dialog”)
<div role="dialog" aria-modal="true" aria-labelledby="modal-1-title"></div>
role=”dialog”は、モーダルのコンテンツがページの他の部分とは別のものであることをスクリーンリーダーなどの支援技術に知らせるために使用します。
④モーダルコンテンツのスクリーンリーダー対応(role=”document”)
<div role="document"><!-- ④ -->
<div id="modal-1-content">モーダルコンテンツ></div>
</div>
role=”document”はスクリーンリーダーなどの支援技術にモーダル内の文書コンテキストについて知らせるために使用します。
⑤モーダル内の閉じるボタン(data-micromodal-close)
すべてのボタンに、アクションを定義するaria-labelを付与します。閉じるボタンにはdata-micromodal-closeを忘れずに付与します。
<button aria-label="Close modal" data-micromodal-close></button>
コンテンツの構造はニーズに合わせて拡張することもできますので、カスタマイズの例として公式のサンプルコードもチェックしてみてください。
CSS
.modal{
display: none;
}
.modal.is-open {
display: block;
}
デフォルトのCSSはないので自由にスタイルを当てることが可能ですが、上のコードは最低限必要です。
本記事で紹介するコードは、公式サンプルのCSSを参考にしながらカスタマイズしています。
すべて掲載するのは長いため、上のリンク先からコピペして使えます。
JavaScript
モーダルの開閉をどのように制御するかでコードが変わります。
データ属性で制御する場合
データ属性の切り替えをフックとしてモーダルを制御する場合は、以下のコードを記載するだけでMicromodal.jsが実行されます。
MicroModal.init();
JavaScript内で制御する場合
Micromodal.jsには以下の2種類のメソッドが用意されており、JavaScript内で書いたプログラム上でモーダルの制御ができます。
//モーダルを開く
MicroModal.show('モーダルid');
//モーダルを閉じる
MicroModal.close('モーダルid');
モーダルの開閉をカスタマイズして使いたい場合に便利ですね!
オプションについて
Micromodal.jsはモーダルの挙動を制御するためのオプションが多数用意されています。
オプション名 | 設定値 | 初期値 | 説明 |
---|---|---|---|
onShow | function | モーダルが開いたときに、実行される関数を指定できます。 | |
onClose | function | モーダルが閉じたときに、実行される関数を指定できます。 | |
openTrigger | string | data-micromodal-trigger | モーダルを開くトリガー要素につけるカスタムデータ属性を指定できます。 |
closeTrigger | string | data-micromodal-close | モーダルを閉じるトリガー要素につけるカスタムデータ属性を指定できます。 |
openClass | string | is-open | モーダルが開くときに追加するclass名を指定できます。 |
disableScroll | boolean | false | モーダルが開いている間、ページスクロールを無効にします。 |
disableFocus | boolean | false | モーダルが開いたとき、モーダル内の最初のフォーカス可能な要素へのオートフォーカスを無効にします。 |
awaitOpenAnimation | boolean | false | CSSアニメーションが終了するまで、モーダル内要素のフォーカスを待ちます。 |
awaitCloseAnimation | boolean | false | CSSアニメーションが終わるのを待ってから、モーダル内要素を非表示にします。 |
debugMode | boolean | false | コンソールに表示される警告を抑制します。 |
オプションはオブジェクトを渡すことで指定できます。
指定しなくても動きますが、アクセシビリティのことを考えるとdisableScroll
は必須にしておくといいかもしれません。
MicroModal.init({
disableScroll: true,//モーダルが開いている間、ページスクロールを無効にします。
});
導入から実際に動かすところまで、とても手軽でしたね!
次からはMicromodal.jsの動く仕組みを図解を交えて解説します!
Micromodal.jsの動く仕組み
Micromodal.jsの挙動は非常にシンプルで、以下2点のみとなります。
- aria-hiddenの値を切り替える
- aria-hiddenの値によって .is-openをつけ外しする
aria-hidden=”true”の場合
aria-hidden="true"
の場合はMicromodal.jsが.is-open
を外します。CSSにはモーダル要素を非表示にするスタイルを指定しましょう。
<div id="modal-1" class="micromodal-slide" aria-hidden="true"><!-- モーダルコンテンツ --></div>
data-micromodal-trigger
が付与された要素をクリックすると、aria-hidden="false"
に値が変わります。
aria-hidden=”false”の場合
aria-hidden="false"
の場合はMicromodal.jsが.is-open
を付与します。
このときCSSにはモーダル要素を表示するスタイルを指定しましょう。
<div id="modal-1" class="micromodal-slide is-open" aria-hidden="false"><!-- モーダルコンテンツ --></div>
data-micromodal-close
が付与された要素をクリックすると、aria-hidden="true"
に値が変わります。
Micromodal.jsを使ったサンプル
モーダルを開いたら背景固定
スクロールを固定するにはdisableScroll
オプションを指定します。
MicroModal.init({ disableScroll: true });
サンプルではひとつのセクション長さを90vhとしていますが、モーダルが出現している間はスクロールできなくなっています。
同一ページ内に複数のモーダルを設置
複数モーダルを設置する際はモーダルそれぞれに固有のidを付与し、モーダルを開くボタンにidを紐付けます。
<button
class="modal__btn modal__btn-primary"
data-micromodal-trigger="modal-1"
role="button"
>
モーダル1
</button>
<button
class="modal__btn modal__btn-primary"
data-micromodal-trigger="modal-2"
role="button"
>
モーダル2
</button>
<button
class="modal__btn modal__btn-primary"
data-micromodal-trigger="modal-3"
role="button"
>
モーダル3
</button>
<div id="modal-1" aria-hidden="true"><!-- モーダルコンテンツ --></div>
<div id="modal-2" aria-hidden="true"><!-- モーダルコンテンツ --></div>
<div id="modal-3" aria-hidden="true"><!-- モーダルコンテンツ --></div>
クリックした画像がポップアップされる
上のコードを応用したギャラリーです。画像をクリックすると、クリックした画像がポップアップされます。
モーダルを閉じた際にモーダル内動画も停止させる
const pauseVideo = () => {
document.querySelector("video").pause(); //video要素を取得し、動画を停止する
};
MicroModal.init({
awaitCloseAnimation: true,
awaitOpenAnimation: true,
onClose: pauseVideo //モーダルを閉じるときにpauseVideoを実行する
});
モーダルを閉じた際にモーダル内の動画も停止させるには、onShowプロパティを用いて、モーダルを開いたときに「動画を停止する処理」を追加します。
ハンバーガーメニューの実装
ボタンを押したらナビゲーションメニューが画面外からスッと出てくるおなじみのUI。
メニューを開いた時、ボタンかオーバーレイ(暗くなっている部分)をクリックするとメニューが閉じるような、一般的な仕様もMicromodal.jsで実現できます。
WAI-ARIAの中で、コンテンツの展開状態を表すaria-expandedがあります。
アクセシビリティを考慮するならば、aria-expandedを開閉の条件(フック)にすることが望ましいですが、現在Firefoxブラウザに対応していません(2022年8月)
Firefoxも2023年10月24日にリリースされたバージョン119で、aria-expandedに対応しました。
ハンバーガーメニューはモーダルの開閉を一つのbutton要素で行う必要があるため、showメソッド・closeメソッドを用いて実装しています。
const button = document.getElementById("buttonHamburger");
const modal = document.getElementById("modal-1");
button.addEventListener("click", () => {
if (modal.classList.contains("is-open")) {
button.classList.remove("is-open");
button.ariaExpanded = true;
MicroModal.close("modal-1", { // モーダルを閉じる処理
awaitCloseAnimation: true // 開閉時のアニメーションを可能に
});
} else {
button.classList.add("is-open");
button.ariaExpanded = false;
MicroModal.show("modal-1", { // モーダルを開く処理
disableScroll: true, // ページスクロールを無効に
awaitOpenAnimation: true, // 開閉時のアニメーションを可能に
onClose: () => {
button.classList.remove("is-open"); // 閉じたときハンバーガーボタンのスタイルを戻す
}
});
}
});
ハンバーガーメニューの動く仕組みは以下のとおりです。
aria-hidden="ture"
のときはモーダル内のメニューを画面外へずらして設置し、aria-hidden="false"
でメニューがコンテンツ部分に被るように指定しています。
ハンバーガーボタンのデザインや、細かい動きのロジックは以下の記事で詳しく解説しています。こちらもぜひチェックしてみてください!
ボタンデザインが変わらない時は…?
サンプルを作るためにコードを書いていると、オーバーレイ部分をクリックしてもハンバーガーメニューのボタンデザインが変わらないという現象が起こりました。
いろいろ検証していると、JavaScriptでCSSのつけ外しを制御していることが原因だとわかりましたので、ポイントを紹介します。
上のサンプルでは、オーバーレイをクリックしてもボタンデザインは変わりません。
この要因は、デフォルトのdata-micromodal-trigger
やdata-micromodal-close
をフックにして動く動作とは連動しないことで起こっているようでした。
画像右のコードは正常に動作するコードです(上で紹介したコードと同じ)。
モーダルが閉じるタイミングで実行されるMicromodal.jsオプションのonCloseを使い、jsのclassListプロパティとremoveメソッドを書いて、ボタンに付与されたis-openクラスを削除することで解決しました。
JavaScript側からMicromodal.jsを動かす際には、ハンバーガーボタンを押したときのクリックイベント内に定義しているModal.showの中で、さらにオプションを定義しないとダメだったようです。
公式にも詳しく書かれていなかったため注意しましょう!
スライダー要素クリック時にモーダルを開く
上の例では、最初のスライダー要素をクリックするとモーダルが開きます。(今回のスライダーはカンタンに実装できるプラグイン「splide」を使用しています)
//splideの設定
const options = {
cover: true,
heightRatio: 0.5
};
const splide = new Splide(".splide", options);
splide.mount();
//micromodalの設定
MicroModal.init({ awaitCloseAnimation: true, awaitOpenAnimation: true });
スライダーとモーダルに関連するコードは上記のコードのみ。とてもシンプルですね!
スライダープラグインの「splide」については以下の記事で詳しく解説していますので、あわせてチェックしてみてください!
モーダル内にスライダー要素を実装
スライダープラグイン「splide」と併用したパターンをもうひとつ。今度は開いたモーダルの中にスライダー要素を実装するパターンです。
こちらを実装するには注意するポイントがあります。
splideで高さを揃えると正常に動かない時の対処
splideはjs側で画像の高さを揃えるcover
オプションを渡すことが可能ですが、こちらを指定するとMicromodal.jsが正常に動作しませんでした。
splideが生成するはずの高さが画像に適用されていないため、モーダルボタンを押しても画像が表示されていません。
ブラウザの幅を変えるとsplideが動くのか、高さが適用され画像が表示されます。
//splideの設定
const options = {
//以下のオプションを指定するとスライダーのレイアウトが崩れてしまう
cover: true, //画像のsrcをその親要素のbackground-imageに変換するかを指定
heightRatio: 0.7 //スライドの高さをスライダーの幅に対する割合で指定
};
const splide = new Splide(".splide", options);
splide.mount();
//micromodalの設定
MicroModal.init({ awaitCloseAnimation: true, awaitOpenAnimation: true });
この現象の対策は、スライダーの画像高さをCSSで指定することです。
img{
width:100%;
height:100%;
object-fit:cover;
}
splideにオプションを渡すのではなく、上のようにCSS側で制御すると正常に動作しました。
Micromodal.jsとsplideを併用するときは上記の点に気をつけて実装しましょう。
まとめ
アクセシビリティなモーダルを自作しようとすると、tabやescなどのキーボードの操作や、WAI-ARIAのことも考えなければならず、とても時間がかかりそうです。
今後モーダルを実装する際には、ぜひ今回ご紹介したMicromodal.jsを使いながら、効率よく実装を進めていきましょう!
また、モーダルと似たUIにLightbox(ポップアップ)がありますが、こちらをカンタンに実装できるライブラリ「Luminous」について解説している記事もあるので、チェックしてみてください!