YouTube動画

マウスオンで再生

  • APIの読み込みで単動画再生
  • playsinline: 1, mute: 1, controls: 0

HTML

<div id="player-container">
   <div id="player"></div>
</div>

CSS

iframe {
        display: block;
        width: min(680px, 90%);
        height: auto;
        margin-inline: auto;
        aspect-ratio: 16 / 9;
      }

js

  var tag = document.createElement("script");
  tag.src = "https://www.youtube.com/iframe_api";
  var firstScriptTag = document.getElementsByTagName("script")[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

  var player;
  function onYouTubeIframeAPIReady() {
    player = new YT.Player("player", {
      videoId: "動画ID",
      playerVars: { playsinline: 1, mute: 1, controls: 0 },
      events: { onReady: onPlayerReady },
    });
  }

  function onPlayerReady(event) {
    const container = document.getElementById("player-container");

    const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;

    if (!isTouchDevice) {
      container.addEventListener("mouseenter", () => player.playVideo());
      container.addEventListener("mouseleave", () => player.pauseVideo());
    } else {
      container.addEventListener("touchstart", () => {
        const state = player.getPlayerState();
        if (state === YT.PlayerState.PLAYING) {
          player.pauseVideo();
        } else {
          player.playVideo();
        }
      });
    }
  }

複数動画再生

HTML

<div class="video-container">
   <div class="yt-player" data-id="動画ID-1">
   </div>
   <div class="yt-player" data-id="動画ID-2">
   </div>
   <div class="yt-player" data-id="動画ID-3">
   </div>
</div>

CSS

.video-container {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
    cursor: pointer;
  }

  #player {
    width: 100%;
    aspect-ratio: 16 / 9;
  }

  .yt-player {
    pointer-events: auto;
  }

  .thumbnail {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-size: cover;
    background-position: center;
    transition: opacity 0.5s ease;
    z-index: 2;
    pointer-events: none;
  }

  .video-container.is-active .thumbnail {
    opacity: 0;
  }

  .play-button {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 14%;
    height: 16%;
    background: rgba(255, 0, 0, 0.8);
    border-radius: 16px;
    &::after {
      content: "";
      display: inline-block;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background-color: #fff;
      width: 25%;
      height: 46%;
      clip-path: polygon(0 0, 100% 50%, 0 100%);
      translate: 3px 0;
    }
  }

js

 var tag = document.createElement("script");
  tag.src = "https://www.youtube.com/iframe_api";
  var firstScriptTag = document.getElementsByTagName("script")[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

  var players = [];

  function onYouTubeIframeAPIReady() {
    var elements = document.querySelectorAll(".yt-player");

    elements.forEach(function (el, index) {
      var videoId = el.getAttribute("data-id");

      var player = new YT.Player(el, {
        height: "200",
        width: "350",
        videoId: videoId,
        playerVars: {
          autoplay: 0,
          controls: 1, // 操作パネル表示
          rel: 0,
          mute: 1, // 消音
        },
        events: {
          onReady: onPlayerReady,
        },
      });
      players.push(player);
    });
  }

  function onPlayerReady(event) {
    var iframe = event.target.getIframe();

    iframe.addEventListener("mouseenter", function () {
      event.target.playVideo();
    });

    iframe.addEventListener("mouseleave", function () {
      event.target.pauseVideo();
    });
  }

iframe埋め込み

埋め込みパラメータ

rel
関連動画を非表示 :
https://www.youtube.com/embed/動画ID?rel=0
loop
動画をループ再生 :
https://www.youtube.com/embed/動画ID?loop=1
autoplay
自動再生 :
https://www.youtube.com/embed/動画ID?autoplay=1
mute
無音にする :
https://www.youtube.com/embed/動画ID?autoplay=1?mute=1
autoplayの場合はセットで
controls
コントローラを非表示 :
https://www.youtube.com/embed/動画ID?controls=0
cc_load_policy
字幕表示 :
https://www.youtube.com/embed/動画ID?cc_load_policy=1
playsinline
プレーヤーインライン再生(iOS) :
https://www.youtube.com/embed/動画ID?playsinline=1
playlist
複数動画再生 :
https://www.youtube.com/embed/動画ID1?playlist=動画ID2,動画ID3
modestbranding
動画内のYouTubeロゴ非表示 :
https://www.youtube.com/embed/動画ID1?modestbranding=1
高画質画像

HTML

<div class="yt_thumbnail">
  <iframe class="intro_movie" src="https://www.youtube.com/embed/動画ID" title="タイトル" frameborder="0" allow="accelerometer; autoplay; picture-in-picture" allowfullscreen=""></iframe>
</div>
高画質画像
<img src="https://img.youtube.com/vi/動画ID/hqdefault.jpg" alt="" />

CSS

iframe {
  display: block;
  width: min(480px, 90%);
  margin-inline: auto;
  aspect-ratio: 16 / 9;
}

Modal自動再生

HTML

<div class="video-grid">
  <div class="thumb" data-video-id="動画ID-1">
    <img src="https://img.youtube.com/vi/動画ID-1/hqdefault.jpg" alt="" />
  </div>
  <div class="thumb" data-video-id="動画ID-2">
    <img src="https://img.youtube.com/vi/動画ID-2/hqdefault.jpg" alt="" />
  </div>
  <div class="thumb" data-video-id="動画ID-3">
    <img src="https://img.youtube.com/vi/動画ID-3/hqdefault.jpg" alt="" />
  </div>
</div>
<div id="videoModal" aria-hidden="true">
  <div class="modal-content">
    <button class="close"></button>
    <div id="player"></div>
  </div>
</div>

CSS

#videoModal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.8);
  display: grid;
  place-content: center;
  opacity: 0;
  visibility: hidden;
  transition:opacity 0.3s ease, visibility 0.3s ease;
  z-index: 11;
  &.is-open {
    opacity: 1;
    visibility: visible;
  }
}
.modal-content {
  width: min(90vw, 980px);
  aspect-ratio: 16 / 9;
  position: relative;
}
.close {
  position: absolute;
  display: grid;
  place-content: center;
  top: -2.5em;
  right: -2.5em;
  background: none;
  border: none;
  height: 30px;
  width: 30px;
  padding: 0;
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.2s ease-in-out;
  &::after {
    content: "";
    display: block;
    background: #fff;
    height: 24px;
    width: 24px;
    clip-path: polygon(5% 0, 0 4%, 45% 50%, 0 95%, 5% 100%, 50% 55%, 95% 100%, 100% 95%, 55% 50%, 100% 5%, 95% 0, 50% 45%);
  }
  &:hover {
    opacity: 0.6;
  }
}

.video-grid {
  display: flex;
  gap: 1em;
  width: fit-content;
  margin-inline: auto;
  .thumb {
    cursor: pointer;
    border: #000 1px solid;
    position: relative;
    overflow: hidden;
    &::before,
    &::after {
      content: "";
      display: inline-block;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      z-index: 2;
    }
    &::before {
      width: 20%;
      height: 23%;
      background: rgba(255, 0, 0, 0.8);
      transition: all 0.3s ease-in-out;
    }
    &::after {
      background-color: #fff;
      width: 6%;
      height: 11%;
      clip-path: polygon(0 0, 100% 50%, 0 100%);
      translate: 3px 0;
    }
    &:hover::before {
      background: rgba(138, 138, 138, 0.8);
    }
    & img {
      aspect-ratio: 16 / 9;
      width: 100%;
      object-fit: cover;
      vertical-align: bottom;
      transition: scale 0.4s ease-in-out;
    }
    &:hover img {
      scale: 1.1;
    }
  }
}

js

let player = null;
let currentVideoId = null;

const tag = document.createElement("script");
tag.src = "https://www.youtube.com/iframe_api";
document.head.appendChild(tag);
function onYouTubeIframeAPIReady() {
}

document.querySelectorAll(".thumb").forEach((btn) => {
  btn.addEventListener("click", () => {
    currentVideoId = btn.dataset.videoId;
    openModal();
  });
});

function openModal() {
  const modal = document.getElementById("videoModal");
  modal.classList.add("is-open");
  modal.setAttribute("aria-hidden", "false");

  player = new YT.Player("player", {
    videoId: currentVideoId,
    playerVars: {
      autoplay: 1,
      mute: 1,
      rel: 0,
      playsinline: 1,
      origin: location.origin,
      enablejsapi: 1,
    },
  });
}

function closeModal() {
  const modal = document.getElementById("videoModal");
  modal.classList.remove("is-open");
  modal.setAttribute("aria-hidden", "true");

  if (player) {
    player.destroy();
    player = null;
  }

  document.getElementById("player").innerHTML = "";
}

document.querySelector(".close").addEventListener("click", closeModal);
document.getElementById("videoModal").addEventListener("click", (e) => {
  if (e.target.id === "videoModal") {
    closeModal();
  }
});
YouTube api読み込まない / 複数設置版

HTML

<div class="video-grid">
  <div class="thumb" data-video-id="動画ID-1">
    <img src="https://img.youtube.com/vi/動画ID-1/hqdefault.jpg" alt="" />
  </div>

  <div class="thumb" data-video-id="動画ID-2">
    <img src="https://img.youtube.com/vi/動画ID-2/hqdefault.jpg" alt="" />
  </div>

  <div class="thumb" data-video-id="動画ID-3">
    <img src="https://img.youtube.com/vi/動画ID-3/hqdefault.jpg" alt="" />
  </div>
</div>

<div id="videoModal">
  <div class="modal-content">
    <button class="close"></button>
    <iframe id="ytFrame" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
  </div>

CSS

#videoModal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.8);
  display: grid;
  place-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
  z-index: 11;
  &.is-open {
    opacity: 1;
    visibility: visible;
  }
}
h2 {
  text-align: center;
}
.modal-content {
  width: min(92vw, 980px);
  aspect-ratio: 16 / 9;
  position: relative;
}

iframe {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 2em;
  @media (736px >= width) {
    border-radius: 1em;
  }
}

.close {
  position: absolute;
  display: grid;
  place-content: center;
  top: -2.5em;
  right: -2.5em;
  background: none;
  border: none;
  height: 30px;
  width: 30px;
  padding: 0;
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.2s ease-in-out;
  &::after {
    content: "";
    display: block;
    background: #fff;
    height: 24px;
    width: 24px;
    clip-path: polygon(5% 0, 0 4%, 45% 50%, 0 95%, 5% 100%, 50% 55%, 95% 100%, 100% 95%, 55% 50%, 100% 5%, 95% 0, 50% 45%);
  }
  &:hover {
    opacity: 0.6;
  }
  @media (736px >= width) {
    top: -3em;
    right: -1em;
    &::after {
      height: 16px;
      width: 16px;
    }
  }
}

.video-grid {
  display: flex;
  gap: 1em;
  width: fit-content;
  margin-inline: auto;
  & * {
    transition: 0.3s all ease-in-out;
  }

  .thumb {
    cursor: pointer;
    outline: #777 1px solid;
    border-radius: 10px;
    min-height: 0%;
    overflow: hidden;
    position: relative;

    &::after {
      content: "";
      display: inline-block;
      background: url(./image/icon_play_btn.png) 50% 50% / contain no-repeat;
      position: absolute;
      left: 50%;
      top: 50%;
      z-index: 2;
      width: 60px;
      height: 60px;
      translate: -50% -50%;
      transition:
        0.3s scale ease-in-out,
        0.3s filter ease-in-out;
    }
    & img {
      aspect-ratio: 17 / 9;
      width: 100%;
      object-fit: cover;
      vertical-align: bottom;
    }

    &:hover {
      filter: brightness(1.2);

      &::after {
        scale: 1.2;
        filter: invert();
      }
      & img {
        scale: 1.05;
      }
    }
  }
}

js

const modal = document.getElementById("videoModal");
const iframe = document.getElementById("ytFrame");

document.querySelectorAll(".thumb").forEach((btn) => {
  btn.addEventListener("click", () => {
    const id = btn.dataset.videoId;
    iframe.src = `https://www.youtube.com/embed/${id}?autoplay=1&mute=1&rel=0&playsinline=1`;
    modal.classList.add("is-open");
  });
});

function closeModal() {
  modal.classList.remove("is-open");
  iframe.src = ""; 
}

document.querySelector(".close").addEventListener("click", closeModal);
modal.addEventListener("click", (e) => {
  if (e.target === modal) closeModal();
});
CSS

前の記事

アコーディオンUI