Home
>
Product
>
Template Top
>
詳細ページ

HubSpot CMS:動的な「導入事例カードモジュール」の実装と活用ガイド

Webサイトにおいて、顧客の信頼を獲得するために「導入事例」は欠かせないコンテンツです。今回解説する「導入事例カードモジュール」を使用すれば、デザインの一貫性を保ちながら、複数の成功事例をスライダー形式で美しく表示させることができます。

Demo Video

Detail

Webサイトにおいて、顧客の信頼を獲得するために「導入事例」は欠かせないコンテンツです。今回解説する「導入事例カードモジュール」を使用すれば、デザインの一貫性を保ちながら、複数の成功事例をスライダー形式で美しく表示させることができます。

1. 目的

本モジュールの主な目的は、「視覚的に優れた導入事例セクションを、専門知識がなくても直感的に構築・更新できるようにすること」です。

  • 信頼性の可視化: 企業のロゴや成果をカード形式で整理し、ユーザーに安心感を与えます。
  • スムーズな閲覧体験: カルーセル(スライダー)機能を搭載しており、限られたスペースでも多くの事例をストレスなく閲覧可能です。
  • デザインの即時カスタマイズ: 見出しのサイズや色、カードの枠線などを、コードを触らずにエディター上で自由に変更できます。

2. ユースケース

  • トップページの信頼性セクション: サイトのメインページに主要な導入企業のロゴと一言コメントを並べ、ブランド力をアピールします。
  • サービス紹介ページの成功事例: 特定のサービスに関連する事例だけをピックアップし、検討中のユーザーの背中を押します。
  • LP(ランディングページ)の成果証明: キャンペーンページなどで、短期間に信頼性を構築するための「お客様の声」として活用します。

3. 実装ステップ

新規ページの作成から、提供されたコードの適用、現場での運用設定までの全工程です。

ステップ1:ページ作成とモジュールの配置

HubSpot管理画面から新しいページを立ち上げます。エディター左側のサイドバーでモジュール名を検索し、編集エリアへドラッグ&ドロップして配置します。

ステップ2:デザインマネージャーでのコード適用

デザインマネージャーで新規モジュールを作成し、公開されているソースコードを、それぞれの該当箇所(HTML/HubL、JS、CSS)へそのままコピー&ペーストして保存・公開します。

ステップ3:エディターでの運用・カスタマイズ

コード適用後は、編集画面のサイドパネルからノーコードで詳細を調整できます。

  • コンテンツの追加: 「cards」グループから、事例ごとの画像、タイトル、説明文を必要な数だけ追加します。
  • 全体設定: セクション全体のタイトル入力や、自動再生(autoplay)の有無を切り替えます。
  • スタイル調整: カラーピッカーを使って、タイトルやカードの枠線の色をブランドイメージに合わせて微調整します。

モジュールのソースコード

HubSpotのDesign Managerで「新規モジュール」を作成し、以下のコードをそれぞれの箇所に貼り付けてください。

1. fields.json

フィールド定義です。繰り返しフィールド(Items)と、スタイル設定用フィールド(Styles)で構成されています。

[
 {
  "allow_new_line": false,
  "display_width": null,
  "id": "f828e942-d88b-6872-99aa-7e6839a2ba4a",
  "label": "section_title",
  "locked": false,
  "name": "section_title",
  "required": false,
  "type": "text"
 },
 {
  "default": {
   "color": null,
   "opacity": null
  },
  "display_width": null,
  "id": "23d16879-569c-2624-b906-6ae2371a442f",
  "label": "title_color",
  "locked": false,
  "name": "title_color",
  "required": false,
  "type": "color"
 },
 {
  "display": "text",
  "display_width": null,
  "id": "bf18e844-9553-d75c-fe55-7e0c1a65fe9d",
  "label": "title_font_size",
  "locked": false,
  "name": "title_font_size",
  "required": false,
  "step": 1,
  "type": "number"
 },
 {
  "children": [
   {
    "default": {
     "size_type": "auto",
     "src": "",
     "alt": null,
     "loading": "lazy"
    },
    "display_width": null,
    "id": "0c514272-f096-02d4-33c1-791a40fe2d9f",
    "label": "Image",
    "locked": false,
    "name": "image",
    "required": false,
    "resizable": true,
    "responsive": true,
    "show_loading": false,
    "type": "image"
   },
   {
    "allow_new_line": false,
    "display_width": null,
    "id": "1f453c47-b6a2-a51a-f8d7-dc5248114ba0",
    "label": "title",
    "locked": false,
    "name": "title",
    "required": false,
    "type": "text"
   },
   {
    "display_width": null,
    "id": "456812f3-1652-0fff-f563-f8787f2efbcc",
    "label": "description",
    "locked": false,
    "name": "description",
    "required": false,
    "type": "richtext"
   }
  ],
  "default": [],
  "display_width": null,
  "expanded": false,
  "group_occurrence_meta": null,
  "id": "004e3419-0e40-def3-93c0-bf008f14bb26",
  "label": "cards",
  "locked": false,
  "name": "cards",
  "occurrence": {},
  "required": false,
  "tab": "CONTENT",
  "type": "group"
 },
 {
  "default": {
   "color": null,
   "opacity": null
  },
  "display_width": null,
  "id": "f577bff8-1c57-1000-f2b9-0297e618fb2a",
  "label": "card_title_color",
  "locked": false,
  "name": "card_title_color",
  "required": false,
  "type": "color"
 },
 {
  "default": {
   "color": null,
   "opacity": null
  },
  "display_width": null,
  "id": "33968af4-9a30-8270-1df2-5ff36ebcca38",
  "label": "card_descriotion_color",
  "locked": false,
  "name": "card_descriotion_color",
  "required": false,
  "type": "color"
 },
 {
  "display": "text",
  "display_width": null,
  "id": "9c9f49bb-5a85-c6b6-395b-c8577fffac7b",
  "label": "card_description_font_size",
  "locked": false,
  "name": "card_description_font_size",
  "required": false,
  "step": 1,
  "type": "number"
 },
 {
  "default": {
   "color": null,
   "opacity": null
  },
  "display_width": null,
  "id": "7152aefd-c5cc-1ad9-9025-c6f55715d19d",
  "label": "border_color",
  "locked": false,
  "name": "border_color",
  "required": false,
  "type": "color"
 },
 {
  "display": "text",
  "display_width": null,
  "id": "1c170b7c-6ba3-2f81-7881-884f1b780fc9",
  "label": "border_width",
  "locked": false,
  "name": "border_width",
  "required": false,
  "step": 1,
  "type": "number"
 },
 {
  "default": false,
  "display": "checkbox",
  "display_width": null,
  "id": "624857cf-7d81-5530-10aa-72b51715b231",
  "label": "autoplay",
  "locked": false,
  "name": "autoplay",
  "required": false,
  "type": "boolean"
 }
]

Source Code

HTML
{% if module.section_title %}
<div class="hs-carousel-section">
  <h2 class="hs-carousel-title" style="color: {{ module.title_color.color }}; font-size: {{ module.title_font_size }}px;">
    {{ module.section_title }}
  </h2>
  
  <div class="hs-carousel-container">
    <button class="hs-carousel-nav hs-carousel-nav-prev" aria-label="前へ">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
        <path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    </button>
    
    <div class="hs-carousel-wrapper">
      <div class="hs-carousel-track">
        {% for card in module.cards %}
        <div class="hs-carousel-card" style="border-color: {{ module.border_color.color }}; border-width: {{ module.border_width }}px;">
          {% if card.image.src %}
          <div class="hs-card-image-wrapper">
            <img src="{{ card.image.src }}" alt="{{ card.image.alt }}" class="hs-card-image">
          </div>
          {% endif %}
          
          <div class="hs-card-content">
            {% if card.title %}
            <h3 class="hs-card-title" style="color: {{ module.card_title_color.color }}; font-size: {{ module.card_title_font_size }}px;">
              {{ card.title }}
            </h3>
            {% endif %}
            
            {% if card.description %}
            <p class="hs-card-description" style="color: {{ module.card_description_color.color }}; font-size: {{ module.card_description_font_size }}px;">
              {{ card.description }}
            </p>
            {% endif %}
          </div>
        </div>
        {% endfor %}
      </div>
    </div>
    
    <button class="hs-carousel-nav hs-carousel-nav-next" aria-label="次へ">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
        <path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    </button>
  </div>
  
  <div class="hs-carousel-dots"></div>
</div>
{% endif %}

<script>
(function() {
  const container = document.querySelector('.hs-carousel-section');
  if (!container) return;
  
  const track = container.querySelector('.hs-carousel-track');
  const prevBtn = container.querySelector('.hs-carousel-nav-prev');
  const nextBtn = container.querySelector('.hs-carousel-nav-next');
  const dotsContainer = container.querySelector('.hs-carousel-dots');
  const cards = container.querySelectorAll('.hs-carousel-card');
  
  const autoplay = {{ module.autoplay|lower }};
  const autoplaySpeed = {{ module.autoplay_speed || 5000 }};
  
  let currentIndex = 0;
  let autoplayInterval;
  let cardsPerView = 3;
  let totalSlides = 0;
  
  function getCardsPerView() {
    if (window.innerWidth <= 768) {
      return 1;
    } else if (window.innerWidth <= 1024) {
      return 2;
    }
    return 3;
  }
  
  function getTotalSlides() {
    return Math.ceil(cards.length / cardsPerView);
  }
  
  function createDots() {
    dotsContainer.innerHTML = '';
    totalSlides = getTotalSlides();
    
    for (let i = 0; i < totalSlides; i++) {
      const dot = document.createElement('button');
      dot.classList.add('hs-carousel-dot');
      dot.setAttribute('aria-label', 'スライド ' + (i + 1));
      dot.setAttribute('data-index', i);
      if (i === currentIndex) {
        dot.classList.add('active');
      }
      dot.addEventListener('click', function() {
        const index = parseInt(this.getAttribute('data-index'));
        goToSlide(index);
      });
      dotsContainer.appendChild(dot);
    }
  }
  
  function updateDots() {
    const allDots = dotsContainer.querySelectorAll('.hs-carousel-dot');
    allDots.forEach(function(dot, index) {
      if (index === currentIndex) {
        dot.classList.add('active');
      } else {
        dot.classList.remove('active');
      }
    });
  }
  
  function updateCarousel() {
    cardsPerView = getCardsPerView();
    totalSlides = getTotalSlides();
    
    if (currentIndex >= totalSlides) {
      currentIndex = totalSlides - 1;
    }
    if (currentIndex < 0) {
      currentIndex = 0;
    }
    
    const cardWidth = 100 / cardsPerView;
    const offset = -(currentIndex * cardWidth * cardsPerView);
    track.style.transform = 'translateX(' + offset + '%)';
    
    updateDots();
  }
  
  function goToSlide(index) {
    totalSlides = getTotalSlides();
    if (index >= 0 && index < totalSlides) {
      currentIndex = index;
      updateCarousel();
      resetAutoplay();
    }
  }
  
  function nextSlide() {
    totalSlides = getTotalSlides();
    if (currentIndex >= totalSlides - 1) {
      currentIndex = 0;
    } else {
      currentIndex++;
    }
    updateCarousel();
  }
  
  function prevSlide() {
    totalSlides = getTotalSlides();
    if (currentIndex <= 0) {
      currentIndex = totalSlides - 1;
    } else {
      currentIndex--;
    }
    updateCarousel();
  }
  
  function resetAutoplay() {
    if (autoplay) {
      clearInterval(autoplayInterval);
      autoplayInterval = setInterval(nextSlide, autoplaySpeed);
    }
  }
  
  function init() {
    cardsPerView = getCardsPerView();
    totalSlides = getTotalSlides();
    currentIndex = 0;
    createDots();
    updateCarousel();
  }
  
  init();
  
  prevBtn.addEventListener('click', function() {
    prevSlide();
    resetAutoplay();
  });
  
  nextBtn.addEventListener('click', function() {
    nextSlide();
    resetAutoplay();
  });
  
  if (autoplay) {
    autoplayInterval = setInterval(nextSlide, autoplaySpeed);
  }
  
  container.addEventListener('mouseenter', function() {
    if (autoplay) clearInterval(autoplayInterval);
  });
  
  container.addEventListener('mouseleave', function() {
    resetAutoplay();
  });
  
  let resizeTimer;
  window.addEventListener('resize', function() {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function() {
      const oldCardsPerView = cardsPerView;
      cardsPerView = getCardsPerView();
      
      if (oldCardsPerView !== cardsPerView) {
        currentIndex = 0;
        createDots();
      }
      updateCarousel();
    }, 250);
  });
})();
</script>
CSS
.hs-carousel-section {
  max-width: 1200px;
  margin: 0 auto;
  padding: 40px 20px;
  box-sizing: border-box;
}
.hs-carousel-title {
  text-align: center;
  margin: 0 0 40px 0;
  font-weight: bold;
  line-height: 1.2;
}
.hs-carousel-container {
  position: relative;
  padding: 0 60px;
  width: 100%;
  box-sizing: border-box;
  margin: 0 auto;
}
.hs-carousel-wrapper {
  overflow: hidden;
  margin-bottom: 30px;
  width: 100%;
  position: relative;
}
.hs-carousel-track {
  display: flex;
  transition: transform 0.5s ease;
  will-change: transform;
}
.hs-carousel-card {
  flex: 0 0 calc(33.333% - 16px);
  background: #fff;
  border-radius: 12px;
  border-style: solid;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  margin-right: 24px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}
.hs-carousel-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.hs-card-image-wrapper {
  width: 100%;
  height: 200px;
  overflow: hidden;
  background: #f5f5f5;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.hs-card-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 20px;
  display: block;
}
.hs-card-content {
  padding: 24px;
  flex-grow: 1;
  display: flex;
  flex-direction: column;
}
.hs-card-title {
  margin: 0 0 12px 0;
  font-weight: 600;
  line-height: 1.4;
}
.hs-card-description {
  margin: 0;
  line-height: 1.6;
}
.hs-carousel-nav {
  position: absolute !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  background: #fff !important;
  border: 2px solid #ddd !important;
  border-radius: 50% !important;
  width: 48px !important;
  height: 48px !important;
  min-width: 48px !important;
  min-height: 48px !important;
  max-width: 48px !important;
  max-height: 48px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  cursor: pointer !important;
  transition: all 0.3s ease !important;
  z-index: 100 !important;
  color: #333 !important;
  padding: 0 !important;
  margin: 0 !important;
  font-size: 16px !important;
  line-height: 1 !important;
  text-decoration: none !important;
  outline: none !important;
  box-sizing: border-box !important;
  flex-shrink: 0 !important;
}
.hs-carousel-nav:hover {
  background: #f5f5f5 !important;
  border-color: #999 !important;
}
.hs-carousel-nav:focus {
  outline: 2px solid #fed500 !important;
  outline-offset: 2px !important;
}
.hs-carousel-nav-prev {
  left: 0 !important;
  right: auto !important;
}
.hs-carousel-nav-next {
  right: 0 !important;
  left: auto !important;
}
.hs-carousel-nav svg {
  pointer-events: none;
  display: block;
  width: 24px;
  height: 24px;
}
.hs-carousel-nav svg path {
  stroke: #333 !important;
}
.hs-carousel-dots {
  display: flex;
  justify-content: center;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 20px;
  padding: 0;
}
.hs-carousel-dot {
  width: 12px !important;
  height: 12px !important;
  min-width: 12px !important;
  min-height: 12px !important;
  max-width: 12px !important;
  max-height: 12px !important;
  border-radius: 50% !important;
  background: #ddd !important;
  border: none !important;
  cursor: pointer !important;
  transition: all 0.3s ease !important;
  padding: 0 !important;
  margin: 0 !important;
  flex-shrink: 0 !important;
  display: block !important;
  box-sizing: border-box !important;
}
.hs-carousel-dot.active {
  background: #fed500 !important;
  width: 32px !important;
  min-width: 32px !important;
  max-width: 32px !important;
  height: 12px !important;
  min-height: 12px !important;
  max-height: 12px !important;
  border-radius: 6px !important;
}
.hs-carousel-dot:hover {
  background: #bbb !important;
}
.hs-carousel-dot:hover.active {
  background: #fed500 !important;
}
@media (max-width: 1024px) {
  .hs-carousel-card {
    flex: 0 0 calc(50% - 12px);
  }
  .hs-carousel-container {
    padding: 0 50px;
  }
}
@media (max-width: 768px) {
  .hs-carousel-card {
    flex: 0 0 calc(100% - 24px);
  }
  .hs-carousel-container {
    padding: 0 50px;
  }
  .hs-carousel-nav {
    width: 40px !important;
    height: 40px !important;
    min-width: 40px !important;
    min-height: 40px !important;
    max-width: 40px !important;
    max-height: 40px !important;
  }
  .hs-carousel-nav svg {
    width: 20px;
    height: 20px;
  }
}
Javascript

FAQ

スマートフォンでは1枚ずつ表示されますか?

はい。画面幅に応じて自動調整されるレスポンシブ機能を内蔵しており、PCでは複数枚、スマートフォンでは1枚と、デバイスに最適な表示数に切り替わります。

スライドが自動で動くスピードは変えられますか?

可能です。コード内の設定数値を変更することで、スライドが切り替わる間隔を調整できます。

カードの枠線を消すことはできますか?

エディターの「border_width」の値を0に設定するか、枠線の色を「透明」に指定することで、枠線のないフラットなデザインに変更できます。