Reactでコーポレートサイトを作る
投稿日:2024年09月16日
更新日:2024年09月17日
Contents
はじめに
題名通りに、Reactを使って、コーポレートサイトを作ります。
今回使う題材は、こちらのデザインを参考にします。
ちなみに他にも、練習用サイトが難易度を分けて用意されています。
また、コードも提供されていて、HTMLとCSSを勉強した後に、自分で試すのに適しています。
ただ、HTMLとCSSで作成しても面白くないので、React+Tailwind CSSを使って実装します。
デザインを参考にしますが、完コピを目的にしていません。
デモサイト
デモサイトは以下のリンクから見ることができます。
レスポンシブ対応で、1024pxで切り替えるようになっています。
また、トップページのみ実装しています。
https://react-corporate-website.pages.dev
プロジェクト作成
mkdir react-corporate-website
cd react-corporate-website
bun create cloudflare@latest ./
What would you like to start with?
category Framework Starter
Which development framework do you want to use?
framework React
Select a variant:
variant TypeScript
Do you want to use git for version control?
yes git
Do you want to deploy your application?
no deploy via `bun run deploy`
動作確認
bun run dev
Tailwind CSSをインストール
bun add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
作成されたtailwind.config.js
に設定を追加
/** @type {import('tailwindcss').Config} */
export default {
- content: [],
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
index.css
を以下のコードに変更App.css
を削除
@tailwind base;
@tailwind components;
@tailwind utilities;
App.tsx
のコードを整理
function App() {
return <h1 className="flex justify-center">Vite + React</h1>;
}
export default App;
ファビコンを設定
public
ディレクトリに、favicon.ico
を追加index.html
にファビコンを設定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+ <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
画像ファイルを追加
public
ディレクトリに、logo.svg
を追加して、vite.svg
を削除
また、asset
ディレクトリに以下の画像ファイルを追加
- about.jpg
- business1.jpg
- business2.jpg
- business3.jpg
- business4.jpg
- company.jpg
- logo.svg
- mainvisual.jpg
タイトル・言語を変更
index.html
のタイトル・言語を変更
<!DOCTYPE html>
- <html lang="en">
+ <html lang="ja">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Vite + React + TS</title>
+ <title>React Website</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
CSSを設定
index.css
でhtml
タグにスクロールをスムーズにする設定を追加
また、body
タグに背景色の設定を追加
@tailwind base;
@tailwind components;
@tailwind utilities;
+
+ html {
+ scroll-behavior: smooth;
+ }
+
+ body {
+ background-color: #F5F5F5;
+ }
共通コンポーネントを作成
ヘッダー・フッター・ヒーローセクションの追加
export default function Header() {
return <header>Header</header>;
}
export default function Hero() {
return <div>Hero</div>;
}
export default function Footer() {
return <footer className="mt-auto">Footer</footer>;
}
ヘッダー・フッター・ヒーローセクションの仮設置
+ import Footer from "./components/footer";
+ import Header from "./components/header";
+ import Hero from "./components/hero";
function App() {
- return <h1 className="flex justify-center">Vite + React</h1>;
+ return (
+ <main className="flex flex-col min-h-dvh">
+ <Header />
+ <Hero />
+ <main className="container mx-auto min-h-dvh">Main</main>
+ <Footer />
+ </main>
+ );
}
export default App;
ヘッダーを作成
header.tsx
を編集
"use client";
import { useState } from "react";
import MenuLink from "./ui/menu-link";
export default function Header() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
return (
<header className="h-20 flex justify-between items-center fixed top-0 left-0 right-0 bg-gray-100/80 z-10">
<h1 className="w-48 lg:flex justify-end items-end pl-4">
<a href="#">
<img src="/logo.svg" alt="logo" width="100" height="100" />
</a>
</h1>
<button
className="lg:hidden z-10 mr-8 text-3xl flex justify-center items-center h-full"
onClick={() => setIsMenuOpen(!isMenuOpen)}
>
{isMenuOpen ? "✕" : "☰"}
</button>
<ul
className={`lg:flex ${
isMenuOpen ? "flex text-center text-xl" : "hidden"
} flex-col lg:flex-row absolute lg:relative top-20 lg:top-0 left-0 w-full lg:w-auto bg-gray-100/80 lg:bg-transparent`}
>
<li className="p-4">
<MenuLink href="#new">NEWS</MenuLink>
</li>
<li className="p-4">
<MenuLink href="#about">ABOUT</MenuLink>
</li>
<li className="p-4">
<MenuLink href="#business">BUSINESS</MenuLink>
</li>
<li className="p-4">
<MenuLink href="#company">COMPANY</MenuLink>
</li>
</ul>
<a
href="#"
className="hidden lg:flex justify-center items-center bg-black text-white w-52 h-full hover:bg-gray-700"
>
お問い合わせ
</a>
</header>
);
}
components
ディレクトリに、ui
ディレクトリを作成
その中に、menu-link.tsx
を作成して、メニューの共通部分をコンポーネント化
export default function MenuLink({
children,
href,
}: {
children: React.ReactNode;
href: string;
}) {
return (
<a href={href} className="hover:underline underline-offset-8">
{children}
</a>
);
}
ヘッダーを固定したことで、ヒーロー部分がかぶるので、margin-topでヘッダーの高さを追加
export default function Hero() {
- return <div>Hero</div>;
+ return <div className="mt-20">Hero</div>;
}
ヒーローを作成
hero.tsx
を編集
+ import mainVisual from "../assets/mainvisual.jpg";
export default function Hero() {
- return <div className="mt-20">Hero</div>;
+ return (
+ <div className="h-screen w-full overflow-hidden">
+ <img
+ src={mainVisual}
+ alt="ヒーロー画像"
+ className="w-full h-full object-cover"
+ />
+ </div>
+ );
}
ヘッダーが透けてしまうので、背景色を追加
の
<header>CSS
に、bg-gray-100/80
を追加
- <header className="h-20 flex justify-between items-center fixed top-0 left-0 right-0 z-10">
+ <header className="h-20 flex justify-between items-center fixed top-0 left-0 right-0 z-10 bg-gray-100/80">
レスポンシブでメニューを開いた時も透けてしまうので、メニューの背景色も追加<ul>
のCSS
にも、bg-gray-100/80
を追加
<ul
className={`lg:flex ${
- isMenuOpen ? "flex text-center text-xl" : "hidden"
+ isMenuOpen ? "flex text-center text-xl bg-gray-100/80" : "hidden"
} flex-col lg:flex-row absolute lg:relative top-20 lg:top-0 left-0 w-full lg:w-auto bg-white lg:bg-transparent`}
>
フッターを作成
footer.tsx
を編集
export default function Footer() {
- return <footer className="mt-auto">Footer</footer>;
+ return (
+ <footer className="lg:h-56 h-64 bg-white">
+ <main className="max-w-5xl mx-auto px-4">
+ <div className="lg:flex justify-between items-center pt-10">
+ <a href="#">
+ <img src="/logo.svg" alt="logo" width="100" height="100" />
+ </a>
+ <section className="text-sm pt-2.5 lg:pt-0">
+ <p>Web Entertainment Design Inc.</p>
+ <p>West Building 3F</p>
+ <p>9-99 Sakuragaokacho Shibuya-ku</p>
+ <p>Tokyo, Japan 150-0031</p>
+ <p>T/99-9999-9999</p>
+ </section>
+ </div>
+ <p className="text-xs pt-10 lg:pt-12">
+ © Web Entertainment Design Inc.
+ </p>
+ </main>
+ </footer>
+ );
}
セクションタイトルコンポーネントを作成
ui
ディレクトリにsection-title.tsx
を作成
export default function SectionTitle({
title,
subTitle,
}: {
title: string;
subTitle: string;
}) {
return (
<div>
<h2 className="text-4xl font-light uppercase tracking-[0.25em]">
{title}
</h2>
<h3 className="text-sm font-light h3t-2.5">{subTitle}</h3>
<hr className="w-10 border-black mt-9" />
</div>
);
}
ニュースを作成
components
ディレクトリにnews.tsx
を作成
import NewsContent from "./ui/news-content";
import SectionTitle from "./ui/section-title";
export default function News() {
return (
<div id="news" className="max-w-5xl mx-auto pt-28 px-4">
<SectionTitle title="news" subTitle="ニュース" />
<div className="lg:flex lg:space-x-5 mt-16 space-y-10 lg:space-y-0">
<NewsContent
date="2022.01.01"
tag="news"
title="タイトルタイトルタイトルタイトル"
/>
<NewsContent
date="2022.01.01"
tag="press"
title="タイトルタイトルタイトルタイトル"
/>
<NewsContent
date="2022.01.01"
tag="news"
title="タイトルタイトルタイトルタイトル"
/>
</div>
</div>
);
}
また、ui
ディレクトリにnews-content.tsx
を作成
export default function NewsContent({
date,
tag,
title,
}: {
date: string;
tag: string;
title: string;
}) {
return (
<div className="flex flex-col justify-center first:pl-0 space-y-4 lg:border-r-2 border-black last:border-r-0 lg:w-1/3 h-20">
<div className="flex space-x-2.5">
<time className="text-sm font-light">{date}</time>
<p className="flex justify-center items-center text-white text-xs font-light bg-black uppercase w-12">
{tag}
</p>
</div>
<p className="font-light">{title}</p>
</div>
);
}
最後に、app.tsx
の<main>を削除して、代わりにNews
コンポーネントを設置
import Footer from "./components/footer";
import Header from "./components/header";
import Hero from "./components/hero";
+ import News from "./components/news";
function App() {
return (
<>
<Header />
<Hero />
- <main className="container mx-auto min-h-dvh">Main</main>
+ <News />
<Footer />
</>
);
}
export default App;
アバウトを作成
components
ディレクトリにabout.tsx
を作成
import about from "../assets/about.jpg";
import SectionTitle from "./ui/section-title";
export default function About() {
return (
<div id="about" className="lg:flex lg:mt-32 pt-24">
<img src={about} alt="" className="lg:h-[400px] lg:w-7/12 object-cover" />
<div className="lg:ml-16 lg:mt-44 mt-8 px-4">
<SectionTitle title="about" subTitle="私たちについて" />
<div className="text-sm lg:mt-12 mt-8 space-y-2">
<p>
テキストテキストテキストテキストテキストテキスト テキストテキストテキストテキストテキストテキスト
</p>
<p>
テキストテキストテキストテキストテキストテキスト テキストテキストテキストテキストテキストテキスト
</p>
<p>
テキストテキストテキストテキストテキストテキスト テキストテキストテキストテキストテキストテキスト
</p>
</div>
</div>
</div>
);
}
app.tsx
にAbout
コンポーネントを設置
+ import About from "./components/about";
import Footer from "./components/footer";
import Header from "./components/header";
import Hero from "./components/hero";
import News from "./components/news";
function App() {
return (
<>
<Header />
<Hero />
<News />
+ <About />
<Footer />
</>
);
}
export default App;
ビジネスを作成
components
ディレクトリにbusiness.tsx
を作成
import business1 from "../assets/business1.jpg";
import business2 from "../assets/business2.jpg";
import business3 from "../assets/business3.jpg";
import business4 from "../assets/business4.jpg";
import BusinessContent from "./ui/business-content";
import SectionTitle from "./ui/section-title";
export default function Business() {
return (
<div id="business" className="max-w-5xl mx-auto px-4 pt-32">
<SectionTitle title="business" subTitle="事業内容" />
<div className="lg:grid grid-cols-2 gap-16 lg:mt-12 mt-8 space-y-8">
<div className="lg:mt-32 space-y-8">
<BusinessContent
title="Web制作・マーケティング"
imageUrl={business1}
/>
<BusinessContent
title="インターネットメディア事業"
imageUrl={business2}
/>
</div>
<div className="space-y-8">
<BusinessContent
title="プロモーション企画・制作"
imageUrl={business3}
/>
<BusinessContent title="ソーシャル企画・運営" imageUrl={business4} />
</div>
</div>
</div>
);
}
また、ui
ディレクトリにbusiness-content.tsx
を作成
export default function NewsContent({
date,
tag,
title,
}: {
date: string;
tag: string;
title: string;
}) {
return (
<div className="flex flex-col justify-center first:pl-0 space-y-4 lg:border-r-2 border-black last:border-r-0 lg:w-1/3 h-20">
<div className="flex space-x-2.5">
<time className="text-sm font-light">{date}</time>
<p className="flex justify-center items-center text-white text-xs font-light bg-black uppercase w-12">
{tag}
</p>
</div>
<p className="font-light">{title}</p>
</div>
);
}
app.tsx
にBusiness
コンポーネントを設置
import About from "./components/about";
+ import Business from "./components/business";
import Footer from "./components/footer";
import Header from "./components/header";
import Hero from "./components/hero";
import News from "./components/news";
function App() {
return (
<>
<Header />
<Hero />
<News />
<About />
+ <Business />
<Footer />
</>
);
}
export default App;
カンパニーを作成
components
ディレクトリにcompany.tsx
を作成
import company from "../assets/company.jpg";
import SectionTitle from "./ui/section-title";
export default function Company() {
return (
<div id="company" className="lg:relative max-w-5xl mx-auto px-4 lg:mb-32">
<div className="bg-white lg:max-w-xl lg:py-24 py-10 lg:px-16 px-4 lg:mt-32 mt-20 h-full">
<SectionTitle title="company" subTitle="会社情報" />
<table className="lg:mt-14 mt-8 text-sm font-light mb-10">
<tr className="flex flex-col lg:block">
<td width="80px" className="lg:h-10">
会社名
</td>
<td className="mb-5">ウェブエンターテイメントデザイン株式会社</td>
</tr>
<tr className="flex flex-col lg:block">
<td width="80px" className="lg:h-10">
所在地
</td>
<td className="mb-5">東京都渋谷区桜丘町99-9 West Building 3F</td>
</tr>
<tr className="flex flex-col lg:block">
<td width="80px" className="lg:h-10">
代表
</td>
<td className="mb-5">XXXXXX</td>
</tr>
<tr className="flex flex-col lg:block">
<td width="80px" className="lg:h-10">
設立
</td>
<td className="mb-5">2021年1月1日</td>
</tr>
<tr className="flex flex-col lg:block">
<td width="80px" className="lg:h-10">
資本金
</td>
<td className="mb-5">3,000,000円</td>
</tr>
<tr className="flex flex-col lg:block">
<td width="80px" valign="top">
事業内容
</td>
<td height="40px" className="lg:space-y-2.5">
<p>Web制作・マーケティング</p>
<p>インターネットメディア事業</p>
<p>プロモーション企画・制作</p>
<p>ソーシャル企画・運営</p>
</td>
</tr>
</table>
</div>
<img
src={company}
alt="会社画像"
className="lg:absolute lg:top-28 right-0 lg:w-1/2 lg:h-2/3 lg:object-cover pt-5 static"
/>
</div>
);
}
app.tsx
にCompany
コンポーネントを設置
import About from "./components/about";
import Business from "./components/business";
+ import Company from "./components/company";
import Footer from "./components/footer";
import Header from "./components/header";
import Hero from "./components/hero";
import News from "./components/news";
function App() {
return (
<>
<Header />
<Hero />
<News />
<About />
<Business />
+ <Company />
<Footer />
</>
);
}
export default App;