この課題は、Tailwind CSS と Swiper を CDN だけで読み込み、ビルド環境なしでスマートフォン製品のLPを1枚組み上げる中級課題です。身につくのは「ユーティリティクラスだけでレイアウトを組む力」と「ライブラリのバージョンを自分で決めて固定する力」の2つです。
模写する対象は公開しています。スマホ製品LPのデモを開く
| 項目 | 内容 |
|---|---|
| 難易度 | 中級 |
| 所要時間 | 目安4〜6時間(実装量からの見積もりで、計測値ではありません) |
| 使う技術 | HTML / Tailwind CSS v4 / Swiper 14 / IntersectionObserver |
見た目を似せるだけなら数時間で終わります。山場はそこではなく、CDNで読み込むライブラリのバージョンが公式ドキュメントの世代とズレたまま放置される、という実務で起きる問題のほうです。
この課題で作るもの
ページを構成する6つのセクション
| セクション | ここで練習すること |
|---|---|
| ヒーロー | 画面いっぱいの高さと中央寄せ、流体的な文字サイズ |
| 製品スライダー | Swiperの組み込みとキーボード操作 |
| 価格プラン | 1カラムから3カラムへ切り替えるグリッド |
| スペック表 | 表だけを横スクロールさせる囲い方 |
| FAQ・問い合わせ | 余白の統一とボタンの状態変化 |
まず骨格だけ書く
完成コードは載せません。写して終わりでは練習になりません。最初はこの骨格だけで十分です。
<body class="font-sans text-white antialiased">
<section class="fade-in animated-bg">ヒーロー</section>
<section id="features" class="fade-in">スライダー</section>
<!-- pricing / specs / faq / contact も同じ形で並べる -->
<footer>コピーライト</footer>
</body>
読み込むライブラリのバージョンを自分で決める
CDNのURLと公式ドキュメントの世代がズレている
よく使われる読み込み方を2026年8月2日に実際に取得して確かめた結果が以下です。
| 対象 | よく書かれる指定 | 実測(2026-08-02) |
|---|---|---|
| Tailwind の CDN | cdn.tailwindcss.com | HTTP 200。ただし /3.4.17 へ1回リダイレクトされv3系に固定(npm上の最新は4.3.3・2026-07-16公開) |
| 公式ドキュメント | tailwindcss.com/docs | ページ内の表記は「Tailwind CSS v4.3」。つまりv4の説明 |
| Swiper の CDN | swiper@11 | 11.2.10 に解決。11系の最終リリースは2025-06-28(最新は14.0.7・2026-07-28公開) |
つまり cdn.tailwindcss.com を読み込んで公式ドキュメントを見ながら書くと、動くのは v3、読む説明は v4 になります。既定値が変わったクラスもあるため、表示がおかしい原因を特定できません。
模写元のデモ自身が、この状態です。2026年8月2日にデモのHTMLを取得して確認したところ、読み込んでいるのは cdn.tailwindcss.com(=v3.4.17)と swiper@11 でした。つまりこれから書くコード(v4)とデモ(v3)は世代が違います。見た目を突き合わせるときは、次の2つが「自分の書き間違い」ではなくバージョン差であることを先に知っておいてください。
| デモで使われているクラス | v3での意味 | v4で同じにするには |
|---|---|---|
shadow-sm | いちばん小さい影 | shadow-xs に書き換える(v4の shadow-sm は一段大きい影) |
border(色指定なし) | 枠線の色は gray-200 | border border-gray-200 のように色を明示する(v4の既定は currentColor=文字色) |
デモに合わせて直すのが目的ではありません。「同じクラス名を書いたのに見え方が違う」が起きたら、まずバージョンを疑うという手順を覚えるのがこの課題の狙いです。
この課題は Tailwind v4 で通す
v3 に留まる選択もありますが、この課題では v4 に揃えます。理由は3つです。
- 現行のインストール手順ページ(Play CDN・2026-08-02取得)が案内するのは
cdn.jsdelivr.net/npm/@tailwindcss/browser@4で、cdn.tailwindcss.com は一度も出てきません。 - 世代を揃えると、うまくいかないときに「自分の書き方の問題」だけを疑えばよくなります。
- v4 のブラウザ版 CDN は生存を確認済みです(HTTP 200・281,817バイト。クラスが生成されることもブラウザで確認)。
ただし公式アップグレードガイドによれば v4 は Safari 16.4 / Chrome 111 / Firefox 128 以降が対象で、古い環境では動きません。そうした案件では v3.4 に留まることを公式が推奨しています。
v3 と v4 で実際に変わった書き方
この課題で影響が出るのは次の2点で、どちらもブラウザで値を読んで確かめています。
1. 設定の入り口が変わった。 v3 は window.tailwind を持ち tailwind.config = {} で色を足せましたが、v4 のブラウザ版では window.tailwind が undefined です(実測)。代わりに CSS 側で書きます。
<style type="text/tailwindcss">
@theme {
--color-brand: #da373d;
}
</style>
これで text-brand が使えます(実測で rgb(218, 55, 61))。type="text/tailwindcss" を付け忘れるとただのCSSとして扱われ、@theme は無視されます。
2. border だけ書いたときの色が変わった。 同じ class="border" の計算値は、v3 が rgb(229, 231, 235)(gray-200)、v4 が rgb(0, 0, 0) すなわち currentColor でした。枠線は border border-gray-300 と色まで書く癖をつけてください。
公式は他に ring の既定幅が3pxから1pxになった点、rounded-sm や shadow-sm の大きさがずれた点を挙げていますが、この課題で使う rounded shadow-md ring-2 は影響しません。CSSの書き方はCSS実装テクニック集で整理できます。
Swiper は14系に上げる
Swiper も 11 のままにせず 14 系へ上げます。公式CHANGELOG(2026-08-02取得)の記載は次のとおりです。
- v14 は全体の TypeScript 書き直しで、v13 は飛ばされている
- v12 からのアップグレードにコード変更は不要。オプションも既定値もそのまま
- 対応ブラウザは Chrome / Edge 110以降、Safari 16.4以降、Firefox 110以降
- 11から12でLESS / SCSSの配布が廃止され、ナビゲーション矢印がSVGになった
下限ブラウザが Safari 16.4 で Tailwind v4 と揃うのが決め手です。片方だけ古い前提を引きずると対応表を二重に管理することになります。LESS / SCSS の廃止は今回の構成では影響しません。11系向けの初期化コードを 14.0.7 で動かし、そのまま動くことも確認しました。
バージョンは必ず固定して書く
@4 や @11 のようなメジャー指定は系列の最新へ自動で追随します。便利に見えますが、次に開いた日に挙動が変わっても自分のコードのせいかライブラリのせいかを切り分けられません。パッチ番号まで固定してください。
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@14.0.7/swiper-bundle.min.css" />
<script src="https://cdn.jsdelivr.net/npm/swiper@14.0.7/swiper-bundle.min.js"></script>
いずれも2026-08-02にHTTP 200で取得できました。なお Play CDN について公式は「開発用であり本番向けではない」と明記しています。仕事で使うときは CLI か Vite でビルドしてください。
手を動かす順番
ヒーローを画面いっぱいにする
<section class="min-h-screen flex flex-col justify-center items-center text-center px-6 fade-in animated-bg">
h-screen ではなく min-h-screen を選びます。高さを固定すると長い見出しで文字が切れるためです。文字サイズは text-4xl sm:text-5xl md:text-6xl と段階で持つか text-[min(10vw,60px)] で流体化するか、どちらかに決めて混ぜないこと。
スライダーを置く
<div class="swiper max-w-4xl mx-auto">
<div class="swiper-wrapper">
<div class="swiper-slide"><!-- 画像 --></div>
</div>
<div class="swiper-pagination mt-6"></div>
</div>
swiper swiper-wrapper swiper-slide はライブラリ側の規約なので、Tailwind のクラスに置き換えず同じ要素に足す形で書きます。初期化は次のとおりです。
new Swiper(".swiper", {
loop: true,
pagination: { el: ".swiper-pagination", clickable: true },
autoplay: { delay: 4000, disableOnInteraction: false, pauseOnMouseEnter: true },
keyboard: { enabled: true },
});
最後の keyboard が今回の肝です。Swiper API リファレンス(2026-08-02取得)では keyboard.enabled の既定値は false で、書かなければ矢印キーは効きません。読み上げ用の属性を扱う a11y モジュールは既定で有効なので、書かなくても働きます。
価格カードを3カラムにする
<div class="max-w-5xl mx-auto grid grid-cols-1 md:grid-cols-3 gap-8 px-4">
狭い画面では1列、md 以上で3列。中央のカードだけ ring-2 ring-black で立たせます。枠線の色は前述のとおり明示すること。スペック表は overflow-x-auto を付けた要素で包みます。
スクロールでフェードインさせる
表示のきっかけは IntersectionObserver で取り、見た目の変化はCSSに任せます。必ず入れてほしいのが動きを減らす設定への対応です。
.fade-in {
opacity: 0;
transform: translateY(40px);
transition: opacity 1s ease, transform 1s ease;
}
.fade-in.show {
opacity: 1;
transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
.fade-in {
opacity: 1;
transform: none;
transition: none;
}
.animated-bg {
animation: none;
}
}
prefers-reduced-motion は、OS側で「視差効果を減らす」を選んだ利用者を検出するメディア特性です。公開中のデモにはこの記述が1箇所もありません(2026-08-02に確認)。ここは模写せず自分で足す部分です。
もう1点。この課題の古い解説には @keyframes fadeIn が載っていますが、フェードインは transition で実装されているため、この定義はどこからも参照されていません。使われないCSSは動かない原因を探すときの候補を増やすだけなので、写さず削ってください。
完成条件(合格ライン)
見た目ではなく次の5つで判定します。すべて自分で数字を読んで確かめられる項目です。
| 判定すること | OKの状態 | 外れたら疑うこと |
|---|---|---|
| 幅320pxでページが横に伸びない | documentElement の scrollWidth と clientWidth が同値 | 幅の広い要素が overflow-x-auto の外にある |
| スペック表は表の中だけ横スクロールする | 表を包む要素は scrollWidth > clientWidth、ページ全体は同値 | 包む要素に overflow-x-auto が無い |
| スライダーをTabとEnterで操作できる | ページネーションの点に tabindex=”0″ と role=”button” が付きEnterで動く | pagination.clickable が true でない |
| 矢印キーでスライドが前後する | swiper.keyboard.enabled が true で左右キーで realIndex が変わる | keyboard: { enabled: true } を書いていない |
| 自動再生を止める手段がある | 停止ボタンが動く、または pauseOnMouseEnter が効く | autoplay に止める手段を付けていない |
判定用のスニペット
開発者ツールのコンソールに貼れば、上の1・3・4をまとめて確認できます。
const de = document.documentElement;
const sw = document.querySelector(".swiper").swiper;
const bullet = document.querySelector(".swiper-pagination-bullet");
console.log({
noPageScroll: de.scrollWidth === de.clientWidth,
keyboard: sw.keyboard.enabled,
bulletTabindex: bullet ? bullet.getAttribute("tabindex") : null,
});
公開中のデモを2026-08-02に同じ手順で測ると1・2・3は通り、4と5は落ちます。swiper.keyboard.enabled は false で、左右キーを押しても realIndex は0のままでした。そのまま写すと同じ状態になるので、この2つは自分で足す部分です。
5つ目を軽く見ないでください。WCAG 2.2 の達成基準2.2.2は、自動で始まり5秒を超えて続く動きには一時停止・停止・非表示のいずれかの手段が必要だとしています。マウスを乗せたときだけ止まる作りはキーボード利用者に届かないので、停止ボタンが確実です。
つまずきポイント
| 症状 | 原因 | 直し方 |
|---|---|---|
| 設定した色が反映されない | v4のブラウザ版に window.tailwind は無い(実測でundefined) | style 要素に type=”text/tailwindcss” を付けて @theme を書く |
| 枠線が黒くなった、または消えた | v4では border の既定色が currentColor(v3はgray-200) | border border-gray-300 のように色まで書く |
| JSで後から足した要素だけ効かない | ブラウザ版はDOMを監視して後からCSSを生成する(実測で追加直後は未適用) | 生成を待つ前提で書く。初期HTMLのクラスは通常どおり効く |
| スライダーが縦に積まれたまま | swiper-bundle.min.css を読み込んでいない | JSと同じバージョンのCSSをlinkで読み込む |
よくある質問
Q. Tailwind CSS はビルドなしでも実務で使えますか?
公式はブラウザ版CDNを「開発用であり本番向けではない」と明記しているため、学習と試作に留め、納品物では CLI か Vite でビルドしたCSSを使ってください。
Q. cdn.tailwindcss.com はもう使えないのですか?
2026-08-02時点ではHTTP 200で動作しますが、3.4.17へリダイレクトされるv3系で現行ドキュメントには登場しないため、説明と挙動が食い違う前提で使うことになります。
Q. Swiper を11から14に上げるとコードを書き直しますか?
公式CHANGELOGは「v12からのアップグレードにコード変更は不要」としており、11から12の変更もLESS/SCSS配布の廃止と矢印のSVG化が中心なので、今回の構成では書き直しは要りません。
Q. バージョンを固定すると更新されなくて困りませんか?
練習用ページで優先すべきは「昨日と同じ結果が再現できること」なので、固定したうえで自分の都合で番号を上げ、そのつど完成条件の5項目を測り直すのが安全です。
Q. スライダーの自動再生は入れないほうがいいですか?
入れること自体は問題ありませんが、5秒を超えて動き続けるものには停止手段が必要(WCAG 2.2 の達成基準2.2.2)なので、自動再生と停止ボタンはセットで作ってください。
Q. どのくらいの時間で終わりますか?
実装量から見積もると4〜6時間が目安ですが、これは計測値ではなくバージョン確認とキーボード対応まで含めた想定で、見た目を似せるだけなら半分程度で終わります。
次の課題へ
ひとつ前の課題は模写中級 #004・Bootstrapでポートフォリオサイトを作る練習です。続けて解くと、ユーティリティ型とコンポーネント型の思想の違いを体感できます。
次はScrollReveal.jsでスクロールアニメーションを付けたLPへ。同じ表現をライブラリに任せると何が減って何が増えるかを比べられます。
他のレベルの課題を探すときは模写コーディング一覧から選んでください。
