LP: 初心者向け紅茶特集サイト①フロントエンド(カート機能・カルーセル・画像&サイトデザイン)

※アイキャッチ画像はフロントエンドのデザインが完成次第、後ほど本実装デザインと差し替え予定。(この暫定の画像も含め、当サイトのアイキャッチ画像は全て自作。)

関連記事:

LP: 初心者向け紅茶特集サイト①フロントエンド(カート機能・カルーセル・画像&サイトデザイン)

LP: 初心者向け紅茶特集サイト ②バックエンド(決済機能・メール送信機能)

概要

以下のデザインお題サイトに掲載されていたものを参考に制作した。

出典: https://note.com/mifu_sensei/n/nbe23f60530f9

また、カート・決済処理機能や問い合わせメールの送信など、商品購入のLPに必要な最低限の機能も実装した。

LPの以下のリンクは以下の通り:

紅茶特集

デザインの工夫

Comming soon…

技術的な観点

開発環境

ConoHa VPSへのデプロイ以前は、XAMPPのローカルサーバーにて開発を進めていた。

デザインやフロントエンドの実装は殆ど全てローカルサーバーにて行った。

決済機能で用いたStripeはSSL化済みのドメインのサーバーでのみ使用可能であることが判明し、当ポートフォリオサイトで使用のConoHa VPSサーバーにLPを移行し、こちらで使用のドメインにサブドメインを設けて運用。

使用ツール・言語(デザイン・フロントエンドのみ)

  • HTML・CSS: サイトの見た目は殆どこれらのコーディングにて実装。
  • JavaScript: 商品追加やモーダル表示など主にカート機能の実装に使用。
  • Bootstrap: レスポンシブ対応のメニューの実装に使用。
  • Swiper: カスタマーレビューのカルーセルに使用。
  • Photoshop: 商品やFVの画像のレタッチに使用。

技術的試行錯誤

カート機能の実装

  1. 商品番号の挿入: それぞれの商品カード内のHTMLにdata-product-idを用いて、個数選択ボタン及びカート追加ボタンに同じ商品番号を設置。
  2. 関数呼び出し: ボタンがクリックされたらonclickで個数追加・減少の関数(increaseQuantity、decreaseQuantity)を呼び出す
  3. 商品内容の処理: 関数側で渡された番号・商品名などを参照して処理

商品カード内での関連コード:

<div class="item_price_cart">
  <input type="hidden" name="id" value="5" >
  <div style="display:flex; align-items: center;">
      <button type="button" onclick="decreaseQuantity(this)" data-product-id="5">
        <i class="fa-solid fa-minus"></i>
      </button>
      <input type="number" id="quantity-5" value="1" min="1">
      <button type="button" onclick="increaseQuantity(this)" data-product-id="5">
        <i class="fa-solid fa-plus"></i>
      </button>
  </div>                            
  <button class="cart_button" type="button" onclick="addToCart(5, 'ワイルドフォレスト', 850, event)">             カートに入れる
  </button>
</div>

JavaScriptの関数:

// 以下商品個数ボタン
function increaseQuantity(button){
    const productId = button.dataset.productId;
    const input = document.querySelector(`#quantity-${productId}`);
    let currentValue = parseInt(input.value) || 0;
    input.value = currentValue + 1;
}
function decreaseQuantity(button){
    const productId = button.dataset.productId;
    const input = document.querySelector(`#quantity-${productId}`);
    let currentValue = parseInt(input.value) || 0;
    if(currentValue > 1){
        input.value = currentValue - 1;
    }
}
//以下カート追加ボタン
function addToCart(id, name, price, event){
    event.preventDefault();
    const quantityInput = document.querySelector(`#quantity-${id}`);
    const quantity = parseInt(quantityInput.value) || 1;
    let cart = JSON.parse(localStorage.getItem('cart')) || [];
    const existingItem = cart.find(item => item.id === id);
    if(existingItem){
        existingItem.quantity += quantity;
    }else{
        cart.push({
            id: id,
            name: name,
            price: price,
            quantity: quantity
        });
    }
    localStorage.setItem('cart', JSON.stringify(cart));
    showToast('カートに追加しました');
}
補足: カート機能をlocalStorageとサーバー内処理の2段構えにする理由
  • UX: localStorageで即時反映することで、閲覧者にとってのサイトの操作性の向上を可能に。
  • パフォーマンス: サーバーに逐一リクエストをしないことで負荷を軽減。
  • セキュリティ: localStorageは改竄可能なので、決済時はサーバー側で数量や金額を検証することで対策。
let cart = JSON.parse(localStorage.getItem('cart')) || [];
//cart.jsの冒頭に設置。
補足: JS・CSSファイルを入れるディレクトリ
  • Laravelにおいて、PHP以外のファイル(主にCSS・JSファイル、画像など)をフロントエンドに反映させる場合はpublicディレクトリ内にファイルを置くのが鉄則。
    • resourcesディレクトリのcss・jsフォルダ内にこれらを置いても機能しない点は注意が必要。
    • なお、resourceディレクトリは開発中のソースコードの置き場であり、Viteを使った開発の効率化が可能。(ただしJS・CSSファイルなどを直接publicに置いて読み込む場合は実質使わない)

トップメニューの実装

レスポンシブ対応のトップメニューのには、Bootstrapのナビバーコンポーネントを使用することで、効率的に実装。

Bootstrapのライブラリをレイアウトのテンプレートファイル(/resources/views/layouts/default.blade.php)内のheadタグに設置。

以下のコードでライブラリを導入可能。

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>

Bootstrap では予め用意されたクラス名をHTMLのタグに付与することでレイアウトや挙動を簡単に実装出来る。

以下が今回使用した主要なクラス名の概要。

  • navbar: Bootstrapにおけるナビゲーションバーの基本スタイルを適用。
  • navbar-expand-*: レスポンシブ対応におけるブレークポイントの指定。
    • 今回はlg(992px)を指定。横幅がこれを下回る場合にハンバーガーメニューに変化。
  • justify-content-end: ナビゲーションを右端に寄せる。
  • collapsenavbar-collapse: ハンバーガーメニューの折りたたみ機能の実装。このクラスの適用タグの子要素以降が初期状態では折り畳まれる。
  • navbar-navnavlink: 主にメニューのリンクの整える。
    • 前者が大画面時にメニューを横並びにし、後者がホバー時やアクティブ時のリンクの色変化を実装。
<nav class="top_menu navbar navbar-expand-lg justify-content-end">
                <div class="container-fluid justify-content-end">
                    <button class="navbar-toggler ms-auto" type="button" data-bs-toggle="collapse" data-bs-       target="#navbarNav"
                    aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="collapse navbar-collapse" id="navbarNav">
                        <ul class="navbar-nav">
                            <li class="navbar-item"><a class="nav-link" href="https://tea-lp.kanakofolio.net/#products">紅茶の種類</a></li>
                            <li class="navbar-item"><a class="nav-link" href="https://tea-lp.kanakofolio.net/#contact">お問い合わせ</a></li>
                            <li class="navbar-item"><a class="nav-link" href="https://tea-lp.kanakofolio.net/#purchase">購入</a></li>
                        </ul>
                    </div>
                </div>
            </nav>
補足:Bootstrap 導入によるレイアウト崩れ
  • Bootstrap ライブラリを読み込むことで、サイトに既存のクラス・ID名とライブラリで定義されるそれらが競合し、意図せず指定が上書きされる場合がある。
  • この場合はブラウザの開発者ツール(Chrome DevToolsなど)を用いてどのCSSが適用されているか確認して原因を特定。
  • 対策としては以下のような方法が考えられる
    • Bootstrapで用意されている同一のクラス・ID名を避ける(.containerや.toastなど)
    • カスタムCSS内で親要素を含めて指定し、特異性を上げる。
    • 必要に応じて、カスタムCSSをBootstrapライブラリの読み込み後に記述し、上書き出来るようにするなど。

Swiperによるカルーセルの実装

LPの「カスタマーレビュー」の項目にて、Swiperを用いたカルーセルを導入。

これにより、使用スペースを最低限に留めつつサイト全体にも動きをつけ、閲覧者が見飽きることを回避出来る。

Swiperのライブラリの読み込みコードは以下の通り。

<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

Bootstrap同様に、Swiperでも予め用意されたクラス名をHTMLタグに付与することでカルーセル機能を効率的に実装出来る。

以下が今回用いたクラス名の概要。

  • swiper: Swiperカルーセルの最外枠のタグに付与。このクラスの要素がスライダーとして認識される。
  • swiper-wrapper: スライド群を纏める要素に付与。子要素の.swiper-slideをこの中に並べることでカルーセルとして動作する。
  • swiper-slide: 各スライドのコンテンツに付与。これ単位で横スライド・縦スライドが切り替わる。
  • swiper-pagination: ページネーションの要素に付与。Swiperオプションで有効化すると自動で丸いインジケータが出現。
<!--一部抜粋-->
<div class="swiper mySwiper">
      <div class="reviews_list swiper-wrapper">
            <div class="swiper-slide">
                <p class="review">コーヒー派の私でも、この紅茶セットの味わいに驚きました。特にミスティックムーンライトのラベンダーとバニラの組み合わせは、心地よいリラックス効果があり、日々のストレスから解放されます。</p>
                <p class="reviewer_name">山本太二 (35歳)</p>
            </div>                 
      </div>
<!--以下reviews_list、swiper-wrapperクラスのdivタグがカルーセルの項目の数だけつづく-->
      <div class="swiper-pagination"></div>
</div>

デザインの観点

画像の選定・レタッチ

Comming soon…

サイトデザイン

Comming soon…