HubSpotモジュール:ファーストビュー1

これは、ページの最上部(「ファーストビュー」)に配置するモジュールで、製品やサービスの第一印象を形作ります。

背景画像の上に 力強いキャッチコピーとコールトゥアクション(CTA) をシンプルに配置したいときに使用します。
ヒーローセクションの共通要素を素早く設定するのに最適です。

Demo Video

Detail

利用目的

背景画像の上に、力強いキャッチコピーコールトゥアクション(CTA) をシンプルに配置したい場合に使用します。
ヒーローセクションの共通要素を素早く設定するのに最適です。

実現できること

  • 背景画像の設定
  • メインキャッチコピー(見出し)の追加
  • キャッチコピーを補足する説明文の追加
  • CTA ボタンの設置
  • CTA ボタン下に補足文を追加(例: 「いつでも解約可能」「クレジットカード不要」など)

実装ポイント & 注意事項

  • フィールド構成:
    このモジュールは以下のフィールドを組み合わせて構成します。
    • Image フィールド(背景用)
    • Text フィールド(キャッチコピー用)
    • Rich text フィールド(説明文用)
    • CTA フィールド(ボタン用)
    • Text フィールド(ボタン補足文用)
    • Choice フィールド(PC 表示時のテキスト配置)
  • 配置上の注意:
    デスクトップビューでは、テキストブロック(キャッチコピー・説明・ボタン)の横位置(左/中央/右)を調整できますが、モバイルビューでは 標準位置(例: 中央揃え)に固定され、可読性を優先します。

フィールド設定例

  1. background_image
    • フィールドタイプ: image
  2. text_alignment
    • フィールドタイプ: Choice
    • 値: left, center, right

  1. horizontal_position
    • フィールドタイプ: number
  2. vertical_position
    • フィールドタイプ: number
  3. main_headline
    • フィールドタイプ: text
  4. description
    • フィールドタイプ: rich text
  5. show_cta_bubble
    • フィールドタイプ: boolean
  6. cta_text
    • フィールドタイプ: text
  7. button_label
    • フィールドタイプ: text
  8. button_link
    • フィールドタイプ: link

Source Code

HTML
<section class="sales-hero" 
         style="background-image: url('{{ module.background_image.src }}');" 
         data-module-id="{{ module_id }}"
         data-horizontal-position="{{ module.horizontal_position or 50 }}"
         data-vertical-position="{{ module.vertical_position or 50 }}">
  <div class="hero-container" 
       style="--horizontal-position: {{ module.horizontal_position or 50 }}%; --vertical-position: {{ module.vertical_position or 50 }}%;">
    
    <div class="hero-content hero-content--{{ module.text_alignment or 'center' }}">
      <h1 class="company-name">{{ module.company_name }}</h1>
      
      <h2 class="main-headline">{{ module.main_headline }}</h2>
      
      <div class="description">
        {% inline_rich_text field="description" value="{{ module.description }}" %}
      </div>
      
      <div class="cta-section">
        {% if module.show_cta_bubble and module.cta_text %}
        <div class="cta-bubble">
          <p class="cta-text">{{ module.cta_text }}</p>
        </div>
        {% endif %}
        
        <a href="{{ module.button_link }}" class="cta-button">
          <span class="button-text">{{ module.button_label }}</span>
        </a>
      </div>
    </div>
    
  </div>
</section>
{{ require_css("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css") }}

CSS
/* ==================================
   Sales Hero Module Styles
   ================================== */
.sales-hero {
  position: relative;
  min-height: 600px;
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  background-attachment: scroll;
  color: white;
  overflow: hidden;
}

/* Main Container */
.hero-container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 80px 20px;
  width: 100%;
  height: 100%;
}

.hero-container::before {
  content: '';
  position: absolute;
  top: var(--vertical-position, 50%);
  left: var(--horizontal-position, 50%);
  transform: translate(-50%, -50%);
  width: 1px;
  height: 1px;
  z-index: 1;
}

/* ==================================
   Content Section
   ================================== */
.hero-content {
  position: absolute;
  top: var(--vertical-position, 50%);
  left: var(--horizontal-position, 50%);
  transform: translate(-50%, -50%);
  max-width: 600px;
  min-width: 300px;
  z-index: 3;
}

/* Text Alignment Options */
.hero-content--left {
  text-align: left;
}
.hero-content--center {
  text-align: center;
}
.hero-content--right {
  text-align: right;
}

/* Company Name */
.company-name {
  font-size: 38px;
  font-weight: 700;
  margin: 0 0 15px 0;
  color: white;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  letter-spacing: -0.5px;
  animation: fadeInUp 0.8s ease-out;
}

/* Main Headline */
.main-headline {
  font-size: 42px;
  font-weight: 700;
  margin: 0 0 25px 0;
  line-height: 1.3;
  color: white;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  letter-spacing: -0.5px;
  animation: fadeInUp 0.8s ease-out 0.2s both;
}

/* Description */
.description {
  font-size: 18px;
  line-height: 1.7;
  margin: 0 0 50px 0;
  opacity: 0.95;
  font-weight: 400;
  animation: fadeInUp 0.8s ease-out 0.4s both;
}

/* Rich text elements styling */
.description p {
  margin-bottom: 1em;
}
.description strong {
  font-weight: 700;
}
.description em {
  font-style: italic;
}

/* ==================================
   CTA Section
   ================================== */
.cta-section {
  position: relative;
  animation: fadeInUp 0.8s ease-out 0.6s both;
  display: flex;
  flex-direction: column;
}

/* Alignment for CTA section */
.hero-content--left .cta-section {
  align-items: flex-start;
}
.hero-content--center .cta-section {
  align-items: center;
}
.hero-content--right .cta-section {
  align-items: flex-end;
}

/* CTA Bubble */
.cta-bubble {
  background: #FFD700;
  color: #333;
  padding: 15px 22px;
  border-radius: 25px;
  margin-bottom: 20px;
  position: relative;
  max-width: 350px;
  box-shadow: 0 4px 15px rgba(255, 215, 0, 0.3);
}

.cta-bubble::after {
  content: '';
  position: absolute;
  bottom: -10px;
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 10px solid #FFD700;
}

/* Bubble arrow positioning based on alignment */
.hero-content--left .cta-bubble::after {
  left: 35px;
}
.hero-content--center .cta-bubble::after {
  left: 50%;
  transform: translateX(-50%);
}
.hero-content--right .cta-bubble::after {
  right: 35px;
}
.cta-text {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
}

/* CTA Button */
.cta-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: white;
  color: #0066CC;
  padding: 18px 35px;
  border-radius: 10px;
  text-decoration: none;
  font-weight: 700;
  font-size: 16px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
  border: none;
  cursor: pointer;
  font-family: inherit;
  min-width: 200px;
}

.cta-button:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  text-decoration: none;
  color: #004499;
  background: #f8f9ff;
}

.cta-button:active {
  transform: translateY(-1px);
  transition: all 0.1s;
}

.button-text {
  font-size: 16px;
}

/* ==================================
   Animations
   ================================== */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ==================================
   Responsive Design
   ================================== */
/* Tablet Styles */
@media (max-width: 1024px) {
  .hero-container {
    padding: 60px 30px;
  }
  
  .hero-content {
    max-width: 550px;
    min-width: 280px;
  }
  
  .main-headline {
    font-size: 36px;
  }
  
  .company-name {
    font-size: 34px;
  }
}

/* Mobile Styles */
@media (max-width: 768px) {
  .sales-hero {
    min-height: 500px;
  }
  
  .hero-container {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    height: auto;
    min-height: 500px;
    padding: 40px 20px;
  }

  /* Override position on mobile for better UX */
  .hero-content {
    position: relative !important;
    top: auto !important;
    left: auto !important;
    transform: none !important;
    max-width: 100%;
    min-width: auto;
    text-align: center !important;
  }
  
  .hero-content .cta-section {
    align-items: center !important;
  }
  
  .hero-content .cta-bubble::after {
    left: 50% !important;
    right: auto !important;
    transform: translateX(-50%) !important;
  }
  
  .main-headline {
    font-size: 32px;
    margin-bottom: 20px;
  }
  
  .company-name {
    font-size: 30px;
  }
  
  .description {
    font-size: 16px;
    margin-bottom: 35px;
  }
  
  .cta-bubble {
    max-width: 100%;
    margin-bottom: 15px;
  }
  
  .cta-button {
    padding: 16px 28px;
    font-size: 15px;
    min-width: 180px;
  }
}

/* Small Mobile Styles */
@media (max-width: 480px) {
  .hero-container {
    padding: 30px 15px;
  }
  
  .main-headline {
    font-size: 28px;
    line-height: 1.4;
  }
  
  .company-name {
    font-size: 26px;
  }
  
  .description {
    font-size: 15px;
  }
  
  .cta-text {
    font-size: 14px;
  }
  
  .cta-button {
    padding: 14px 24px;
    font-size: 14px;
    min-width: 160px;
  }
}

/* ==================================
   Optimizations & Accessibility
   ================================== */
/* High-DPI Display Optimization */
@media only screen and (-webkit-min-device-pixel-ratio: 2),
       only screen and (min--moz-device-pixel-ratio: 2),
       only screen and (-o-min-device-pixel-ratio: 2/1),
       only screen and (min-device-pixel-ratio: 2),
       only screen and (min-resolution: 192dpi),
       only screen and (min-resolution: 2dppx) {
  .sales-hero {
    image-rendering: -webkit-optimize-contrast;
    image-rendering: crisp-edges;
  }
}

/* Accessibility Enhancements */
@media (prefers-reduced-motion: reduce) {
  .sales-hero *,
  .sales-hero *::before,
  .sales-hero *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Focus Styles for Accessibility */
.cta-button:focus {
  outline: 3px solid #FFD700;
  outline-offset: 2px;
}

Javascript
/**
 * Sales Hero Module JavaScript
 * HubSpot Custom Module Enhancement Script
 */
(function() {
  'use strict';
  // Module initialization
  const SalesHero = {

    // Configuration
    config: {
      animationDelay: 100,
      observerThreshold: 0.1,
      buttonHoverDelay: 150
    },
    // Initialize the module
    init: function() {
      this.setupIntersectionObserver();
      this.enhanceButtons();
      this.trackAnalytics();
      this.setupAccessibility();

      // Wait for DOM to be fully loaded
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', this.onDOMReady.bind(this));
      } else {
        this.onDOMReady();
      }
    },
    // DOM Ready handler
    onDOMReady: function() {
      this.optimizePerformance();
      console.log('Sales Hero Module: Initialized successfully');
    },
    // Setup Intersection Observer for animation triggers
    setupIntersectionObserver: function() {
      if ('IntersectionObserver' in window) {
        const observer = new IntersectionObserver((entries) => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              entry.target.classList.add('animate-in');
              observer.unobserve(entry.target);
            }
          });
        }, {
          threshold: this.config.observerThreshold,
          rootMargin: '0px 0px -50px 0px'
        });
        // Observe hero sections
        const heroSections = document.querySelectorAll('.sales-hero');
        heroSections.forEach(section => {
          observer.observe(section);
        });
      }
    },
    // Enhance CTA buttons with advanced interactions
    enhanceButtons: function() {
      const ctaButtons = document.querySelectorAll('.cta-button');

      ctaButtons.forEach(button => {
        // Add ripple effect on click
        button.addEventListener('click', this.createRippleEffect.bind(this));

        // Enhanced hover effects
        button.addEventListener('mouseenter', this.onButtonHover.bind(this));
        button.addEventListener('mouseleave', this.onButtonLeave.bind(this));

        // Keyboard navigation enhancement
        button.addEventListener('focus', this.onButtonFocus.bind(this));
        button.addEventListener('blur', this.onButtonBlur.bind(this));
      });
    },
    // Create ripple effect for button clicks
    createRippleEffect: function(e) {
      const button = e.currentTarget;
      const rect = button.getBoundingClientRect();
      const ripple = document.createElement('span');

      const size = Math.max(rect.width, rect.height);
      const x = e.clientX - rect.left - size / 2;
      const y = e.clientY - rect.top - size / 2;

      ripple.style.cssText = `
        position: absolute;
        width: ${size}px;
        height: ${size}px;
        left: ${x}px;
        top: ${y}px;
        background: rgba(255, 255, 255, 0.3);
        border-radius: 50%;
        transform: scale(0);
        animation: ripple 0.6s ease-out;
        pointer-events: none;
        z-index: 1;
      `;

      // Add ripple animation CSS if not exists
      if (!document.getElementById('ripple-styles')) {
        const style = document.createElement('style');
        style.id = 'ripple-styles';
        style.textContent = `
          @keyframes ripple {
            to {
              transform: scale(2);
              opacity: 0;
            }
          }
          .cta-button {
            position: relative;
            overflow: hidden;
          }
        `;
        document.head.appendChild(style);
      }

      button.appendChild(ripple);

      // Remove ripple after animation
      setTimeout(() => {
        if (ripple.parentNode) {
          ripple.parentNode.removeChild(ripple);
        }
      }, 600);
    },
    // Button hover handler
    onButtonHover: function(e) {
      const button = e.currentTarget;
      const icon = button.querySelector('i');

      if (icon) {
        setTimeout(() => {
          icon.style.transform = 'translateX(5px) scale(1.1)';
        }, this.config.buttonHoverDelay);
      }
    },
    // Button leave handler
    onButtonLeave: function(e) {
      const button = e.currentTarget;
      const icon = button.querySelector('i');

      if (icon) {
        icon.style.transform = 'translateX(0) scale(1)';
      }
    },
    // Button focus handler for accessibility
    onButtonFocus: function(e) {
      const button = e.currentTarget;
      button.style.boxShadow = '0 0 0 3px rgba(255, 215, 0, 0.5), 0 10px 30px rgba(0, 0, 0, 0.25)';
    },
    // Button blur handler
    onButtonBlur: function(e) {
      const button = e.currentTarget;
      button.style.boxShadow = '0 6px 20px rgba(0, 0, 0, 0.15)';
    },
    // Performance optimizations
    optimizePerformance: function() {
      // Preload critical background images
      this.preloadCriticalImages();

      // Setup passive event listeners where appropriate
      this.setupPassiveListeners();

      // Debounce resize events
      let resizeTimeout;
      window.addEventListener('resize', () => {
        clearTimeout(resizeTimeout);
        resizeTimeout = setTimeout(this.onWindowResize.bind(this), 250);
      });
    },
    // Preload critical images
    preloadCriticalImages: function() {
      const heroSection = document.querySelector('.sales-hero');
      if (heroSection) {
        const bgImage = window.getComputedStyle(heroSection).backgroundImage;
        const imageUrl = bgImage.replace(/url\\(['"]?(.*?)['"]?\\)/i, '$1');

        if (imageUrl && imageUrl !== 'none') {
          const img = new Image();
          img.src = imageUrl;
        }
      }
    },
    // Setup passive event listeners for better performance
    setupPassiveListeners: function() {
      const heroSection = document.querySelector('.sales-hero');
      if (heroSection) {
        heroSection.addEventListener('touchstart', function() {}, {
          passive: true
        });
        heroSection.addEventListener('touchmove', function() {}, {
          passive: true
        });
      }
    },
    // Window resize handler
    onWindowResize: function() {
      // Recalculate any dynamic positioning if needed
      const ctaBubbles = document.querySelectorAll('.cta-bubble');
      ctaBubbles.forEach(bubble => {
        if (window.innerWidth <= 768) {
          // Mobile adjustments for bubble positioning
          bubble.style.maxWidth = '100%';
        } else {
          bubble.style.maxWidth = '350px';
        }
      });
    },
    // Analytics tracking
    trackAnalytics: function() {
      const ctaButtons = document.querySelectorAll('.cta-button');

      ctaButtons.forEach((button, index) => {
        button.addEventListener('click', (e) => {
          // HubSpot Analytics tracking
          if (typeof _hsq !== 'undefined') {
            _hsq.push(['trackEvent', {
              eventId: 'sales_hero_cta_click',
              value: button.href || button.getAttribute('data-href'),
              buttonText: button.textContent.trim(),
              modulePosition: index
            }]);
          }

          // Google Analytics tracking (if available)
          if (typeof gtag !== 'undefined') {
            gtag('event', 'click', {
              'event_category': 'Sales Hero Module',
              'event_label': button.textContent.trim(),
              'value': index
            });
          }

          // Custom analytics tracking
          this.sendCustomAnalytics('cta_click', {
            buttonText: button.textContent.trim(),
            buttonUrl: button.href,
            timestamp: new Date().toISOString(),
            moduleId: button.closest('.sales-hero').getAttribute('data-module-id')
          });
        });
      });

      // Track module visibility
      this.trackModuleVisibility();
    },
    // Send custom analytics
    sendCustomAnalytics: function(event, data) {
      // Only send if custom tracking is enabled
      if (window.salesHeroAnalytics && window.salesHeroAnalytics.enabled) {
        const payload = {
          event: event,
          timestamp: new Date().toISOString(),
          url: window.location.href,
          userAgent: navigator.userAgent,
          ...data
        };

        // Send to custom endpoint if configured
        if (window.salesHeroAnalytics.endpoint) {
          fetch(window.salesHeroAnalytics.endpoint, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify(payload)
          }).catch(err => {
            console.warn('Sales Hero Analytics: Failed to send data', err);
          });
        }
      }
    },
    // Track module visibility for engagement metrics
    trackModuleVisibility: function() {
      if ('IntersectionObserver' in window) {
        const visibilityObserver = new IntersectionObserver((entries) => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              const moduleId = entry.target.getAttribute('data-module-id');

              // Track module view
              if (typeof _hsq !== 'undefined') {
                _hsq.push(['trackEvent', {
                  eventId: 'sales_hero_module_viewed',
                  moduleId: moduleId
                }]);
              }

              this.sendCustomAnalytics('module_viewed', {
                moduleId: moduleId,
                visibilityRatio: entry.intersectionRatio
              });

              visibilityObserver.unobserve(entry.target);
            }
          });
        }, {
          threshold: 0.5,
          rootMargin: '0px'
        });
        const heroSections = document.querySelectorAll('.sales-hero[data-module-id]');
        heroSections.forEach(section => {
          visibilityObserver.observe(section);
        });
      }
    },
    // Setup accessibility enhancements
    setupAccessibility: function() {
      const heroSections = document.querySelectorAll('.sales-hero');

      heroSections.forEach(section => {
        // Add proper ARIA labels
        section.setAttribute('role', 'banner');
        section.setAttribute('aria-label', 'Hero section with call-to-action');

        // Enhance CTA buttons
        const ctaButton = section.querySelector('.cta-button');
        if (ctaButton) {
          // Add ARIA attributes
          ctaButton.setAttribute('role', 'button');

          // Add descriptive text for screen readers
          const buttonText = ctaButton.querySelector('.button-text');
          const icon = ctaButton.querySelector('i');

          if (buttonText && icon) {
            const ariaLabel = `${buttonText.textContent.trim()}, opens in ${ctaButton.target === '_blank' ? 'new tab' : 'same tab'}`;
            ctaButton.setAttribute('aria-label', ariaLabel);
          }

          // Add keyboard navigation support
          ctaButton.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' || e.key === ' ') {
              e.preventDefault();
              ctaButton.click();
            }
          });
        }

        // Ensure images have proper alt text
        const images = section.querySelectorAll('img');
        images.forEach(img => {
          if (!img.alt || img.alt.trim() === '') {
            console.warn('Sales Hero Module: Image missing alt text', img.src);
            img.setAttribute('role', 'presentation');
          }
        });

        // Add skip link for keyboard users
        this.addSkipLink(section);
      });
    },
    // Add skip link for accessibility
    addSkipLink: function(section) {
      const skipLink = document.createElement('a');
      skipLink.href = '#content-after-hero';
      skipLink.textContent = 'Skip to main content';
      skipLink.className = 'skip-link';
      skipLink.style.cssText = `
        position: absolute;
        top: -40px;
        left: 6px;
        background: #000;
        color: #fff;
        padding: 8px;
        text-decoration: none;
        z-index: 1000;
        border-radius: 4px;
        font-size: 14px;
        transition: top 0.3s;
      `;

      skipLink.addEventListener('focus', function() {
        this.style.top = '6px';
      });

      skipLink.addEventListener('blur', function() {
        this.style.top = '-40px';
      });

      section.insertBefore(skipLink, section.firstChild);
    },
    // Error handling and fallbacks
    handleErrors: function() {
      window.addEventListener('error', (e) => {
        if (e.target.tagName === 'IMG' && e.target.closest('.sales-hero')) {
          console.warn('Sales Hero Module: Image error handled', e.target.src);
          e.target.style.display = 'none';
        }
      });
    },
    // Module cleanup (useful for SPA applications)
    cleanup: function() {
      // Remove event listeners to prevent memory leaks
      const ctaButtons = document.querySelectorAll('.cta-button');
      ctaButtons.forEach(button => {
        button.replaceWith(button.cloneNode(true));
      });

      console.log('Sales Hero Module: Cleaned up successfully');
    },
    // Development helpers
    debug: function() {
      if (window.location.search.includes('hero-debug=true')) {
        const debugInfo = {
          modules: document.querySelectorAll('.sales-hero').length,
          buttons: document.querySelectorAll('.cta-button').length,
          images: document.querySelectorAll('.sales-hero img').length,
          hasIntersectionObserver: 'IntersectionObserver' in window,
          performance: performance.now()
        };

        console.table(debugInfo);

        // Add visual debug indicators
        document.querySelectorAll('.sales-hero').forEach((section, index) => {
          const debugBadge = document.createElement('div');
          debugBadge.textContent = `Hero Module ${index + 1}`;
          debugBadge.style.cssText = `
            position: absolute;
            top: 10px;
            right: 10px;
            background: red;
            color: white;
            padding: 5px 10px;
            font-size: 12px;
            z-index: 9999;
            border-radius: 3px;
          `;
          section.appendChild(debugBadge);
        });
      }
    }
  };
  // Auto-initialize when DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function() {
      SalesHero.init();
      SalesHero.debug();
    });
  } else {
    SalesHero.init();
    SalesHero.debug();
  }
  // Expose module for external access
  window.SalesHeroModule = SalesHero;
  // Handle page visibility changes (for analytics)
  document.addEventListener('visibilitychange', function() {
    if (document.hidden) {
      SalesHero.sendCustomAnalytics('page_hidden', {
        timeOnPage: performance.now()
      });
    } else {
      SalesHero.sendCustomAnalytics('page_visible', {
        returnTime: performance.now()
      });
    }
  });
})();