【WEB開発とWEB制作の違い 徹底比較 -LP編-】JavaScriptはコピペしかしてこなかったWEB制作コーダーがReact+TailwindでLPコーディング(実案件)してみた
投稿日: 2025年10月17日
ゾス。ShiftBの運営スタッフ兼ストイックコース講師のあおやぎです。
今回は、初めてのReactを使ったお仕事が一区切りしたため、記録と振り返りの記事になります。
「LPコーディング」というあまりReactやモダンな技術うんぬんからは離れた領域の、
ちょっと変わった切り口からReact周辺の技術を解説していこうと思います。
HTML, scss(CSS), jQuery(JavaScript) 以外の技術を使ったことがないコーダー
ReactやNext.js,Tailwind CSSといったモダンな技術に興味がある・学習中だけど、
まだそれらを使った仕事をしたことがない方
LPを作成するけどどの技術スタックを使えばいいか決まっていない方
にぜひ読んでいただきたい記事になります!
以下条件のどちらか1つにでもあてはまるなら「React(TypeScript) + Tailwind CSS」でLPコーディングすべし。
あてはまらないなら、ぶっちゃけHTML, scss(CSS), jQuery(JavaScript)で事足りるし
ReactやTailwindを使うメリットなし。
①Next.jsを利用したWEBサービスの独自ドメイン配下にLPを設置する場合
②「HTML, scss(CSS), jQuery(JavaScript),WordPress(PHP) 」以外のスキルを持たないコーダーが、React(TypeScript)やTailwind CSSを実際のコーディングを通して理解してみたい
コーディング単価が数万〜十数万のLPコーディングにおいて、採用される技術は以下のようになることが多いと思います。
・骨組み、マークアップ→ HTML
・スタイリング→バニラのCSS or SCSS
・アニメーション→jQuery(最近はバニラで書くことも多いかも?)
正直、モダンとは言えないというか、これらの技術のプロです!!とか言われても、
「ノマドワーカー目指す系のプログラミングスクールを最近卒業したのかな?」
と思われるのがオチです。(もちろん凄腕の人もいますがこの価格帯にはいません)
とはいえ、LPコーディングは「早い・安い・デザインに忠実」が特徴の牛丼みたいなお仕事です。
※決して軽視はしていないです。牛丼(LPコーディング)がないと人間(サービス)は生きていけない(売れない)ですし、牛丼チェーン(WEBマーケ会社)はめちゃめちゃ儲かってます)
牛丼作るなら食材にこだわる必要はないって話と同じです。
でも最低限の味(デザインの再現)はないとダメなんですよね。
まとめると、以下のようなイメージです。
それぞれの所感は以下の通りです。(今回はメインの骨組みとスタイリングに絞って解説します。)
Reactを本格的に学び始めたのは、LPコーディング開始2ヶ月前ぐらい、かつ別業務とも並行だったため、基本的にはAIエージェント+Reactを用いた過去のコードを参考にしながら進めていきました。
まず、HTMLとReactで明確に違う点の一つ目は「コンポーネント」です。
以下のようなレイアウトを組もうとしたときの、実際のコードを見比べてみましょう。
まずはHTMLから。
HTML(class名はBEM記法)
index.html
<section class="voice" id="voice">
<div class="voice__inner">
<ul class="voice__list">
<li class="voice__item">
<h3 class="voice__title">
受講生の声を集めて 表に発信するのが大変...🌀
</h3>
<p class="voice__text">
受講生に、学んだことやサポート内容をSNS等で発信して欲しいけど、できていない。
運営からしつこく言うのも気が引ける…
</p>
<div class="voice__info">
<img src="/images/lp/design_school.png" alt="">
<p class="voice__author">デザインスクール運営</p>
</div>
</li>
<li class="voice__item">
<h3 class="voice__title">
コミュニティ内部が なかなか活性化されない 💦
</h3>
<p class="voice__text">
一部の受講生ばかりが目立って、残りの人はいつも静か。
コミュニティ全体の熱量がなかなか上がらない…
</p>
<div class="voice__info">
<img src="/images/lp/programming_school.png" alt="">
<p class="voice__author">プログラミングスクール運営</p>
</div>
</li>
<li class="voice__item">
<h3 class="voice__title">
受講生のサポートと PR活動の両立が大変...😕
</h3>
<p class="voice__text">
受講生サポートに専念したいけど、新規集客もしなくてはいけない。
限られた時間の中での両立が難しい…
</p>
<div class="voice__info">
<img src="/images/lp/sns_school.png" alt="">
<p class="voice__author">SNSスクール運営</p>
</div>
</li>
</ul>
</div>
</section>
特にこれといって難しい点はないですし、高度なプログラミングの知識がなくてもコードを読むことはできます。
しかし、個人的には
①class名を都度考える必要がある
②同じコードがliタグより内側のコードのように、同じ役割のコードを繰り返す必要がある
(例えば、voice__infoのdivタグのようなタグはレイアウト調整のためだけに存在しており、3つのカード要素で差分はコンテンツしかないので繰り返し記述したくない)
といった点で少しコードが冗長になっているなあと感じてしまいます。
これがReact+TypeScript(.tsx)になると以下のようになります。(本来、Tailwindのクラスが入りますがReact説明のために一旦省きます。)
①index.tsx
import { Card } from "./Card";
<div className="">
<Card
title={
<>
受講生の活動や成果を
<br />
表に発信するのが大変...🌀
</>
}
description={
<>
受講生に、学んだことやサポート内容をSNS等で発信して欲しいけど、できていない。
<br />
運営からしつこく言うのも気が引ける…
</>
}
businessName="デザインスクール運営"
imagePath="/images/lp/design_school.png"
/>
<Card
title={
<>
コミュニティ内部が
<br />
なかなか活性化されない 💦
</>
}
description={
<>
一部の受講生ばかりが目立って、残りの人はいつも静か。
<br />
コミュニティ全体の熱量がなかなか上がらない…
</>
}
businessName="プログラミングスクール運営"
imagePath="/images/lp/programming_school.png"
/>
<Card
title={
<>
受講生のサポートと
<br />
PR活動の両立が大変...😕
</>
}
description={
<>
受講生サポートに専念したいけど、新規集客もしなくてはいけない。
<br />
限られた時間の中での両立が難しい…
</>
}
businessName="SNSスクール運営"
imagePath="/images/lp/sns_school.png"
/>
</div>
②Card.tsx
type Props = {
title: React.ReactNode;
businessName: string;
description: React.ReactNode;
imagePath?: string;
};
export const Card: React.FC<Props> = ({
title,
businessName,
description,
imagePath,
}) => {
return (
<div className="">
{description}
</div>
</div>
<div className="">
<Image
src={imagePath || ""}
alt={businessName}
width={1280}
height={1280}
className=""
/>
<div className="">
{businessName}
</div>
</div>
);
};
一見、コードの記述量自体は増えているように見えますが、各コードの分担がされているのがわかるかと思います。
繰り返し部分は、Card.tsxのように切り出しておく。
大元のファイルでは、「Card」というコンポーネントを使うことだけ宣言し、差分だけ(文章の中身や画像のパスなど)を記述しておく。
こういった記述のメリットに明確に気づくのは、「修正したい」ときです。
HTMLでカードレイアウトを修正する場合、仮にHTMLの入れ子構造が悪い、class指定が間違っていた時は3要素分の計3箇所修正する必要があります。
しかし、Reactであればカードレイアウトのコードを司っているのはCard.tsxの1箇所だけなのでコード修正の工数が3分の1になります。
まとめると、「コンテンツ(情報)」と「レイアウト(見た目)」を明確にコードで役割分担できるのが最大のメリットかな、と思います。
次は、スタイリングの部分です。
Reactの設計思想として、コンポーネントのスタイリングはコンポーネントファイル内で完結させるのでReact側からはCard.tsxのみ取り上げます。
また、scssかcssは今回の論点では関係ないので、簡素化のためにバニラのcssと比べます。
個人的に、スタイリングに関して自分の意見はどっちの方が優れている、という考えは特になく、ケースバイケースというのが結論です。
なんとなく使用感を掴んでいただければと思います。
ぶっちゃけできることは変わらんですが、Tailwindのメディアクエリ(sm: md: など)を全部のプロパティの前につけなくちゃいけない仕様だけはどうにかしてほしいな、と思いました。
style.css
.voice__list{
display: flex;
justify-content: center;
align-items: center;
}
.voice__item{
width: 300px;
margin: 0 10px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 8px;
background-color: #fff;
}
.voice__title{
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.voice__text{
font-size: 14px;
margin-bottom: 15px;
}
.voice__info{
display: flex;
align-items: center;
}
.voice__info img{
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
}
.voice__author{
font-size: 14px;
}
Tailwind(arbitraryの値が多すぎ問題は見逃してください😭)
<div className="flex flex-col items-start justify-start gap-[19px]
sm:gap-[calc(19/375*100vw)]
md:gap-[calc(24/1512*100vw)]
xl:gap-[24px]">
<div className="text-[16px] leading-[24px] font-bold
sm:text-[calc(16/375*100vw)] sm:leading-[calc(24/375*100vw)]
md:text-[calc(19/1512*100vw)] md:leading-[calc(30/1512*100vw)]
xl:text-[19px] xl:leading-[30px]">
{title}
</div>
<div className="text-[14px] leading-[24px]
sm:text-[calc(14/375*100vw)] sm:leading-[calc(24/375*100vw)]
md:text-[calc(14/1512*100vw)] md:leading-[calc(24/1512*100vw)]
xl:text-[14px] xl:leading-[24px]">
{description}
</div>
</div>
<div className="flex items-center justify-start gap-[14px]
sm:gap-[calc(14/375*100vw)]
md:gap-[calc(14/1512*100vw)]
xl:gap-[14px]">
<Image
src={imagePath || ""}
alt={businessName}
width={1280}
height={1280}
className="block object-cover size-[64px]
sm:size-[calc(64/375*100vw)]
md:size-[calc(64/1512*100vw)]
xl:size-[64px]"
/>
<div className="text-center text-[12px]
sm:text-[calc(12/375*100vw)]
md:text-[calc(12/1512*100vw)] md:leading-8
xl:text-[12px] xl:leading-8">
{businessName}
</div>
</div>
今回は以上です!
ゾス!!🔥