5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.jsで簡易コーポレートサイトを作成する #1 -Home/Contactコンポーネント編-

Last updated at Posted at 2023-03-13

概要

webSiteをNext.jsで作成します。
Next.jsの基本構造を理解し、Topページ・お問合せページのコンポーネントを作成します。

完成イメージ

000001.jpg 000010.jpg

プロジェクト作成

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 アプリケーションや、サーバーサイドのコードをコンパイルに必要なすべてが含まれます。

.babelrc
{
    "presets": ["next/babel"]
}

ローディングが完了したらhttp://localhost:3000 にアクセスするとwebサイトが表示されます。
000020.jpg

基本部分編集

VisualStudioCodeでプロジェクトフォルダを開きボイラープレートを編集して不要な部分を削除していきます。

Next.jsでは、ページはpagesディレクトリにある.js, .jsx, .ts, .tsxファイルから書き出されるReact Componentです。各ページは、そのファイル名に基づいてルートと関連づけられます。
index.jsの中身を消して下記のように編集して、http://localhost:3000 にアクセスしたときに表示される内容を変えてみます。

pages/index.js
export default function Home() {
  return (
    <h1>Top</h1>
  )
}

変更を加えて保存するとすぐに反映されます(npm run devしたままの状態の場合)。
(デフォルトで設定されているglobal.cssのbackgroundが効いているため背景が変です。)

000030.jpg

Top画面を作成する

index.js

index.jsを編集します。
Top画面に中身を追加します。
中身はフロントエンド開発で作成したwebsiteのindex.htmlの中からコピーして作成します。
コピーするのは<main>〜</main>です。
コピーして、index.jsのreturn ()内に貼り付けます。

index.js
  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が効いているため背景が変です。)
000040.jpg

スタイル調整

全体に適用するものに関しては、stylesフォルダのglobal.cssに記述し、Topページのみの場合はHome.module.cssに記述するようにします。
一旦global.cssとHome.modules.cssの中身をすべて削除して下記を貼り付けます。
next.jsで自動で生成されるdivに__nextがあり、これがフロントエンド開発で作成したfooterに位置に影響を及ぼすため、height:100%;を指定しておきます。

styles/global.css
html {
  height: 100%;
}

#__next {
  height: 100%;
}

.App {
  height: 100%;
}

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  height: 100%;
}
styles/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;
}

index.js編集

global.cssは既に適用されていますが(_app.jsで読み込み済みのため)、Home.module.cssを適用するには設定が必要です。
まず、上部でHome.module.cssを読み込みます。
classはclassNameに変更し、Home.module.cssで設定されているものを読み込むので、styles.〇〇という形でclassNameを指定します。

保存したら、Home.jsでHome.cssを読み込みます。

index.js
+ 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">

ここまでの最終的なコードはこちらです。

pages/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>
    </>
  )
}
000050.jpg

Contact画面作成

同様にcontact.jsとContact.module.cssを作成して実装していきます。

touch pages/contact.js styles/Contact.module.css

contact.js編集

編集して、基本構造の中に、contact.htmlの<main>〜</main>を記述します。

pages/contact.js
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.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;
    }
}

読み込み、className変更

Contact.module.cssの読み込みとクラス名の編集をして保存します。

エラーを表示する部分は、クラス名がform_errorとhiddenの2つ用意されていました。複数のクラス名を設定する場合下記のように記述できます。

className={`${styles.form_error} ${styles.hidden}`}

が、のちのちreact-hook-formでバリデーションをつけて不要になってしまうので、hiddenクラスを削除して対処しておきます。

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 >
    )
}

保存して確認します。
Next.jsではファイル名がそのままURLになるので、確認するときはhttp://localhost:3000/contact となります。
000060.jpg

Contact画面ができました。

最終的なコード

index.js

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

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.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

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

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;
}

関連コンテンツ

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?