CSSの scroll-snap を用いた、モダンで滑らかなカルーセル型スライダーです。レスポンシブに対応し、ナビゲーションドットとボタンで直感的な操作が可能です。

お客様の声

当サービスをご利用いただいた皆様の体験談をご紹介します。

「このプロダクトのおかげで、私たちのワークフローは完全に生まれ変わりました。直感的なインターフェースと素晴らしいサポートチームのおかげで、日々成長するビジネスに最適です。」

Sarah Jenkins

佐藤 彩

プロダクトマネージャー

「多くの類似ツールを試してきましたが、これこそが際立っています。デザインの細部へのこだわりとスムーズな操作性により、毎日の作業が楽しくなりました。」

Michael Chen

田中 健一

UX デザイナー

「既存システムとのシームレスな連携により、数週間分の開発期間を短縮できました。非常に堅牢で、私たちの規模拡大にも難なく対応してくれます。」

Elena Rodriguez

鈴木 エレナ

CTO

「カスタマーサービスが並外れています。質問があるときはいつでも、役に立つ解決策を即座に返信してくれます。私たちの成功の真のパートナーです。」

David Miller

山田 大輔

オペレーションディレクター
<div class="testimonial-section">
  <div class="testimonial-header">
    <h2>お客様の声</h2>
    <p>当サービスをご利用いただいた皆様の体験談をご紹介します。</p>
  </div>
  
  <div class="slider-wrapper">
    <button class="slider-btn prev" aria-label="前のレビューへ">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>
    </button>
    
    <div class="testimonial-slider" id="testimonial-slider">
      {/* Testimonial 1 */}
      <div class="testimonial-card">
        <div class="quote-icon">"</div>
        <p class="review">「このプロダクトのおかげで、私たちのワークフローは完全に生まれ変わりました。直感的なインターフェースと素晴らしいサポートチームのおかげで、日々成長するビジネスに最適です。」</p>
        <div class="author-info">
          <img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Sarah" alt="Sarah Jenkins" class="avatar" />
          <div>
            <h4 class="author-name">佐藤 彩</h4>
            <span class="author-role">プロダクトマネージャー</span>
          </div>
        </div>
      </div>
      
      {/* Testimonial 2 */}
      <div class="testimonial-card">
        <div class="quote-icon">"</div>
        <p class="review">「多くの類似ツールを試してきましたが、これこそが際立っています。デザインの細部へのこだわりとスムーズな操作性により、毎日の作業が楽しくなりました。」</p>
        <div class="author-info">
          <img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Michael" alt="Michael Chen" class="avatar" />
          <div>
            <h4 class="author-name">田中 健一</h4>
            <span class="author-role">UX デザイナー</span>
          </div>
        </div>
      </div>
      
      {/* Testimonial 3 */}
      <div class="testimonial-card">
        <div class="quote-icon">"</div>
        <p class="review">「既存システムとのシームレスな連携により、数週間分の開発期間を短縮できました。非常に堅牢で、私たちの規模拡大にも難なく対応してくれます。」</p>
        <div class="author-info">
          <img src="https://api.dicebear.com/7.x/avataaars/svg?seed=Elena" alt="Elena Rodriguez" class="avatar" />
          <div>
            <h4 class="author-name">鈴木 エレナ</h4>
            <span class="author-role">CTO</span>
          </div>
        </div>
      </div>
      
      {/* Testimonial 4 */}
      <div class="testimonial-card">
        <div class="quote-icon">"</div>
        <p class="review">「カスタマーサービスが並外れています。質問があるときはいつでも、役に立つ解決策を即座に返信してくれます。私たちの成功の真のパートナーです。」</p>
        <div class="author-info">
          <img src="https://api.dicebear.com/7.x/avataaars/svg?seed=David" alt="David Miller" class="avatar" />
          <div>
            <h4 class="author-name">山田 大輔</h4>
            <span class="author-role">オペレーションディレクター</span>
          </div>
        </div>
      </div>
    </div>
    
    <button class="slider-btn next" aria-label="次のレビューへ">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
    </button>
  </div>
  
  <div class="slider-dots" id="slider-dots"></div>
</div>
.testimonial-section {
  max-width: 1000px;
  margin: 0 auto;
  padding: 4rem 2rem;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: #1a1a2e;
}

.testimonial-header {
  text-align: center;
  margin-bottom: 3rem;
}

.testimonial-header h2 {
  font-size: 2.5rem;
  font-weight: 800;
  margin-bottom: 0.5rem;
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.testimonial-header p {
  color: #64748b;
  font-size: 1.1rem;
}

.slider-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1rem;
}

.testimonial-slider {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  gap: 2rem;
  padding: 1rem 0;
  /* スクロールバーを非表示 */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */
}

.testimonial-slider::-webkit-scrollbar {
  display: none; /* Chrome/Safari */
}

.testimonial-card {
  flex: 0 0 100%;
  scroll-snap-align: center;
  background: #ffffff;
  border-radius: 24px;
  padding: 2.5rem;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.8);
  display: flex;
  flex-direction: column;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

@media (min-width: 768px) {
  .testimonial-card {
    flex: 0 0 calc(50% - 1rem); /* 2カラム表示 */
  }
}

.testimonial-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.12);
}

.quote-icon {
  font-size: 4rem;
  line-height: 1;
  color: #e2e8f0;
  margin-bottom: -1rem;
  font-family: serif;
}

.review {
  font-size: 1.125rem;
  line-height: 1.7;
  color: #334155;
  flex-grow: 1;
  margin-bottom: 2rem;
  font-style: italic;
}

.author-info {
  display: flex;
  align-items: center;
  gap: 1rem;
  border-top: 1px solid #f1f5f9;
  padding-top: 1.5rem;
}

.avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid #e2e8f0;
}

.author-name {
  margin: 0 0 0.25rem 0;
  font-weight: 700;
  font-size: 1.1rem;
}

.author-role {
  color: #64748b;
  font-size: 0.9rem;
}

.slider-btn {
  background: #ffffff;
  border: none;
  border-radius: 50%;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  color: #4facfe;
  transition: all 0.2s ease;
  flex-shrink: 0;
  z-index: 10;
}

.slider-btn:hover {
  background: #4facfe;
  color: #ffffff;
  transform: scale(1.05);
}

.slider-btn:active {
  transform: scale(0.95);
}

.slider-dots {
  display: flex;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 2rem;
}

.dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #cbd5e1;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: all 0.3s ease;
}

.dot.active {
  background: #4facfe;
  width: 24px;
  border-radius: 12px;
}

/* ダークモード対応 */
@media (prefers-color-scheme: dark) {
  .testimonial-section {
    color: #f8fafc;
  }
  
  .testimonial-header p {
    color: #94a3b8;
  }
  
  .testimonial-card {
    background: #1e293b;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
    border-color: rgba(255, 255, 255, 0.05);
  }
  
  .quote-icon {
    color: #334155;
  }
  
  .review {
    color: #cbd5e1;
  }
  
  .author-info {
    border-top-color: #334155;
  }
  
  .slider-btn {
    background: #1e293b;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  }
  
  .slider-btn:hover {
    background: #4facfe;
  }
  
  .dot {
    background: #475569;
  }
}
document.addEventListener('DOMContentLoaded', () => {
  const slider = document.getElementById('testimonial-slider');
  const dotsContainer = document.getElementById('slider-dots');
  const prevBtn = document.querySelector('.slider-btn.prev');
  const nextBtn = document.querySelector('.slider-btn.next');
  
  if (!slider) return;

  const cards = slider.querySelectorAll('.testimonial-card');
  const cardCount = cards.length;
  
  // 画面幅に応じて表示されているカード数を取得
  const getVisibleCards = () => window.innerWidth >= 768 ? 2 : 1;
  
  // ドットの生成と更新
  const updateDots = () => {
    dotsContainer.innerHTML = '';
    const visibleCards = getVisibleCards();
    const dotCount = Math.max(1, cardCount - visibleCards + 1);
    
    for (let i = 0; i < dotCount; i++) {
      const dot = document.createElement('button');
      dot.classList.add('dot');
      if (i === 0) dot.classList.add('active');
      dot.setAttribute('aria-label', `スライド ${i + 1} へ`);
      dot.addEventListener('click', () => scrollToSlide(i));
      dotsContainer.appendChild(dot);
    }
  };

  updateDots();
  
  // リサイズ時に再計算
  window.addEventListener('resize', () => {
    updateDots();
    updateActiveDot();
  });

  // 指定のスライドへスクロール
  const scrollToSlide = (index) => {
    const cardWidth = cards[0].offsetWidth;
    const gap = parseFloat(window.getComputedStyle(slider).gap) || 0;
    slider.scrollTo({
      left: index * (cardWidth + gap),
      behavior: 'smooth'
    });
  };

  // スクロール位置に応じてアクティブなドットを更新
  const updateActiveDot = () => {
    const dots = dotsContainer.querySelectorAll('.dot');
    if (!dots.length) return;
    
    const cardWidth = cards[0].offsetWidth;
    const gap = parseFloat(window.getComputedStyle(slider).gap) || 0;
    const scrollPosition = slider.scrollLeft;
    
    // 現在のインデックスを計算
    const activeIndex = Math.round(scrollPosition / (cardWidth + gap));
    
    dots.forEach((dot, index) => {
      dot.classList.toggle('active', index === activeIndex);
    });
  };

  // スクロールイベントに連動
  slider.addEventListener('scroll', updateActiveDot);

  // ボタンによるスクロール操作
  prevBtn.addEventListener('click', () => {
    const cardWidth = cards[0].offsetWidth;
    const gap = parseFloat(window.getComputedStyle(slider).gap) || 0;
    slider.scrollBy({ left: -(cardWidth + gap), behavior: 'smooth' });
  });

  nextBtn.addEventListener('click', () => {
    const cardWidth = cards[0].offsetWidth;
    const gap = parseFloat(window.getComputedStyle(slider).gap) || 0;
    slider.scrollBy({ left: (cardWidth + gap), behavior: 'smooth' });
  });
});