Roa run dev

HTML+CSS+JavaScriptで「お問い合わせフォーム」ページ制作【レシピ】

HTML+CSS+JavaScript【トップページ制作編】の続きの記事になります。

ディレクトリ構成

このディレクトリ構成は、Roa run devコードルールに従っています。

ディレクトリ構成
project-root/
│
├── index.html         
├── contact.html 
├── style.css                
│
└── asset/
    ├── css/
    │   ├── reset.css        
    │   ├── layout.css       
    │   └── component.css    
    │
    ├── js/
    │   └── layout.js        
    │   └── component.js 
    │
    └── images/ 
  • index.html: トップページのHTMLファイル。
  • style.css: ページ全体のスタイルを定義したファイル。
  • reset.css: ブラウザごとのスタイルの違いをリセットするためのCSS。
    • デフォルトのCSSリセット
  • layout.css: ページのレイアウトに関連するスタイル。
    • ヘッダーやフッターのスタイリング
    • ボディーやメイン、セクション関連のスタイリング
  • component.css: ページのコンポーネントごとのスタイル。
    • ハンバーガナビなどのナビやページネーションなども含める
    • タブスライダーなどのアニメーションを持ったUIなど
  • layout.js: ページの動的要素やインタラクションを制御するJavaScriptファイル。

HTML

contact.htmlのform部分

HTML(contact.html)
<section class="section">
  <h2 class="heading02">お問い合わせフォーム</h2>
  <form id="contact-form" class="contactForm" action="submit.php" method="POST">
    <div class="formGroup">
      <label for="name">お名前:</label>
      <input type="text" class="inputText" id="name" name="name" required>
    </div>
    <div class="formGroup">
      <label for="email">メールアドレス:</label>
      <input type="email" class="inputText" id="email" name="email" required>
    </div>
    <div class="formGroup">
      <label for="phone">電話番号:</label>
      <input type="tel" class="inputText" id="phone" name="phone" pattern="\d{3}-\d{4}-\d{4}" placeholder="000-0000-0000">
    </div>
    <div class="formGroup">
      <label for="subject">件名:</label>
      <select class="select" id="subject"  name="subject" required>
        <option value="">選択してください</option>
        <option value="service">サービスについて</option>
        <option value="support">サポートについて</option>
        <option value="other">その他</option>
      </select>
    </div>
    <div class="formGroup">
      <label for="message">メッセージ:</label>
      <textarea class="textarea" id="message" name="message" rows="5" required></textarea>
    </div>
    <div class="formGroup">
      <label for="privacyPolicy">
        <input type="checkbox" class="checkbox" id="privacyPolicy" name="privacyPolicy" required>
      </label>
    </div>
    <button class="contactFormSubmit" type="submit">送信する</button>
  </form>
</section>

CSS

component.cssのform関連一部

CSS(component.css)
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
  お問い合わせフォーム
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
.contactForm {
  width: 100%;
}
.formGroup {
  margin-bottom: 15px;
  padding: 10px;
  background-color: #fff;
}

/* フォーム-アイテム */
.label {
  display: block;
  padding: 10px;
  border: 1px solid #000;
  background-color: #000;
  color: #fff;
  font-weight: 600;
}
.label-privacy {
  display: flex;
  justify-content: center;
  align-items: center;
  border: none;
  margin-top: 10px;
}
label-privacy input[type="checkbox"] {
  width: 30px;
  height: 30px;
}
/*  */
input[type="text"],
input[type="submit"],
button[type="submit"]
select,
textarea {
  display: block;
  font-size: 16px;
}
input:focus,
textarea:focus,
select:focus,
button:focus {
  outline: #ccc;
  border-color: #ccc; 
  box-shadow: none;
}
input[type="checkbox"]  {
  outline: #000;
  border:3px solid #000; 
}
/*  */
.inputBox {
  width: 100%;
  padding: 10px;
  outline: #000;
  border: 3px solid #000; 
}
.textareaBox {
  width: 100%;
  height: 200px;
  padding: 10px;
  outline: #000;
  border:3px solid #000; 
}
.selectBox {
  width: 100%;
  padding: 10px;
  outline: #000;
  border: 3px solid #000; 
}
.checkbox {
  outline: #000;
  border:3px solid #000; 
  width: 30px;
  height: 30px;
}
button.contactFormSubmit {
  max-width: 250px;
  width: 100%;
  padding: 10px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
button.contactFormSubmit:hover {
  background-color: #0056b3;
}

/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
  お問い合わせ-スクロールボックス
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
.contact-scroll-box {
  max-width: 760px;
  width: 100%;
  height: 300px;
  margin: 30px auto 0;
  padding: 30px 15px;
  background-color: #fff;
  border: 1px solid #ccc;
  color: #000;
  overflow-y: scroll;
}
.contact-scroll-box h3
{
  font-size: 16px;
  font-weight: 700;
  line-height: 1em;
}
.contact-scroll-box ol {
  padding-left: 20px;
  list-style: decimal;
}
.contact-scroll-box ol li {
  font-size: 15px;
  line-height: 1.5em;
  font-weight: 400;
  margin-top: 30px;
  counter-increment: number;
}
.contact-scroll-box ol ol {
  font-size: 14px;
  line-height: 1.5em;
  font-weight: 300;
  margin-top: 15px;
  padding-left: 20px;
  list-style: none;
  counter-reset: number;
}
/*★★★min-width 768★★★*/
@media screen and (min-width: 768px) {
  .contact-scroll-box h3
  {
    font-size: 18px;
    font-weight: 700;
  }
  .contact-scroll-box ol li {
    font-size: 16px;
  }
  .contact-scroll-box ol ol {
    font-size: 14px;
  }
}

JS

component.jsのformの一部

JavaScript(component.js)
document.getElementById('contact-form').addEventListener('submit', function(event) {
  event.preventDefault();

  const name = document.getElementById('name').value.trim();
  const email = document.getElementById('email').value.trim();
  const phone = document.getElementById('phone').value.trim();
  const subject = document.getElementById('subject').value;
  const message = document.getElementById('message').value.trim();
  const privacyPolicy = document.getElementById('privacyPolicy').checked;

  let hasError = false;
  clearErrors();

  // バリデーション
  if (name === "") {
    setError('name', 'お名前を入力してください。');
    hasError = true;
  }

  if (!/^[\w\-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email)) {
    setError('email', '有効なメールアドレスを入力してください。');
    hasError = true;
  }

  if (!hasError) {
    alert('フォームが送信されました!');
  }
});

function setError(id, message) {
  const element = document.getElementById(id);
  const errorElement = document.createElement('p');
  errorElement.className = 'error-message';
  errorElement.textContent = message;
  element.parentElement.appendChild(errorElement);
}

function clearErrors() {
  const errors = document.querySelectorAll('.error-message');
  errors.forEach(error => error.remove());
}

まとめ