「スワイプ型LPを自分でコーディングしたいけど、どう実装すればいいかわからない…」
スワイプ型LPは、正しく実装すればCVR248%向上、読了率65%という効果を発揮します。しかし、実装を誤ると操作性が悪くなり、逆効果になることも。この記事では、コピペで使えるHTML/CSS/JavaScriptのコードサンプルとともに、スワイプ型LPの実装方法を解説します。
初心者でも実装できるよう、ステップバイステップで説明します。
実装前の準備
スワイプ型LPの実装に必要なものを確認しましょう。
必要なスキル
- HTML:基本的な構造を書ける程度
- CSS:flexbox、position、transitionの理解
- JavaScript:イベントハンドリングの基礎
用意するもの
- スライド画像:390 x 844px推奨(8〜12枚)
- コードエディタ:VSCode等
- ローカルサーバー:Live Server等(動作確認用)
基本構造(HTML)
まずは、スワイプ型LPの基本的なHTML構造を作成します。
HTML<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>スワイプ型LP</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="lp-container">
<!-- プログレスインジケーター -->
<div class="progress-bar">
<div class="progress-fill"></div>
</div>
<!-- スライドコンテナ -->
<div class="slides-wrapper">
<div class="slide active">
<img src="slide1.jpg" alt="スライド1">
</div>
<div class="slide">
<img src="slide2.jpg" alt="スライド2">
</div>
<div class="slide">
<img src="slide3.jpg" alt="スライド3">
</div>
<!-- 必要な枚数だけ追加 -->
</div>
<!-- 固定CTA -->
<div class="fixed-cta">
<a href="#" class="cta-button">今すぐ申し込む</a>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
HTML構造のポイント
- viewport設定:
user-scalable=noでピンチズームを無効化 - progress-bar:上部に進捗バーを配置
- slides-wrapper:全スライドを包含するコンテナ
- fixed-cta:画面下部に固定するCTAボタン
スタイリング(CSS)
次に、スワイプ操作を実現するためのCSSを記述します。
CSS* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
touch-action: none;
}
#lp-container {
position: relative;
width: 100%;
height: 100%;
max-width: 430px;
margin: 0 auto;
background: #000;
}
/* プログレスバー */
.progress-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 4px;
background: rgba(255,255,255,0.3);
z-index: 100;
}
.progress-fill {
height: 100%;
background: #ff6b6b;
width: 0%;
transition: width 0.3s ease;
}
/* スライドコンテナ */
.slides-wrapper {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transform: translateY(100%);
transition: all 0.4s ease-out;
}
.slide.active {
opacity: 1;
transform: translateY(0);
}
.slide.prev {
opacity: 0;
transform: translateY(-30%);
}
.slide img {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 固定CTA */
.fixed-cta {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 16px;
padding-bottom: calc(16px + env(safe-area-inset-bottom));
background: linear-gradient(transparent, rgba(0,0,0,0.8));
z-index: 50;
}
.cta-button {
display: block;
width: 100%;
max-width: 400px;
margin: 0 auto;
padding: 18px 32px;
background: #ff6b6b;
color: #fff;
text-align: center;
text-decoration: none;
font-size: 18px;
font-weight: bold;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(255,107,107,0.4);
}
/* PC表示時の調整 */
@media (min-width: 430px) {
#lp-container {
height: 100vh;
box-shadow: 0 0 30px rgba(0,0,0,0.3);
}
}
CSSのポイント
| プロパティ | 目的 |
|---|---|
touch-action: none |
ブラウザのデフォルトスワイプを無効化 |
overflow: hidden |
スクロールを防止 |
transform: translateY |
スライドアニメーション |
env(safe-area-inset-bottom) |
iPhoneのセーフエリア対応 |
スワイプ処理(JavaScript)
スワイプ操作を検出し、スライドを切り替えるJavaScriptを実装します。
JavaScriptclass SwipeLP {
constructor() {
this.slides = document.querySelectorAll('.slide');
this.progressFill = document.querySelector('.progress-fill');
this.currentIndex = 0;
this.totalSlides = this.slides.length;
this.startY = 0;
this.endY = 0;
this.isAnimating = false;
this.init();
}
init() {
// タッチイベント
document.addEventListener('touchstart', (e) => this.handleTouchStart(e));
document.addEventListener('touchend', (e) => this.handleTouchEnd(e));
// マウスイベント(PC対応)
document.addEventListener('mousedown', (e) => this.handleMouseDown(e));
document.addEventListener('mouseup', (e) => this.handleMouseUp(e));
// ホイールイベント(PC対応)
document.addEventListener('wheel', (e) => this.handleWheel(e));
// 初期表示
this.updateProgress();
}
handleTouchStart(e) {
this.startY = e.touches[0].clientY;
}
handleTouchEnd(e) {
this.endY = e.changedTouches[0].clientY;
this.handleSwipe();
}
handleMouseDown(e) {
this.startY = e.clientY;
}
handleMouseUp(e) {
this.endY = e.clientY;
this.handleSwipe();
}
handleWheel(e) {
if (this.isAnimating) return;
if (e.deltaY > 0) {
this.nextSlide();
} else {
this.prevSlide();
}
}
handleSwipe() {
if (this.isAnimating) return;
const threshold = 50; // スワイプ判定の閾値
const diff = this.startY - this.endY;
if (diff > threshold) {
this.nextSlide();
} else if (diff < -threshold) {
this.prevSlide();
}
}
nextSlide() {
if (this.currentIndex >= this.totalSlides - 1) return;
this.isAnimating = true;
this.slides[this.currentIndex].classList.remove('active');
this.slides[this.currentIndex].classList.add('prev');
this.currentIndex++;
this.slides[this.currentIndex].classList.add('active');
this.updateProgress();
setTimeout(() => {
this.slides[this.currentIndex - 1].classList.remove('prev');
this.isAnimating = false;
}, 400);
}
prevSlide() {
if (this.currentIndex <= 0) return;
this.isAnimating = true;
this.slides[this.currentIndex].classList.remove('active');
this.currentIndex--;
this.slides[this.currentIndex].classList.remove('prev');
this.slides[this.currentIndex].classList.add('active');
this.updateProgress();
setTimeout(() => {
this.isAnimating = false;
}, 400);
}
updateProgress() {
const progress = ((this.currentIndex + 1) / this.totalSlides) * 100;
this.progressFill.style.width = progress + '%';
}
}
// 初期化
document.addEventListener('DOMContentLoaded', () => {
new SwipeLP();
});
JavaScriptのポイント
- threshold:50px以上のスワイプで切り替え判定
- isAnimating:連続スワイプ防止フラグ
- wheel対応:PCでのマウスホイール操作
- updateProgress:進捗バーの更新
応用:オーバーレイテキストの追加
画像上にテキストを重ねる実装方法です。
HTML(スライド部分)<div class="slide">
<img src="slide1.jpg" alt="スライド1">
<div class="overlay-text">
<h2 class="headline">CVR248%UP</h2>
<p class="subtext">スワイプ型LPで成果を出す</p>
</div>
</div>
.overlay-text {
position: absolute;
bottom: 120px;
left: 20px;
right: 20px;
color: #fff;
text-shadow: 0 2px 8px rgba(0,0,0,0.5);
}
.headline {
font-size: 32px;
font-weight: 900;
margin-bottom: 8px;
}
.subtext {
font-size: 16px;
}
応用:計測タグの埋め込み
スライドごとの閲覧データを取得するための実装です。
JavaScript(計測用)// Google Analytics 4 対応の計測
function trackSlideView(slideIndex) {
if (typeof gtag !== 'undefined') {
gtag('event', 'slide_view', {
'slide_number': slideIndex + 1,
'slide_total': this.totalSlides
});
}
}
// nextSlide()内で呼び出し
nextSlide() {
// ... 既存のコード ...
trackSlideView(this.currentIndex);
}
計測のポイント
スライドごとの離脱率を計測することで、「何枚目で離脱が多いか」を特定できます。これがスワイプ型LPの改善しやすさにつながり、離脱率50%減に貢献します。
よくあるエラーと解決法
| エラー/問題 | 原因 | 解決法 |
|---|---|---|
| スワイプが効かない | touch-actionの設定漏れ | body に touch-action: none を追加 |
| 画面が揺れる | overflow設定の問題 | html, body に overflow: hidden を追加 |
| iPhoneで下にスペースが出る | セーフエリア未対応 | env(safe-area-inset-bottom) を使用 |
| 連続スワイプでバグる | アニメーション中の処理 | isAnimatingフラグで制御 |
実践チェックリスト
実装完了後のチェックリストです。
- スマホ実機でスワイプ操作が動作する
- PCでマウスホイール操作が動作する
- プログレスバーが正しく更新される
- CTAボタンが常に表示されている
- セーフエリアが確保されている
- 画像が画面に収まっている(はみ出していない)
- アニメーションがスムーズに動く
- 計測タグが正しく発火している
もっと簡単に作りたい方へ
コーディングに自信がない方や、もっと手軽にスワイプ型LPを作成したい方には、ノーコードツールの活用がおすすめです。
当サイトのスワイプ型LP作成ツールなら、画像をアップロードするだけで簡単にスワイプ型LPが作成できます。HTML/CSS/JavaScriptの知識は不要です。
まとめ
スワイプ型LPの実装は、HTML/CSS/JavaScriptの基礎知識があれば可能です。この記事で紹介したコードをベースに、自社の商材に合わせてカスタマイズしてください。
正しく実装されたスワイプ型LPは、CVR248%向上、離脱率50%減、読了率65%といった効果をもたらします。計測タグも忘れずに埋め込み、継続的な改善を行いましょう。
この記事のポイント
- HTML:シンプルなdiv構造でスライドを配置
- CSS:touch-action、overflow、transformがキー
- JS:タッチイベントでスワイプを検出
- セーフエリア対応を忘れずに
- 計測タグでスライドごとの分析が可能