Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
17
Help us understand the problem. What is going on with this article?
@kitikitchen

スマホで使えるシンプルなモーダルウィンドウ

モーダルウィンドウを実装したい、でもライブラリ使うほどの要件ではない。
といった時に使える自前でパパっとモーダルウィンドウの実装。

やりたいこと

  • 要素(ボタンやaタグ)をクリックしたらモーダルウィンドウが表示される
  • モーダルウィンドウは画面の中央に表示
  • モーダル内の要素が画面の高さを超えた場合、スクロールできる
  • 「閉じるボタン」を押したらモーダルウィンドウが閉じる
  • オーバーレイをクリックしたらモーダルウィンドウが閉じる
html
<!-- モーダルを表示させるためのボタンにはclass="modalBtn"を付与 -->
<button class="modalBtn" type="button">モーダル表示ボタン</button>
<p>aタグでも<a class="modalBtn" href="#">モーダル表示</a></p>

<!-- モーダルウィンドウテンプレート -->
<div class="modal">
  <div class="modal_container">
    <div class="modal_inner">
      <div class="modal_content">
        <div>ここにモーダルで表示させたいものをいれる。</div>
        <!-- モーダルを閉じるボタンにはclass="modalClose"を付与 -->
        <button class="modalClose" type="button">閉じる</button>
        <p>aタグでも<a class="modalClose" href="#">閉じる</a></p>
      </div>
    </div>
  </div>
</div>
scss
// モーダルウィンドウの上下の余白(コンテンツ内の要素が画面の高さを超えた場合に適用される)
$modal_padding_y: 20px;

// モーダルウィンドウの左右の余白
$modal_padding_x: 20px;

.modal {
  visibility: hidden;
  overflow-y: scroll;
  opacity: 0;
  position: fixed;
  z-index: 100;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 0 $modal_padding_x;
  transition: opacity 0.3s, visibility 0s 0.3s;
  background: rgba(0, 0, 0, 0.8);

  &.is-active {
    visibility: visible;
    opacity: 1;
    transition: opacity 0.3s, visibility 0s 0s;
  }
}

.modal_container {
  display: flex;
  min-height: 100%;
  justify-content: center;
  align-items: center;

  // 以下、IE11 ハック(IEでこれがないと上下中央寄せが出来ない)
  _:-ms-lang(x)::-ms-backdrop,
  & {
    min-height: 100vh;
  }

  &::after {
    content: '';
    min-height: inherit;
    font-size: 0;
  }
}

.modal_inner {
  margin: $modal_padding_y auto;
  width: auto;
}

.modal_content {
  display: none;
  border-radius: 2px;
  background: #fff;

  .is-active & {
    display: block;
  }
}
jQuery
$(function(){
  var $modal = $('.modal');
  var $inner = $('.modal_inner');
  var $btn = $('.modalBtn');
  var $close = $('.modalClose');

  // モーダルを開く処理
  $btn.on('click', function(event) {
    event.preventDefault();
    $modal.addClass('is-active');
  });

  // モーダルを閉じる処理
  $close.add($modal).on('click', function(event) {
    event.preventDefault();
    $modal.removeClass('is-active');
  });

  // コンテンツクリック時に閉じないようにする処理
  $inner.on('click', function(event) {
    event.stopPropagation();
  });
});

ページに複数のモーダルウィンドウが存在する場合

  • モーダルウィンドウテンプレートを複数用意して data属性で管理
html
<!-- モーダルを表示させるためのボタンにはclass="modalBtn"を付与 -->
<button class="modalBtn" data-modalIndex="1" type="button">モーダル表示ボタン</button>
<p>aタグでも<a class="modalBtn" data-modalIndex="2" href="#">モーダル表示</a></p>

<!-- モーダルウィンドウテンプレート1 -->
<div class="modal" data-modalIndex="1">
  <div class="modal_container">
    <div class="modal_inner">
      <div class="modal_content">
        <div>ここにモーダルで表示させたいものをいれます。</div>
        <!-- モーダルを閉じるボタンにはclass="modalClose"を付与 -->
        <button class="modalClose" type="button">閉じる</button>
        <p>aタグでも<a class="modalClose" href="#">閉じる</a></p>
      </div>
    </div>
  </div>
</div>

<!-- モーダルウィンドウテンプレート2 -->
<div class="modal" data-modalIndex="2">
  <div class="modal_container">
    <div class="modal_inner">
      <div class="modal_content">
        <div>モーダル2</div>
        <!-- モーダルを閉じるボタンにはclass="modalClose"を付与 -->
        <button class="modalClose" type="button">閉じる</button>
        <p>aタグでも<a class="modalClose" href="#">閉じる</a></p>
      </div>
    </div>
  </div>
</div>
scss
変更なし
jQeury
$(function(){
  var $modal = $('.modal');
  var $inner = $('.modal_inner');
  var $btn = $('.modalBtn');
  var $close = $('.modalClose');

  // モーダルを開く処理
  $btn.on('click', function(event) {
    event.preventDefault();
    var _modalIndex = $(this).attr('data-modalIndex') || null;

    if (_modalIndex) {
      $modal.filter('[data-modalIndex="' + _modalIndex + '"]').addClass('is-active');
    } else {
      $modal.addClass('is-active');
    }
  });

  // モーダルを閉じる処理
  $close.add($modal).on('click', function(event) {
    event.preventDefault();
    $modal.removeClass('is-active');
  });

  // コンテンツクリック時に閉じないようにする処理
  $inner.on('click', function(event) {
    event.stopPropagation();
  });
});

モーダルウィンドウ下のコンテンツをスクロールさせたくない場合

  • モーダルウィンドウが表示されているときにはその他のコンテンツを固定させる
HTML
<body>
<div class="wrapper>
~
</div>
</body>
SCSS
.wrapper {
  &.is-locked {
    position: fixed;
    width: 100%;
  }
}
JavaScript
$(function(){
  var $modal = $('.modal');
  var $inner = $('.modal_inner');
  var $btn = $('.modalBtn');
  var $close = $('.modalClose');

  var $win = $(window);
  var $wrapper = $('.wrapper');
  var scrollPosition;
  var scrollPositionLocked;

  // スクロール位置を取得
  $win.on('scroll load', function(event) {
    scrollPosition = $win.scrollTop();
  });

  // モーダルを開く処理
  $btn.on('click', function(event) {
    event.preventDefault();
    var _modalIndex = $(this).attr('data-modalIndex') || null;

    // モーダル以外を固定
    scrollPositionLocked = scrollPosition;
    $wrapper.addClass('is-locked');
    $wrapper.css({top: -scrollPosition});

    if (_modalIndex) {
      $modal.filter('[data-modalIndex="' + _modalIndex + '"]').addClass('is-active');
    } else {
      $modal.addClass('is-active');
    }

  });

  // モーダルを閉じる処理
  $close.add($modal).on('click', function(event) {
    event.preventDefault();

    // モーダル以外を固定解除
    $wrapper.removeClass('is-locked');
    $win.scrollTop(scrollPositionLocked);

    $modal.removeClass('is-active');
  });

  // コンテンツクリック時に閉じないようにする処理
  $inner.on('click', function(event) {
    event.stopPropagation();
  });
});
17
Help us understand the problem. What is going on with this article?
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
kitikitchen
フロントエンドエンジニアもどき

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
17
Help us understand the problem. What is going on with this article?