AsaDesign

レシピサイトをつくる(モーダルウィンドウでリンク先を表示する-JavaScript)

参考にさせていただきました

完成イメージ

記事一覧のどれかをクリックすると、モーダルで投稿詳細ページが表示されます。

HTML

<ul class="modal-recipe">
  <li>
    <a class="js-modal-recipe" href="https://~~"></a>
  </li>
</ul>

ulのmodal-recipeはcssスタイルをあてます。

aのjs-modal-recipehrefのリンクはJavaScriptで使います。

JavaScript

JavaScript全コード
// タグを出力してオブジェクトを作る
const printRecipeModal = recipeUrl => {
  let modal = document.createElement('div');
  modal.id = "modalRecipe";
  modal.classList.add('ed-modal');
  modal.innerHTML = `
  <div id="modalOverlay">
  <div class="modalContent">
    <div id="closeModal" class="ed-closeModal"></div>
      <div class="recipe">
        <iframe src="${recipeUrl}" frameborder="0" allowfullscreen> </iframe>
      <div>
  </div>
  </div>`;
  document.body.appendChild(modal);
  closeModal(modal);
};

// モーダルを閉じる
const closeModal = modal => {
  document.getElementById('closeModal').addEventListener('click', () => {
    document.body.removeChild(modal);
  });
  document.getElementById('modalOverlay').addEventListener('click', () => {
    document.body.removeChild(modal);
  });  
  window.addEventListener('keyup', e => {
    if (e.key === 'Escape') {
      document.body.removeChild(modal);
    }
  });
};

// モーダルを開く
const openRecipeModal = selector => {
  let linksElements = [...document.querySelectorAll(selector)];
  linksElements.forEach((el) => {
    el.addEventListener('click', e => {
      e.preventDefault();
      printRecipeModal(el.href);
    });
  });
};

openRecipeModal('.js-modal-recipe');

モーダルを開く関数では、①<a>タグの配列を取得して、②タグを生成する関数に、クリックした<a>タグのhrefリンクを渡しています。

タグを生成する関数では、受け取ったhrefリンクを<iframe>タグのsrc部分に埋め込み、document.body.appendChild(modal);でHTMLにモーダル部分を追加しています。

モーダルを閉じる関数では、バツボタンをクリック or モーダルの外側をクリック or Escapeキーをクリックして離した(keyup)時に、document.body.removeChild(modal);でHTMLからモーダル部分を削除しています。

CSS

CSS全コード
/* カード */
ul.modal-recipe {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 10px;
}
ul.modal-recipe li a {
  display: block;
  text-align: center;
}
ul.modal-recipe li a:hover {
  box-shadow: 0 15px 30px -5px rgb(0 0 0 / 15%), 0 0 5px rgb(0 0 0 / 10%);
  transform: translateY(-4px);
  text-decoration: none;
}
ul.modal-recipe li a img {
  border-radius: 50%;
}
ul.modal-recipe li a p {
  color: #313131;
  padding: 5px 0;
  font-size: .8rem;
}
/* modal */
.ed-modal {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.9);
display: flex;
z-index: 9999;
}
div#modalOverlay {
  width: 100%;
  height: 100%;
  display: flex;
  cursor: pointer;
}
.ed-closeModal {
  position: absolute;
  top: -35px;
  right: 5px;
  cursor: pointer;
  width: 1.5rem;
  height: 1.5rem;
  opacity: 0.5;
}
.ed-closeModal::before, .ed-closeModal::after {
content: "";
width: 35px;
height: 2px;
background: #fff;
position: absolute;
top: 0;
transform: rotate(45deg);
transform-origin: top left;
}
.ed-closeModal::before {
left: 0;
}
.ed-closeModal::after {
right: 0;
transform: rotate(-45deg);
transform-origin: top right;
}

.modalContent {
width: 100%;
max-width: 800px;
margin: auto;
position: relative;
}

.recipe {
width: 100%;
position: relative;
/* height: 0; */
height: 90vh;
padding-bottom: 56.25%;
overflow: hidden;
filter: drop-shadow(0px 2px 5px #313131);
animation: fadeIn 1.2s ease 0s 1 normal;
}
.recipe iframe {
width: 100%;
position: absolute;
top: 0;
left: 0;
height: 100%;
}

@keyframes fadeIn {
0% {
  opacity: 0;
  transform: translateY(30px);
}
100% {
  opacity: 1;
}
}

@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
ul.modal-recipe li {
  width: 100%;
}
}

ul.modal-recipeでは記事一覧の見た目を調整します。