概要
webSiteをNext.jsで作成します。
Next.jsの基本構造を理解し、Topページ・お問合せページのコンポーネントを作成します。
完成イメージ
プロジェクト作成
create-next-appを使ってNext.jsのプロジェクトを作成します。
create-next-appは公式のNext.js シングルページアプリケーションを作る方法です。
ボイラープレートを生成してくれます。
npxはパッケージをインストールせずに実行できる便利コマンドなコマンドです。
今回は「next-website」というプロジェクト名で作成していきます。
npx create-next-app@latest next-website
Ok to proceed? (y) と出たらそのままエンターをおします。
Ok to proceed? (y) y
TypeScriptを使うか聞かれますが、今回はJavaScriptを使うのでNoを選択します。
? Would you like to use TypeScript with this project? › No / Yes
ESLintを使うか聞かれるので、Yesにしてすすめます。
ESLintはJavaScriptの記述を統一するのに役立ち、コードを実行する前にバグを見つけることができるので便利です。
? Would you like to use ESLint with this project? › No / Yes
プロジェクト名がフォルダ名となり、フォルダが作成されます。
ガイドのサジェストにも書いてあるとおり、プロジェクトフォルダ内に移動して開発サーバをスタートさせて確認してみます。
cd next-website
npm run dev
windowsでうまく起動しない(SWC Failed to Loadがでる)場合、
.babelrc
ファイルを作成して下記を記述して保存し、もう一度実行してみます。
next/babel プリセットは、React アプリケーションや、サーバーサイドのコードをコンパイルに必要なすべてが含まれます。
{
"presets": ["next/babel"]
}
ローディングが完了したらhttp://localhost:3000 にアクセスするとwebサイトが表示されます。
基本部分編集
VisualStudioCodeでプロジェクトフォルダを開きボイラープレートを編集して不要な部分を削除していきます。
Next.jsでは、ページはpagesディレクトリにある.js, .jsx, .ts, .tsxファイルから書き出されるReact Componentです。各ページは、そのファイル名に基づいてルートと関連づけられます。
index.jsの中身を消して下記のように編集して、http://localhost:3000 にアクセスしたときに表示される内容を変えてみます。
export default function Home() {
return (
<h1>Top</h1>
)
}
変更を加えて保存するとすぐに反映されます(npm run devしたままの状態の場合)。
(デフォルトで設定されているglobal.cssのbackgroundが効いているため背景が変です。)
Top画面を作成する
index.js
index.jsを編集します。
Top画面に中身を追加します。
中身はフロントエンド開発で作成したwebsiteのindex.htmlの中からコピーして作成します。
コピーするのは<main>〜</main>
です。
コピーして、index.jsのreturn ()内に貼り付けます。
export default function Home() {
return (
- <h1>Top</h1>
+ <>
+ <header class="top">
+ <h1 class="top_msg">bluecode, Lifestyle developer.</h1>
+ </header>
+ <main>
+ <section class="content">
+ <h2>websiteの最新情報</h2>
+ <p>最新の情報をご案内します。</p>
+ </section>
+ </main>
+ </>
)
}
<>
<header class="top">
<h1 class="top_msg">bluecode, Lifestyle developer.</h1>
</header>
<main>
<section class="content">
<h2>websiteの最新情報</h2>
<p>最新の情報をご案内します。</p>
</section>
</main>
</>
保存して確認するとすでに反映されています。
(デフォルトで設定されているglobal.cssのbackgroundが効いているため背景が変です。)
スタイル調整
全体に適用するものに関しては、stylesフォルダのglobal.cssに記述し、Topページのみの場合はHome.module.cssに記述するようにします。
一旦global.cssとHome.modules.cssの中身をすべて削除して下記を貼り付けます。
next.jsで自動で生成されるdivに__nextがあり、これがフロントエンド開発で作成したfooterに位置に影響を及ぼすため、height:100%;
を指定しておきます。
html {
height: 100%;
}
#__next {
height: 100%;
}
.App {
height: 100%;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
height: 100%;
}
.top {
/* 背景に取得した画像を設定 */
background-image: url("https://picsum.photos/1000/300");
/* 画像をいっぱいに表示 */
background-size: cover;
/* 表示する高さを画面の40%に */
height: 40vh;
/* 表示幅を画面の90%に */
width: 100%;
/* フレックスボックスを指定*/
display: flex;
/* フレックスアイテムを使って両端から中央に配置*/
justify-content: center;
/* フレックスアイテムを使って上下から中央に配置 */
align-items: center;
/* テキストの配置を中央揃えに */
text-align: center;
}
.top_msg {
/* 文字色を白に */
color: #fff;
}
.content {
width: 90%;
margin: 0 auto;
text-align: center;
}
index.js編集
global.cssは既に適用されていますが(_app.jsで読み込み済みのため)、Home.module.cssを適用するには設定が必要です。
まず、上部でHome.module.cssを読み込みます。
classはclassNameに変更し、Home.module.cssで設定されているものを読み込むので、styles.〇〇という形でclassNameを指定します。
保存したら、Home.jsでHome.cssを読み込みます。
+ import styles from '../styles/Home.module.css';
export default function Home() {
return (
<>
<header class="top">
<h1 class="top_msg">bluecode, Lifestyle developer.</h1>
</header>
<main>
<section class="content">
<h2>websiteの最新情報</h2>
<p>最新の情報をご案内します。</p>
</section>
</main>
</>
)
}
classはclassNameと表現するので、index.js内のclassをclassNameに書き換えていきます。
すべてのclassを下記のように書き換えます。
importしたstylesのtop,title、contentを指すように指定しています。
+ <section className={styles.top}>
- <section class="top">
ここまでの最終的なコードはこちらです。
import styles from '../styles/Home.module.css';
export default function Home() {
return (
<>
<header className={styles.top}>
<h1 className={styles.top_msg}>bluecode, Lifestyle developer.</h1>
</header>
<main>
<section className={styles.content}>
<h2>websiteの最新情報</h2>
<p>最新の情報をご案内します。</p>
</section>
</main>
</>
)
}
Contact画面作成
同様にcontact.jsとContact.module.cssを作成して実装していきます。
touch pages/contact.js styles/Contact.module.css
contact.js編集
編集して、基本構造の中に、contact.htmlの<main>〜</main>
を記述します。
import styles from '../styles/Contact.module.css';
export default function Contact() {
return (
<main class="contact_form">
<h2>お問合せ</h2>
<form>
<div class="form_group">
<label>お名前</label>
<input type="text" id="name" />
<span class="form_error hidden" id="name_error">お名前は必須です。</span>
</div>
<div class="form_group">
<label>email</label>
<input type="email" id="email" />
<span class="form_error hidden" id="email_error">emailは必須かつemailの形式で入力してください。</span>
</div>
<div class="form_group">
<label>お問合せ内容</label>
<textarea id="body" rows={4}></textarea>
<span class="form_error hidden" id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
</div>
<button class="submit_btn" id="submit_btn">送信</button>
</form>
</main >
)
}
スタイル設定
Contact.module.cssにContactに関わるスタイルコピペで記述します。
.contact_form {
padding: 40px 20px;
text-align: center;
}
.form_group {
border-top: 1px solid #ddd;
margin-top: 20px;
padding: 20px 0px;
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.form_group label {
width: 30%;
font-weight: bold;
font-size: 18px;
}
.form_group input,
.form_group textarea {
border: 1px solid #ddd;
border-radius: 6px;
width: 60%;
font-size: 18px;
}
.form_group input {
height: 40px;
}
.submit_btn {
padding: 5px 15px;
background-color: #049dbf;
color: #fff;
border-radius: 5px;
border: 0;
font-size: 16px;
}
.submit_btn:hover {
background-color: #0183a0;
}
.form_error {
padding-left: 30%;
width: 60%;
font-size: small;
color: red;
text-align: start;
padding-top: 10px;
}
/*スマホ対応*/
@media screen and (max-width: 640px) {
/* お問合せフォーム */
.form_group label {
width: 100%;
padding-bottom: 10px;
}
.form_group input,
.form_group textarea {
width: 100%;
margin: 0;
padding: 0;
}
.submit_btn {
width: 100%;
height: 50px;
}
.form_error {
width: 100%;
text-align: left;
padding: 5px 0;
}
}
読み込み、className変更
Contact.module.cssの読み込みとクラス名の編集をして保存します。
エラーを表示する部分は、クラス名がform_errorとhiddenの2つ用意されていました。複数のクラス名を設定する場合下記のように記述できます。
className={`${styles.form_error} ${styles.hidden}`}
が、のちのちreact-hook-formでバリデーションをつけて不要になってしまうので、hiddenクラスを削除して対処しておきます。
import styles from '../styles/Contact.module.css';
export default function Contact() {
return (
<main className={styles.contact_form}>
<h2>お問合せ</h2>
<form>
<div className={styles.form_group}>
<label>お名前</label>
<input type="text" id="name" />
<span className={styles.form_error} id="name_error">お名前は必須です。</span>
</div>
<div className={styles.form_group}>
<label>email</label>
<input type="email" id="email" />
<span className={styles.form_error} id="email_error">emailは必須かつemailの形式で入力してください。</span>
</div>
<div className={styles.form_group}>
<label>お問合せ内容</label>
<textarea id="body" rows={4}></textarea>
<span className={styles.form_error} id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
</div>
<button className={styles.submit_btn} id="submit_btn">送信</button>
</form>
</main >
)
}
保存して確認します。
Next.jsではファイル名がそのままURLになるので、確認するときはhttp://localhost:3000/contact となります。
Contact画面ができました。
最終的なコード
index.js
import styles from '../styles/Home.module.css';
export default function Home() {
return (
<>
<header className={styles.top}>
<h1 className={styles.top_msg}>bluecode, Lifestyle developer.</h1>
</header>
<main>
<section className={styles.content}>
<h2>websiteの最新情報</h2>
<p>最新の情報をご案内します。</p>
</section>
</main>
</>
)
}
contact.js
import styles from '../styles/Contact.module.css';
export default function Contact() {
return (
<main className={styles.contact_form}>
<h2>お問合せ</h2>
<form>
<div className={styles.form_group}>
<label>お名前</label>
<input type="text" id="name" />
<span className={styles.form_error} id="name_error">お名前は必須です。</span>
</div>
<div className={styles.form_group}>
<label>email</label>
<input type="email" id="email" />
<span className={styles.form_error} id="email_error">emailは必須かつemailの形式で入力してください。</span>
</div>
<div className={styles.form_group}>
<label>お問合せ内容</label>
<textarea id="body" rows={4}></textarea>
<span className={styles.form_error} id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
</div>
<button className={styles.submit_btn} id="submit_btn">送信</button>
</form>
</main >
)
}
Contact.module.css
.contact_form {
padding: 40px 20px;
text-align: center;
}
.form_group {
border-top: 1px solid #ddd;
margin-top: 20px;
padding: 20px 0px;
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.form_group label {
width: 30%;
font-weight: bold;
font-size: 18px;
}
.form_group input,
.form_group textarea {
border: 1px solid #ddd;
border-radius: 6px;
width: 60%;
font-size: 18px;
}
.form_group input {
height: 40px;
}
.submit_btn {
padding: 5px 15px;
background-color: #049dbf;
color: #fff;
border-radius: 5px;
border: 0;
font-size: 16px;
}
.submit_btn:hover {
background-color: #0183a0;
}
.form_error {
padding-left: 30%;
width: 60%;
font-size: small;
color: red;
text-align: start;
padding-top: 10px;
}
/*スマホ対応*/
@media screen and (max-width: 640px) {
/* お問合せフォーム */
.form_group label {
width: 100%;
padding-bottom: 10px;
}
.form_group input,
.form_group textarea {
width: 100%;
margin: 0;
padding: 0;
}
.submit_btn {
width: 100%;
height: 50px;
}
.form_error {
width: 100%;
text-align: left;
padding: 5px 0;
}
}
globals.css
html {
height: 100%;
}
#__next {
height: 100%;
}
.App {
height: 100%;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
height: 100%;
}
Home.module.css
.top {
/* 背景に取得した画像を設定 */
background-image: url("https://picsum.photos/1000/300");
/* 画像をいっぱいに表示 */
background-size: cover;
/* 表示する高さを画面の40%に */
height: 40vh;
/* 表示幅を画面の90%に */
width: 100%;
/* フレックスボックスを指定*/
display: flex;
/* フレックスアイテムを使って両端から中央に配置*/
justify-content: center;
/* フレックスアイテムを使って上下から中央に配置 */
align-items: center;
/* テキストの配置を中央揃えに */
text-align: center;
}
.top_msg {
/* 文字色を白に */
color: #fff;
}
.content {
width: 90%;
margin: 0 auto;
text-align: center;
}