模写上級 #007 | 飲食店LPをHTML/CSSとLism CSSで


模写上級 #007は、イタリアンレストランの1ページ完結型LPを、HTML・CSSと軽量CSSフレームワーク「Lism CSS」で再現する課題です。この課題で身につくのは、フレームワークが用意したレイアウト部品の「効く範囲」と「効かない範囲」を見分け、狭い画面で崩れたときに原因を1箇所に特定する力です。

見た目を似せるだけの課題ではありません。今回のデモページは、スマートフォン幅で実際に横スクロールが発生します。その原因を自分で突き止めて直せたかどうかを合格ラインに置いています。以下の数値はすべて2026年8月2日にヘッドレスChromeで実測したものです。

難易度上級
所要時間目安6〜10時間(実装量から見積もった目安で、計測値ではありません)
使う技術HTML / CSS(Grid・Flexbox) / Lism CSS / IntersectionObserver

このLPで作るもの

題材は南イタリア料理のトラットリア「Trattoria LUCE」です。ヒーローから予約フォームまでを1ページに収めた、実際の飲食店サイトとほぼ同じ情報量を持つLPになっています。まずはPCとスマートフォンの両方で通してスクロールし、次の表の「観察ポイント」を意識して見てください。

セクション観察ポイント使う技術
ヒーロー画面いっぱいの背景と大きな見出し背景グラデーション+clamp()
CONCEPT画像とテキストの2カラム、数値3つの横並びGrid / Flexbox
MENU3カラムのカード。狭い画面でも3列のままGrid
CHEF左右を入れ替えた2カラムGrid
COURSEコース名と価格を左右に振り分ける行Flexbox
ACCESS / 予約入力欄の2カラムと、日時・人数のプルダウンGrid / フォーム要素

予約セクションは、時間と人数を <select> のプルダウンで選ぶ実装です。ボタンを並べて選ばせる形式ではないので、状態管理のJavaScriptは必要ありません。デモに入っているJavaScriptは、スクロールで要素をふわりと出す処理・ヘッダーに影を付ける処理・コピーライトの年を入れる処理の3つだけで、全体で30行ほどです。ページ内リンクの滑らかなスクロールもJavaScriptではなくCSSの scroll-behavior: smooth で実現されています。

デモは外部の配信元に3つ依存しています。CSSフレームワークのLism CSS、Google FontsのNoto Serif JP・Noto Sans JP・Cormorant Garamond、そして写真5点のUnsplashです。フォントが当たっていないだけで印象は大きく変わるため、余白を測り直す前にこの3つの読み込み状況を確認してください。


Lism CSSはバージョンを固定して読み込む

Lism CSSは、レイアウト用のクラスを組み合わせてページの骨組みを作る「レイアウトファースト」設計のCSSフレームワークです。CSSファイルを1つ読み込むだけで導入でき、ビルド作業は要りません。npmのレジストリで確認したところ、2026年8月2日時点の最新版は0.24.0(公開日2026年7月5日)、初回公開は2025年5月20日で、これまでに73バージョンが公開されています。開発は止まっていません。

出典はnpmレジストリのパッケージ情報Lism CSS公式ドキュメントのインストール手順(いずれも2026年8月2日取得)です。

読み込みは1行、ただしバージョンを書く

CDNから読み込む場合、バージョン部分に @latest と書くこともできますが、この課題では使わないでください。@latest は「今この瞬間の最新版」を指すため、フレームワーク側が更新された日を境に、昨日まで動いていたページが何の予告もなく崩れます。公式ドキュメントのインストール手順も、@latest ではなく具体的なバージョン番号を書いた例を示しています。

<!-- デモと同じ見え方にしたいとき(デモが読み込んでいるのはこのバージョン) -->
<link href="https://cdn.jsdelivr.net/npm/lism-css@0.0.13/dist/css/main.css" rel="stylesheet" />

<!-- 最新の設計で作り直したいとき -->
<link href="https://cdn.jsdelivr.net/npm/lism-css@0.24.0/dist/css/main.css" rel="stylesheet" />

デモページのHTMLを見ると、読み込んでいるのは lism-css@0.0.13 です。最新の0.24.0とは71バージョン離れています。デモのソースをそのまま写しながら読み込みだけを最新版にすると、見た目が合わない原因がフレームワーク側にあることに気づけません。

バージョンを上げると実際に何が止まるか

デモのHTMLは一切変えず、読み込むCSSのバージョンだけを0.0.13から0.24.0に差し替えて、同じ要素の計算後スタイルを比較しました。デモが使っている25個のユーティリティクラスのうち9個が0.24.0には存在せず、次のように無効化されます。エラーもコンソール警告も出ないため、崩れた理由が見えないのが厄介なところです。

クラス0.0.13での実測値0.24.0での実測値
-c:main色 rgb(201, 168, 76)rgb(255, 255, 255)(金色が消える)
-jc:sbspace-betweennormal(左右振り分けが崩れる)
-td:nnoneunderline(リンクに下線が戻る)
-ta:ccenterstart(中央寄せが解除)
-ai:ccenternormal(縦位置が揃わない)
-ov:hhiddenvisible(はみ出しが隠れない)

これらは削除されたのではなく、短縮形から正式名へ書き換えられています。0.24.0では -ai:c-ai:center-jc:sb-jc:between-ta:c-ta:center-ov:h-ov:hidden-td:n-td:none になります。-container:mis--container 系のトレイトクラスへ、色の -c:main-c:brand-c:accent へ整理されました。最新版で作り直すなら、この対応を先にまとめてから着手すると手戻りが減ります。

一方で、レイアウトの中心である l--stack l--flex l--columns l--center は両バージョンで同じ定義のまま残っています。骨組みは安定していて、細かい装飾用のクラス名が動いた、という理解でおおむね合っています。

Lism CSSを使わずに進めることもできる

2026年8月2日時点で、CDNのCSSファイルは正常に取得できます(HTTP 200・約29KB)。ただし将来配信が止まった場合や、フレームワークを使わずに実力を測りたい場合は、素のHTMLとCSSだけで進めても構いません。Lism CSSのクラスは、次のように置き換えれば同じ結果になります。

  • l--stackdisplay: flex; flex-direction: column; だけの定義です
  • l--flexdisplay: flex; だけで、折り返しの指定は含まれていません
  • l--columnsdisplay: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); です
  • l--centerdisplay: grid; place-content: center; place-items: center; です

この4つを自前のCSSに書けば、フレームワークなしでもデモとほぼ同じ骨組みが組めます。l--columnsminmax(0, 1fr) は特に重要なので、写すときに 1fr へ省略しないでください。理由は次の節で扱います。


完成条件(合格ライン)

上級課題の合否は「なんとなく似ている」では判定できません。この課題では、幅を変えたときにレイアウトが崩れないことを合格ラインに置きます。ブラウザの開発者ツールでデバイスツールバーを開き、幅を1280px・768px・375px・320pxの4段階に変えながら、次の4項目を確認してください。

判定項目合格ライン外れたら疑うこと
横スクロール4段階すべてで発生しない折り返し指定のない横並び(l--flex 相当)に大きな gap が付いていないか
カラム幅2カラム・3カラムの各列が等幅を保つGridの列指定を 1fr で書いていないか(minmax(0, 1fr) にする)
ヘッダー80px以上スクロールすると背景が濃くなるスクロール監視でクラスが付いていない、または position: fixed が外れていないか
スクロール演出各セクションが画面に入ると浮き上がる監視対象のクラス名が要素側と一致しているか

1つ目と2つ目は目視ではなく数値で判定できます。開発者ツールのコンソールに次の2行を貼れば、その場で答えが出ます。

// 0 なら合格。1以上ならその数値ぶん横にはみ出している
document.documentElement.scrollWidth - document.documentElement.clientWidth;

// 各グリッドの列幅。ひとつの行の中で数値がバラついていたら不合格
[...document.querySelectorAll('[style*="--cols"]')]
  .map(el => getComputedStyle(el).gridTemplateColumns);

参考までに、デモページを実測した結果は次のとおりです。1280pxと768pxでははみ出し0px、375pxで23px、320pxで50pxのはみ出しが出ました。カラム幅のほうは8つのグリッドすべてが4段階とも等幅を保っています。つまりデモ自身が狭い画面で横に溢れている状態で、あなたの模写が320pxで0pxになれば、デモより良い出来ということになります。


つまずきポイント

以下は、実際にデモのコードを手元で動かして再現できたものだけを載せています。

症状原因直し方
スマホ幅で横スクロールが出る横並びの行に折り返し指定がなく、gap が広すぎるその行に flex-wrap: wrap を足す
2カラムの左右が不揃いになる列指定が 1fr で、中身の最小幅に押し広げられているminmax(0, 1fr) に書き換える
remで書いた文字サイズが合わないデモのフレームワークが狭い画面でルート文字サイズを縮めている実測値をpxで確認してから換算する
クラスを写したのに効かない読み込んでいるバージョンにそのクラスが無いデモと同じ0.0.13を指定する
雰囲気が似ないWebフォントか写真が読めていないネットワークタブで3つの外部読み込みを確認する

横スクロールの犯人はCONCEPTの数値3つ

320px幅ではみ出している要素を全部拾うと、CONCEPTセクションにある「12 Years / 4.8 Rating / 28 Seats」の横並びに絞り込めました。この行は入れ物の幅が119pxしかないのに、中身は192px必要としています。差の73pxがそのままページ全体の横スクロールにつながっていました。

原因は2つ重なっています。1つは、この行が使っている l--flexdisplay: flex だけの定義で、折り返しを含んでいないこと。もう1つは、要素間の隙間が36.75pxずつ、2箇所で73.5px確保されていることです。入れ物が119pxしかない場所で、隙間だけで73.5pxを使ってしまっています。

/* 修正前: 折り返さないので横に溢れる */
.stat-row { display: flex; gap: 36.75px; }

/* 修正後: 狭いときだけ折り返す */
.stat-row { display: flex; flex-wrap: wrap; gap: 12px; }

この修正を当てて再計測したところ、行のはみ出しもページ全体のはみ出しも0pxになりました。注意したいのは、隙間を狭めるだけでは直らない点です。折り返しを付けずに隙間を36.75pxから12pxへ縮めただけでは、はみ出しは残ったままでした。効いているのは flex-wrap: wrap のほうで、隙間の調整は見栄えの微調整にすぎません。この順序を取り違えると、数値をいじり続けて時間を失います。

remの実測値がずれるのはルート文字サイズのせい

デモが読み込んでいる0.0.13は、ルート文字サイズを clamp(0.875rem, 0.625rem + 1vw, 1rem) で可変にしています。実測すると、320pxと375pxの幅では14px、768pxと1280pxでは16pxでした。つまり狭い画面では 1rem が16pxではなく14pxになります。

デモの見出しは clamp(3rem, 8vw, 6rem) ですが、320pxでの実測値は48pxではなく42pxでした。開発者ツールで測った数値をそのまま自分のページにrem指定で写すと、ここで6pxずれます。フレームワークを使わずに作る場合は、pxの実測値を基準にするか、ルート文字サイズも同じ式で揃えてください。なお最新の0.24.0はこの可変指定をやめており、全幅で16pxのままです。


進め方

上から順に作るのではなく、骨組みを全部通してから装飾に入るほうが早く終わります。装飾を先に詰めると、レイアウトを直すたびに調整をやり直すことになるためです。

  1. デモを1280pxと320pxの両方で見て、セクションの並びと各セクションのカラム数だけをメモする
  2. Lism CSSをバージョン指定で読み込み、全セクションの空箱をHTMLだけで並べる
  3. この段階で320pxのはみ出しを0pxにしておく(後から直すより圧倒的に楽)
  4. テキストと画像を流し込み、色とフォントを当てる
  5. スクロール演出とヘッダーの背景変化を実装する
  6. 完成条件の4項目を4段階の幅で再確認する

完成したら店名・写真・コース内容を差し替えて、自分のポートフォリオ作品に仕立て直してください。デモと同じ内容のまま公開するより、題材を変えたほうが実力の証明になります。作り始める前に構成の決め方を整理しておきたい場合は、デザインカンプを作る前に決めておくルールが参考になります。


次に取り組む課題

この課題は模写上級シリーズの最後にあたります。1つ前の課題は模写上級 #006 SaaS系LPの模写です。今回が「余白と色で世界観を作る」課題なのに対し、#006は情報を整理して伝える方向の課題なので、両方こなすと引き出しが増えます。

他のレベルの課題に進む場合は模写コーディング課題の一覧から選んでください。初級から上級、Figmaを使う課題までまとめてあります。

今回つまずいたのがCSSの書き方そのものだった場合は、CSSのテクニックまとめで該当箇所を補強してから戻ってくると進みが変わります。Lism CSSそのものをもう少し知りたい場合は、Lism CSSの特徴を解説した記事も用意しています。


よくある質問

Q. Lism CSSを使わずに素のHTMLとCSSだけで作ってもいいですか?

構いません。この課題で使っているLism CSSのレイアウトクラスは4つだけで、いずれも数行のCSSに置き換えられるため、自前のCSSで書いても完成条件は同じように満たせます。

Q. デモと同じ写真やフォントは使えますか?

写真はUnsplash、フォントはGoogle Fontsから読み込んでいるため、それぞれの利用規約の範囲で使えます。ポートフォリオとして公開するなら、写真は自分で選び直したほうが作品としての印象が良くなります。

Q. 予約フォームは実際に送信できるようにする必要がありますか?

この課題では不要です。デモも送信時の既定動作を止めるだけで、サーバーへは何も送っていません。見た目と入力体験の再現に集中してください。

Q. デモと同じバージョンではなく最新のLism CSSで作ってもいいですか?

問題ありませんが、装飾用のクラス名が変わっているため、デモのソースをそのまま写すと一部が効かなくなります。最新版で作るなら、本文の対応表を見ながらクラス名を読み替えてください。

差分チェックツールで効率UPお手本コードと自分のコードを比較して、違いを一目で確認できます。練習前にブックマークしておくと便利です。
Diff Checkerを開く →

Q. 模写したページをポートフォリオに載せてもいいですか?

「模写作品」であることを明記し、元のデモページへのリンクを併記すれば問題ありません。オリジナル作品として提示するのは避けてください。

Q. どのくらいの実力があれば取り組めますか?

HTMLとCSSでGridとFlexboxを一通り書ける状態が目安です。JavaScriptは30行ほどしか出てこないため、DOM操作の基本が分かっていれば足ります。