マウスホバーで画像が追従して、左右端の画像にホバーすると自動スライドできるスライダーです。機能変更・追加・削除・修正・デザイン変更等のカスタマイズは制限ありません。また、ある程度は動作確認していますが、コピー&ペーストなどで動作不具合がありましても自己責任で修正してください。

※リンクURLや使用画像のアドレスはご自身の環境に合わせてください。

変更オプション

コメントアウトのコードの変更でスライダー仕様の変更ができます

・画像サイズ・画像間マージン・画像表示枚数
・枠線の太さと色・角の丸み(既存と調和)・スライダー内背景
・停止速度調整・リンク先URL・キャプション表示
・スライダー方向変更カルーセル方式※別記載ホバー時の矢印※別記載
ワードプレスに組み込む場合は、CSSのBODYを調整してください
動作確認できます👆
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>マウス追従型スライダー</title>
  <style>
    :root {
      /*=======画像サイズ========*/
      --image-width: 200px;
      /*=======画像間マージン====*/
      --image-margin: 10px;
      /*=======表示枚数==========*/
      --visible-count: 3;
    }

    body {
      margin: 0;
      padding: 0;
      /*=======背景画像グラデーション==========
      background: radial-gradient(circle at 30% 30%, #e0f7fa, #b2ebf2, #80deea);*/
      background: rgba(255, 255, 255,0);
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      font-family: 'Helvetica Neue', sans-serif;
    }

    .slider-container {
      overflow: hidden;
      /*=======スライダーの横幅を自動計算==========*/
      width: calc(var(--image-width) * var(--visible-count) + var(--image-margin) * (var(--visible-count) - 1));
      border-radius: 16px;
      border: 2px solid #200bdd;/* 枠線の太さと色 */
      border-radius: 16px;/* 角の丸み(既存と調和) */
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
      /*=======画像内背景==========*/
      /*background: rgba(255, 255, 255, 0);===透明==*/
      background: rgba(255, 255, 255, 0.9);
      backdrop-filter: blur(6px);
      touch-action: pan-x;
      cursor: grab;
    }

    .slider-track {
      display: flex;
      /*=======滑らかに停止==========*/
      transition: transform 0.3s ease-out;
      will-change: transform;
    }

    .slider-track a {
      display: block;
      width: var(--image-width);
      margin-right: var(--image-margin);
      flex-shrink: 0;
    }

    .slider-track img {
      display: block;
      width: 100%;
      height: auto;
      object-fit: cover;
      border-radius: 12px;
      /*=======画像の影==========*/
      box-shadow: 0 2px 6px rgba(0,0,0,0.1);
    }

    .captioned {
      position: relative;
      margin: 0;
    }

    .captioned img {
      display: block;
      width: 100%;
      height: auto;
      border-radius: 12px;
    }

    .captioned figcaption {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: white;
      font-size: 18px;
      font-weight: bold;
      text-shadow: 0 0 6px rgba(0,0,0,0.6);
      pointer-events: none;
    }
  </style>
</head>
<body>

  <div class="slider-container" id="sliderContainer">
    <div class="slider-track" id="sliderTrack">
      <!--=======リンク先URL・画像表示アドレスは変更してください==========-->       
      <a href="https://example.com/1"><img src="./image/set01.png" alt="1" />
      <!--======キャプション表示===========-->
      <figcaption><font color="yellow">画像1の物語を表示</font></figcaption></figure></a>
      <a href="https://example.com/2"><img src="./image/set02.png" alt="2" /></a>
      <a href="https://example.com/3"><img src="./image/set03.png" alt="3" /></a>
      <a href="https://example.com/4"><img src="./image/set04.png" alt="4" /></a>
      <a href="https://example.com/5"><img src="./image/set05.png" alt="5" /></a>
      <a href="https://example.com/6"><img src="./image/set06.png" alt="6" /></a>
      <!--=======画像数の調整 任意の数========
      <a href="https://example.com/7"><img src="./image/set07.png" alt="7" /></a>
      <a href="https://example.com/8"><img src="./image/set08.png" alt="8" /></a>
      <a href="https://example.com/9"><img src="./image/set09.png" alt="9" /></a>
      <a href="https://example.com/10"><img src="./image/set10.png" alt="10" /></a>-->
    </div>
  </div>

  <script>
    const container = document.getElementById('sliderContainer');
    const track = document.getElementById('sliderTrack');
    const imageWidth = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--image-width'));
    const imageMargin = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--image-margin'));
    const visibleCount = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--visible-count'));
    const step = imageWidth + imageMargin;
    const imageCount = track.querySelectorAll('a').length;
    const maxTranslate = step * (imageCount - visibleCount);
  
    const leftZone = document.createElement('div');
    const rightZone = document.createElement('div');
    leftZone.className = 'hover-zone hover-left';
    rightZone.className = 'hover-zone hover-right';
    container.appendChild(leftZone);
    container.appendChild(rightZone);

    let isHovering = false;
    let lastX = null;
    let currentTranslate = 0;

    container.addEventListener('mouseenter', () => {
      isHovering = true;
    });

    container.addEventListener('mousemove', e => {
      if (!isHovering) return;
      if (lastX === null) {
        lastX = e.clientX;
        return;
      }
      const deltaX = e.clientX - lastX;
      lastX = e.clientX;
      /*=======方向移動 "-="==========*/
      currentTranslate += deltaX;
      currentTranslate = Math.max(-maxTranslate, Math.min(0, currentTranslate));
      track.style.transform = `translateX(${currentTranslate}px)`;
    });

    container.addEventListener('mouseleave', () => {
      isHovering = false;
      lastX = null;
    });

    // タッチ操作(スマホ対応)
    let startX = 0;
    container.addEventListener('touchstart', e => {
      startX = e.touches[0].clientX;
    });

    container.addEventListener('touchmove', e => {
      const deltaX = e.touches[0].clientX - startX;
      startX = e.touches[0].clientX;
      currentTranslate += deltaX;
      currentTranslate = Math.max(-maxTranslate, Math.min(0, currentTranslate));
      track.style.transform = `translateX(${currentTranslate}px)`;
    });

  const style = document.createElement('style');
  style.textContent = `
    .hover-zone {
    position: absolute;
    top: 0;
    width: 50px;
    height: 100%;
    z-index: 10;
    background: rgba(0,0,0,0.01);
    }
    .hover-left { left: 0; }
    .hover-right { right: 0; }
  `;
document.head.appendChild(style);

// 自動スライド処理
let hoverInterval = null;

leftZone.addEventListener('mouseenter', () => {
  hoverInterval = setInterval(() => {
     // 画像数に応じて
    currentTranslate += 5;
    currentTranslate = Math.min(0, currentTranslate);
    track.style.transform = `translateX(${currentTranslate}px)`;
  }, 30);
});

leftZone.addEventListener('mouseleave', () => {
  clearInterval(hoverInterval);
});

rightZone.addEventListener('mouseenter', () => {
  hoverInterval = setInterval(() => {
    // 画像数に応じて
    currentTranslate -= 5;
    currentTranslate = Math.max(-maxTranslate, currentTranslate);
    track.style.transform = `translateX(${currentTranslate}px)`;
  }, 30);
});

rightZone.addEventListener('mouseleave', () => {
  clearInterval(hoverInterval);
});
    </script>
  </body>
</html>
カルーセル方式(JS)
<script>
const container = document.getElementById('sliderContainer');
const track = document.getElementById('sliderTrack');
const imageWidth = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--image-width'));
const imageMargin = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--image-margin'));
const step = imageWidth + imageMargin;
const visibleCount = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--visible-count'));

// 元画像を取得
const images = Array.from(track.children);
const imageCount = images.length;

// ===== 無限ループ用に複製(末尾だけ) =====
images.forEach(img => {
  track.appendChild(img.cloneNode(true));
});

// トラック全体の幅を調整
const totalCount = track.querySelectorAll('a').length;
track.style.width = `${totalCount * step}px`;

// 初期位置を「元画像群の先頭」に設定
let currentTranslate = 0;
track.style.transform = `translateX(${currentTranslate}px)`;

// ===== 共通移動関数 =====
function moveSlider(deltaX) {
  currentTranslate += deltaX;
  track.style.transition = 'transform 0.2s linear';
  track.style.transform = `translateX(${currentTranslate}px)`;

  // 末尾に到達したら先頭に戻す(ジャンプではなく自然に)
  if (currentTranslate <= -(imageCount * step)) {
    track.style.transition = 'none';
    currentTranslate = 0; // 先頭に戻す
    track.style.transform = `translateX(${currentTranslate}px)`;
    requestAnimationFrame(() => {
      track.style.transition = 'transform 0.2s linear';
    });
  }

  // 先頭より戻りすぎたら末尾へ(逆方向)
  if (currentTranslate > 0) {
    track.style.transition = 'none';
    currentTranslate = -(imageCount * step);
    track.style.transform = `translateX(${currentTranslate}px)`;
    requestAnimationFrame(() => {
      track.style.transition = 'transform 0.2s linear';
    });
  }

  // 右端に到達したら左端へジャンプ
  if (currentTranslate < -(imageCount * step * 2 - visibleCount * step)) {
    track.style.transition = 'none';
    currentTranslate += imageCount * step;
    track.style.transform = `translateX(${currentTranslate}px)`;

    requestAnimationFrame(() => {
      track.style.transition = 'transform 0.2s linear';
    });
  }
}

// ===== マウス操作 =====
let isHovering = false;
let lastX = null;

container.addEventListener('mouseenter', () => {
  isHovering = true;
});
container.addEventListener('mousemove', e => {
  if (!isHovering) return;
  if (lastX === null) {
    lastX = e.clientX;
    return;
  }
  const deltaX = e.clientX - lastX;
  lastX = e.clientX;
  moveSlider(deltaX);
});
container.addEventListener('mouseleave', () => {
  isHovering = false;
  lastX = null;
});

// ===== タッチ操作(スマホ対応) =====
let startX = 0;
container.addEventListener('touchstart', e => {
  startX = e.touches[0].clientX;
});
container.addEventListener('touchmove', e => {
  const deltaX = e.touches[0].clientX - startX;
  startX = e.touches[0].clientX;
  moveSlider(deltaX);
});

// ===== 自動スライド用 hover-zone =====
const leftZone = document.createElement('div');
const rightZone = document.createElement('div');
leftZone.className = 'hover-zone hover-left';
rightZone.className = 'hover-zone hover-right';
container.appendChild(leftZone);
container.appendChild(rightZone);

const style = document.createElement('style');
style.textContent = `
  .hover-zone {
    position: absolute;
    top: 0;
    width: 50px;
    height: 100%;
    z-index: 10;
    background: rgba(0,0,0,0.01);
  }
  .hover-left { left: 0; }
  .hover-right { right: 0; }
`;
document.head.appendChild(style);

let hoverInterval = null;

leftZone.addEventListener('mouseenter', () => {
  hoverInterval = setInterval(() => {
    moveSlider(5); // 左方向へ
  }, 30);
});
leftZone.addEventListener('mouseleave', () => {
  clearInterval(hoverInterval);
});

rightZone.addEventListener('mouseenter', () => {
  hoverInterval = setInterval(() => {
    moveSlider(-5); // 右方向へ
  }, 30);
});
rightZone.addEventListener('mouseleave', () => {
  clearInterval(hoverInterval);
});
</script>
ホバー時の矢印 (CSS)
 /*=======各設定は自由にどうぞ============*/
  .hover-zone {
  position: absolute;
  top: 0;
  width: 50px;
  height: 100%;
  z-index: 10;
  background: rgba(0,0,0,0.01);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(56, 30, 170, 0); /* 初期は透明 */
  font-size: 24px;
  transition: color 0.3s ease;
  pointer-events: auto;
}

.hover-zone:hover {
  color: rgba(0, 0, 0, 0.8); /* ホバー時に矢印が見える */
  background: rgba(255, 255, 255,0.6);
  top: 50px;
  border-radius: 6px;
  width: 50px;
  height: 100px;
}

.hover-left { left: 0; }
.hover-right { right: 0; }

.hover-left::before {
  content: "<";
}

.hover-right::before {
  content: ">";
}

終わり・・・