star back image
people4
電飾 電飾
moon
astronaut

【cookie】ジェンダー切り替えボタン

BLOG WEBログ
読了約:46分

ECサイトのTOPページで、女性と男性でビジュアルを切り替えたいとお話がありました。デザインにはそのためのボタンがドーンと配置されています。

ボタンでメインビジュアルを差し替えると言う、そんなは要件はありますか?

メニューで女性ページ男性ページに飛ばすのではなくですか?

はい。TOPページだけの専用のボタンで切り替えます。

犬と猫とか、白と黒とかで切り替える、みたいな感じ。

説明が難しいのでサンプルをご確認ください。

めずらしいなと思いつつ、出番はなさそうなので忘れ去られる前に、せっかく実装したので保管しようと思いました。

【共有】ソースコード

作成のサンプルイメージです。
Cookieを採用していて、ジェンダー切り替えをするとページをリロードしても選択ジェンダーが担保されて、再表示されます。

切り替えイメージ

要件は以下です。

  • 初期表示はWOMENを表示
  • WOMEN/MENボタンを押したら表示が切り替わる
  • ページを再表示しても選択していたボタンのジェンダーを担保していたい(Cookie)
  • 切り替えたい所 1:swiperスライダー
  • 切り替えたい所 2:swiper下のバナー
ジェンダー切り替えボタン
https://astrowave.jp/amnesia_record/gender_cookie.php

健忘録リスト

swiper

<!-- Swiper CSS -->
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">
<!-- Swiper JS -->
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>

読みこませるのを忘れずに。

html

<div class="l_body__main">
  <div class="wp_box">
    <h3 class="p-top-onebanner__title">ボタン</h3>

    <!-- gender -->
    <ul class="gender">
      <li><a href="#" class="gender-btn active" data-gender="women"><span>WOMEN</span></a></li>
      <li><a href="#" class="gender-btn" data-gender="men"><span>MEN</span></a></li>
    </ul>

    <h3 class="p-top-onebanner__title">スライダー</h3>

    <!-- swiper -->
    <div class="p-top-hero__slider swiper c-slider-hero js-slider-hero2">
      <div class="swiper-wrapper">
        <!-- 各スライド -->
        <div class="swiper-slide">
          <div class="gender-switch-wrapper">
            <!-- スライドコンテンツ -->
            <div class="gender-content gender-women is-active">
              <div class="c-slider-hero__image">
                <picture>
                  <source srcset="./img/image_fx_1_women.jpg" media="(max-width: 767px)">
                  <img src="./img/image_fx_1_women.jpg" alt="">
                </picture>
              </div>
              <div class="c-slider-hero__content">
                <a class="c-link-parent" href="/amnesia_record/gender_cookie.php">
                  <h2 class="c-slider-hero__title u-font-en-h1">WOMENS COLLECTION</h2>
                  <div class="c-slider-hero__button">
                    <span class="c-link-parent__button">もっと見る</span>
                  </div>
                  </a>
              </div>
            </div>
            <div class="gender-content gender-men">
              <div class="c-slider-hero__image">
                <picture>
                  <source srcset="./img/image_fx_1_men2.jpg" media="(max-width: 767px)">
                  <img src="./img/image_fx_1_men2.jpg" alt="">
                </picture>
              </div>
              <div class="c-slider-hero__content">
                <a class="c-link-parent" href="/amnesia_record/gender_cookie.php">
                  <h2 class="c-slider-hero__title u-font-en-h1">MENS COLLECTION</h2>
                  <div class="c-slider-hero__button">
                    <span class="c-link-parent__button">もっと見る</span>
                  </div>
                  </a>
              </div>
            </div>
          </div>
        </div>
        <!-- 各スライド -->
        <div class="swiper-slide">
          <div class="gender-switch-wrapper">
            <!-- スライドコンテンツ -->
            <div class="gender-content gender-women is-active">
              <div class="c-slider-hero__image">
                <picture>
                  <source srcset="./img/image_fx_1_women2.jpg" media="(max-width: 767px)">
                  <img src="./img/image_fx_1_women2.jpg" alt="">
                </picture>
              </div>
              <div class="c-slider-hero__content">
                <a class="c-link-parent" href="/amnesia_record/gender_cookie.php">
                  <h2 class="c-slider-hero__title u-font-en-h1">WOMENS COLLECTION</h2>
                  <div class="c-slider-hero__button">
                    <span class="c-link-parent__button">もっと見る</span>
                  </div>
                  </a>
              </div>
            </div>
            <div class="gender-content gender-men">
              <div class="c-slider-hero__image">
                <picture>
                  <source srcset="./img/image_fx_1_men.jpg" media="(max-width: 767px)">
                  <img src="./img/image_fx_1_men.jpg" alt="">
                </picture>
              </div>
              <div class="c-slider-hero__content">
                <a class="c-link-parent" href="/amnesia_record/gender_cookie.php">
                  <h2 class="c-slider-hero__title u-font-en-h1">MENS COLLECTION</h2>
                  <div class="c-slider-hero__button">
                    <span class="c-link-parent__button">もっと見る</span>
                  </div>
                  </a>
              </div>
            </div>
          </div>
        </div>
      </div>
      
      <!-- ページネーション -->
      <div class="c-slider-hero__pagination c-slider-hero__pagination--white js-slider-pagination"></div>
      
      <!-- ナビゲーションボタン(オプション) -->
      <div class="c-slider-hero__arrow c-slider-hero__arrow--prev js-slider-prev"></div>
      <div class="c-slider-hero__arrow c-slider-hero__arrow--next js-slider-next"></div>
    </div>

    <h3 class="p-top-onebanner__title">バナー</h3>

    <!-- バナー -->
    <div class="gender-switch-wrapper p-top-onebanner__image">
      <div class="gender-content gender-women is-active" style="opacity: 1; visibility: visible; pointer-events: auto;">
        <!-- WOMEN用の内容 -->
        <a href="/amnesia_record/gender_cookie.php">
          <picture>
            <source srcset="./img/image_fx_1_women.jpg" media="(max-width: 767px)">
            <img src="./img/image_fx_1_women.jpg" alt="">
          </picture>
          <div class="p-top-onebanner__content">
            <h3 class="p-top-onebanner__subtitle">
              <p class=" typesquare_option">WOMENS ITEMS</p></h3><div class="p-top-onebanner__button">
              <span class="c-link">
                もっと見る</span>
            </div>
          </div>
        </a>
      </div>
      <div class="gender-content gender-men" style="opacity: 0; visibility: hidden; pointer-events: none;">
        <!-- MEN用の内容 -->
        <a href="/amnesia_record/gender_cookie.php">
          <picture>
          <source srcset="./img/image_fx_1_men2.jpg" media="(max-width: 767px)">
          <img src="./img/image_fx_1_men2.jpg" alt="">
          </picture>
          <div class="p-top-onebanner__content">
            <h3 class="p-top-onebanner__subtitle">
              <p class=" typesquare_option">MENS ITEMS</p></h3><div class="p-top-onebanner__button">
              <span class="c-link">
                もっと見る</span>
            </div>
          </div>
        </a>
      </div>
    </div>

  </div>
</div>

ボタンとswiperとバナーが配置されます。

css

cssがとても長いので、
このページのスクロール量が大変になるので省略です。
>>サンプルページの750行目より確認ください。

heroSlider_readable.jsファイル(swiper用)

// heroSlider_readable.js
// 可読化+ページネーションアニメーション付き

let paginationAnimationId;

function animatePaginationSmooth(activeBullet, duration = 7000) {
  if (!activeBullet) return;
  let start = null;
  if (paginationAnimationId) {
    cancelAnimationFrame(paginationAnimationId);
  }
  function step(timestamp) {
    if (!start) start = timestamp;
    const elapsed = timestamp - start;
    const progress = Math.min((elapsed / duration) * 100, 100);
    activeBullet.style.background = `conic-gradient(#FFF 0%, #FFF ${progress}%, transparent ${progress}%, transparent 100%)`;
    if (elapsed < duration) {
      paginationAnimationId = requestAnimationFrame(step);
    } else {
      activeBullet.style.background = `conic-gradient(#FFF 0%, #FFF 100%, transparent 100%, transparent 100%)`;
    }
  }
  paginationAnimationId = requestAnimationFrame(step);
}

function heroSliderWithPaginationAnimation() {
  // Swiperライブラリが利用可能かチェック
  if (typeof Swiper === 'undefined') {
    console.log('Swiper library not loaded');
    return;
  }
  
  const heroSliders = document.querySelectorAll('.js-slider-hero2'); // 必要に応じてクラス名を調整
  
  // heroSlidersが存在し、forEachが利用可能かチェック
  if (!heroSliders || heroSliders.length === 0) {
    console.log('heroSliders not found');
    return;
  }
  
  // forEachの代わりにforループを使用(より安全)
  for (let i = 0; i < heroSliders.length; i++) {
    const sliderWrapper = heroSliders[i];
    // sliderWrapper自体がスライダーコンテナなので、直接使用
    const slider = sliderWrapper;
    const slides = slider ? slider.querySelectorAll('.swiper-slide') : [];
    const pagination = sliderWrapper.querySelector('.js-slider-pagination');
    const prev = sliderWrapper.querySelector('.js-slider-prev');
    const next = sliderWrapper.querySelector('.js-slider-next');
    
    // 必要な要素が存在しない場合はスキップ
    if (!slider || !slides || slides.length === 0) {
      console.log('Required slider elements not found', {
        slider: !!slider,
        slides: slides ? slides.length : 0,
        pagination: !!pagination,
        prev: !!prev,
        next: !!next
      });
      continue;
    }
    
    console.log('Initializing Swiper with:', {
      slides: slides.length,
      pagination: !!pagination,
      prev: !!prev,
      next: !!next
    });
    
    if (slides.length <= 1) {
      if (prev) prev.classList.add('is-hidden');
      if (next) next.classList.add('is-hidden');
      continue;
    }
    const autoplayDelay = 4000;
    const swiper = new Swiper(slider, {
      speed: 900,
      slidesPerView: 1,
      loop: true,
      threshold: 10,
      pagination: {
        el: pagination,
        clickable: true
      },
      navigation: {
        nextEl: next,
        prevEl: prev
      },
      autoplay: {
        delay: autoplayDelay,
        disableOnInteraction: false,
        waitForTransition: true
      },
      simulateTouch: true,
      touchRatio: 1,
      grabCursor: true
    });
    
    console.log('Swiper initialized successfully:', swiper);

    function startPaginationAnimation() {
      document.querySelectorAll('.swiper-pagination-bullet').forEach(bullet => {
        bullet.style.background = '';
      });
      const activeBullet = pagination.querySelector('.swiper-pagination-bullet-active');
      animatePaginationSmooth(activeBullet, autoplayDelay);
    }

    // スライド切り替え開始時にタイトルをフェードアウト
    swiper.on('slideChangeTransitionStart', function() {
      slider.classList.add('is-transition');
    });

    // スライド切り替え完了時にタイトルをふわっと表示
    swiper.on('slideChangeTransitionEnd', function() {
      setTimeout(function() {
        slider.classList.remove('is-transition');
      }, 0);
    });

    swiper.on('autoplay', startPaginationAnimation);
    swiper.on('slideChange', startPaginationAnimation);
    swiper.on('paginationUpdate', startPaginationAnimation);

    startPaginationAnimation();

    // 初期表示時に最初のスライドのタイトルをふわっと表示
    slider.classList.add('is-transition');
    
    // 500ms後に最初のスライドのタイトルを表示
    setTimeout(function() {
      slider.classList.remove('is-transition');
    }, 500);
  }
}

window.addEventListener('DOMContentLoaded', function() {
  console.log('DOMContentLoaded event fired');
  heroSliderWithPaginationAnimation();
});

好きなように変えてください。

javascript

ジェンダー切り替え動作と、Cookieの設定のスクリプトです。

<script>
// Cookie操作のヘルパー関数
function setCookie(name, value, days) {
  var expires = "";
  if (days) {
    var date = new Date();
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
    expires = "; expires=" + date.toUTCString();
  }
  document.cookie = name + "=" + value + expires + "; path=/";
}

function getCookie(name) {
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ') c = c.substring(1, c.length);
    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
  }
  return null;
}

// ジェンダー切り替えの状態を保存する関数
function saveGenderState(gender) {
  setCookie('selected_gender', gender, 30); // 30日間保持
}

// Cookieをクリアする関数
function clearAllCookies() {
  // 特定のCookieを削除
  setCookie('selected_gender', '', -1); // 過去の日付で削除
  setCookie('number', '', -1); // 過去の日付で削除
  
  // ページをリロードしてデフォルト状態に戻す
  location.reload();
}

// ジェンダー切り替えの状態を復元する関数
function restoreGenderState() {
  var savedGender = getCookie('selected_gender');
  if (savedGender && (savedGender === 'women' || savedGender === 'men')) {
    return savedGender;
  }
  return 'women'; // デフォルトはwomen
}

// ジェンダー切り替えの表示を更新する関数
function updateGenderDisplay(gender) {
  // ボタンの状態を更新
  var genderBtns = document.querySelectorAll('.gender-btn');
  genderBtns.forEach(function(btn) {
    if (btn.getAttribute('data-gender') === gender) {
      btn.classList.add('active');
    } else {
      btn.classList.remove('active');
    }
  });

  // コンテンツの表示を更新(ページ全体のすべてのgender-switch-wrapperを対象)
  document.querySelectorAll('.gender-switch-wrapper').forEach(function(wrapper) {
    var all = wrapper.querySelectorAll('.gender-content');
    var target = wrapper.querySelector('.gender-content.gender-' + gender);
    if (target && all.length > 0) {
      fadeSwitch(target, all);
    }
  });
  
  // デバッグ用ログ(開発時のみ)
  if (window.location.hostname === 'localhost' || window.location.hostname.includes('dev')) {
    console.log('Gender updated to:', gender, 'Found wrappers:', document.querySelectorAll('.gender-switch-wrapper').length);
  }
}

// ジェンダー切り替え
function fadeSwitch(target, all) {
  if (!target || !all || all.length === 0) return;
  
  all.forEach(function(el) {
    if (el === target) {
      el.classList.add('is-active');
      el.style.opacity = '1';
      el.style.visibility = 'visible';
      el.style.pointerEvents = 'auto';
    } else {
      el.classList.remove('is-active');
      el.style.opacity = '0';
      el.style.visibility = 'hidden';
      el.style.pointerEvents = 'none';
    }
  });
}

document.addEventListener('DOMContentLoaded', function() {
  // URLパラメータを優先し、なければCookieから復元
  var urlParams = new URLSearchParams(window.location.search);
  var urlGender = urlParams.get('gender');
  
  var currentGender;
  if (urlGender && (urlGender === 'women' || urlGender === 'men')) {
    // URLパラメータがある場合はそれを優先
    currentGender = urlGender;
    // URLパラメータの状態もCookieに保存
    saveGenderState(currentGender);
  } else {
    // URLパラメータがない場合はCookieから復元
    currentGender = restoreGenderState();
  }
  
  // ページ全体のgender表示を更新
  updateGenderDisplay(currentGender);

  // ジェンダーボタンのクリックイベント
  var genderBtns = document.querySelectorAll('.gender-btn');
  genderBtns.forEach(function(btn) {
    btn.addEventListener('click', function(e) {
      e.preventDefault();
      
      var gender = this.getAttribute('data-gender');
      
      // ページ全体の表示を更新
      updateGenderDisplay(gender);
      
      // 状態をCookieに保存
      saveGenderState(gender);
    });
  });

  // Cookieクリアボタンのクリックイベント
  var clearCookieBtn = document.getElementById('clearCookieBtn');
  if (clearCookieBtn) {
    clearCookieBtn.addEventListener('click', function(e) {
      e.preventDefault();
      
      // 確認ダイアログを表示
      if (confirm('保存された設定をクリアしますか?\nこの操作は元に戻せません。')) {
        clearAllCookies();
      }
    });
  }
});

// ページ読み込み完了後に再度表示を更新(他のセクションの読み込み完了を待つ)
window.addEventListener('load', function() {
  var currentGender = restoreGenderState();
  updateGenderDisplay(currentGender);
});
</script>

ボタンを押したらWOMEN/MENの要素へ交互にis-activeのクラスが差し代わるようですね。

はい。Cookieの保存は30日間にしています。

オプション

以下のようにURLに?パラメータを追加でアクセスすると、指定したジェンダーで表示されるようにしてます。

WOMEN表示: gender_cookie.php?gender=women
MEN表示: gender_cookie.php?gender=men


// URLパラメータを優先し、なければCookieから復元
var urlParams = new URLSearchParams(window.location.search);
var urlGender = urlParams.get('gender');

if (urlGender && (urlGender === 'women' || urlGender === 'men')) {
// URLパラメータがある場合はそれを優先
currentGender = urlGender;
// URLパラメータの状態もCookieに保存
saveGenderState(currentGender);
} else {
// URLパラメータがない場合はCookieから復元
currentGender = restoreGenderState();
}

MENの表示になるURL
https://astrowave.jp/amnesia_record/gender_cookie.php?gender=men

以上になります。

【AI】イラストを描いてもらった

今回の記事のキャッチ画像で使わせてもらいます「Google ImageFX」で作成した画像です。誰でもgoogleアカウントでログインして使えます。

この記事にピッタリなイラストのための考えたリクエストは、
「遺跡の祭壇でクリスタルに触れた時、眩しい光と共に目の前に、過去と未来の出来事が無限スクロールするように流れる様に驚く探検家。スクロール映像に寄りで、探検家は上半身の画角。探検家を女性に。」です。

トゥームレイダーみたいなの好きです。

星間旅路のメロディ

「宇宙の静けさに包まれながら、漂流する過去の音楽を捜し求め、銀河の奥底でその旋律に耳を傾ける。」

「この電波はどこの星からきたのだろうか。」

ロケットに乗って、重力ターンするのだ!

「【cookie】ジェンダー切り替えボタン」への1件のフィードバック

コメントは受け付けていません。