半年前の自分が書いたjQueryで動くモーダルウィンドウをリファクタリングしてみました。
リファクタリングにあたっては以下のポイントを意識しました。
- 機能とデザインの分離 : スタイルに関することは達成可能な限りJSではなくCSSにやらせる
- パフォーマンスを意識 : JSによるDOM操作、アニメーション系メソッドなど重い実装を排除する
- アクセシビリティを意識 : マウスだけでなくキーボード操作を可能にする
- アンチパターンを排除 : 3.のキーボード操作実装にあたって、同じ記述の繰り返しを避ける(DRY原則)
というわけで完成したモーダルはこちらです。
See the Pen jQuery Modal by Hibiki Kudo (@h_kudo) on CodePen.
動きも軽快でキーボードでも操作できる。いい感じです。
以下簡単に説明です。
機能とデザインの分離 : スタイルに関することは達成可能な限りJSではなくCSSにやらせる
従来モーダルの中央寄せはJSで計算して描画していましたが、中央寄せはCSSだけで実装できます。またその他のスタイル実装においても.css
メソッドを使わず、なるべく.addClass
, .removeClass
メソッドを用いてCSSクラスを変更する形にします。
$(window).resize(centeringModal);
function centeringModal() {
var width = $(window).width();
var height = $(window).height();
var cWidth = $("#modal-content").outerWidth();
var cHeight = $("#modal-content").outerHeight();
$("#modal-content").css({
left: (width - cWidth) / 2 + "px",
top: (height - cHeight) / 2 + "px"
});
}
↓
.modal__content{
width: 500px;
min-height: 220px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
パフォーマンスを意識 : JSによるDOM操作、アニメーション系メソッドなど重い実装を排除する
従来は.append
, .remove
メソッドを使ってモーダル背景を直接DOM操作していましたが、これはパフォーマンス的に重いので思い切ってHTMLにモーダル背景を置きっぱなしにし、この表示・非表示を切り替えるのみにする形にしました。
また、処理の重い.fadeIn
, .fadeOut
などのアニメーション系メソッドを非使用とし、アニメーションはもっぱらCSSのtransition
プロパティにやらせます。
$( "#modal-content" ).fadeIn();
↓
$( "#modal-content" ).addClass(".is-visible");
.modal__content.is-visible{
opacity: 1;
visibility: visible;
transition:visibility .3s ease, opacity .3s ease;
z-index: 1002;
}
アクセシビリティを意識 : マウスだけでなくキーボード操作を可能にする
基本的には.on
イベントに.click
だけでなく.keydown
を追加するだけなので意外と簡単。
他にはtabindex
属性をこねこねしたり.focus
,.blur
メソッドを使って、キーボードユーザーのユーザビリティを高めています。
モーダル・オーバーレイは置きっ放しにするためスクリーンリーダー・ユーザーなどにとって邪魔な要素となりますが、role="presentation"
、aria-hidden="true"
を追記することでアクセシビリティを担保させています。
const $modalOpen = $(".js-modal-open");
$modalOpen.on("click", function(e) {
/* 処理 */
});
$modalOpen.on("keydown", function(e) {
if (e.keyCode === 13) {
$(this).trigger("click");
}
});
アンチパターンを排除 : 3.のキーボード操作実装にあたって、同じ記述の繰り返しを避ける
キーボード操作を追加するだけなら確かに簡単でしたが、上記のafterVer1.jsでは.on
メソッドを繰り返し書いてしまっています。連想配列を使ってよりすっきりと記述することができました。
const $modalOpen = $(".js-modal-open");
$modalOpen.on({
click: function() {
/* 処理 */
},
keydown: function(e) {
if (e.keyCode === 13) {
this.trigger("click");
}
}
});
所感
- パフォーマンスは体感的に向上してるんですが、今回ちゃんと計測してません(次こそは)。
- CodePen埋め込み良い。
- 我々がその気になればjQueryもモダンを意識して書くことは可能…ということ!
精進します。