Help us understand the problem. What is going on with this article?

jQueryモーダルウィンドウをリファクタリング

More than 1 year has passed since last update.

半年前の自分が書いたjQueryで動くモーダルウィンドウをリファクタリングしてみました。

リファクタリングにあたっては以下のポイントを意識しました。

  1. 機能とデザインの分離 : スタイルに関することは達成可能な限りJSではなくCSSにやらせる
  2. パフォーマンスを意識 : JSによるDOM操作、アニメーション系メソッドなど重い実装を排除する
  3. アクセシビリティを意識 : マウスだけでなくキーボード操作を可能にする
  4. アンチパターンを排除 : 3.のキーボード操作実装にあたって、同じ記述の繰り返しを避ける(DRY原則)

というわけで完成したモーダルはこちらです。

See the Pen jQuery Modal by Hibiki Kudo (@h_kudo) on CodePen.

動きも軽快でキーボードでも操作できる。いい感じです。
以下簡単に説明です。

機能とデザインの分離 : スタイルに関することは達成可能な限りJSではなくCSSにやらせる

従来モーダルの中央寄せはJSで計算して描画していましたが、中央寄せはCSSだけで実装できます。またその他のスタイル実装においても.cssメソッドを使わず、なるべく.addClass, .removeClassメソッドを用いてCSSクラスを変更する形にします。

before.js
$(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"
  });
}

after.css
.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プロパティにやらせます。

before.js
$( "#modal-content" ).fadeIn();

after.js
$( "#modal-content" ).addClass(".is-visible");
after.css
.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"を追記することでアクセシビリティを担保させています。

afterVer1.js
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メソッドを繰り返し書いてしまっています。連想配列を使ってよりすっきりと記述することができました。

afterVer2.js
const $modalOpen = $(".js-modal-open");

$modalOpen.on({
  click: function() {
    /* 処理 */
  },
  keydown: function(e) {
    if (e.keyCode === 13) {
      this.trigger("click");
    }
  }
});

所感

  • パフォーマンスは体感的に向上してるんですが、今回ちゃんと計測してません(次こそは)。
  • CodePen埋め込み良い。
  • 我々がその気になればjQueryもモダンを意識して書くことは可能…ということ!

精進します。

cloudpack
Amazon Web Services (AWS) の導入設計、環境構築、運用・保守をサポートするマネジドホスティングサービス
https://cloudpack.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした