フォームの章分け
フォーム / パターン集トップ
長い問い合わせは fieldset と legend で章に分ける。必須の凡例は先頭に置く
プレビュー#
コピーする#
上のプレビューでつまみを動かし、「生成する」で調整を反映したコードを作ってからコピーしてください。下の欄は生成の元になる型で、直接コピーするものではありません。
<form class="form-sections" action="#" method="post" novalidate>
<!-- 骨格をこちらにしたときは、入力画面の h1 もこの節が持つ。
「フォームの基本形」と二枚重ねにすると、h1 が2つになる -->
<h1>お問い合わせ</h1>
<p class="form-note">「必須」の付いた項目は入力が必要です。</p>
<!-- 各欄の末尾には、空のエラー文の置き場を先に置く。
「エラーサマリー」を足したとき、ここへ同じ文言が書き込まれる -->
<fieldset class="form-sections__group">
<legend>ご依頼内容</legend>
<div class="field">
<label for="fs-topic">ご相談の種類 <span class="req" aria-hidden="true">必須</span></label>
<select id="fs-topic" name="topic" aria-describedby="fs-topic-msg" required>
<option value="">選んでください</option>
<option value="teiki">豆の定期便の申し込み</option>
<option value="mame">豆選びの相談</option>
<option value="kengaku">焙煎所の見学</option>
</select>
<p class="field__error" id="fs-topic-msg" hidden></p>
</div>
<div class="field">
<label for="fs-detail">相談したいこと <span class="req" aria-hidden="true">必須</span></label>
<textarea id="fs-detail" name="detail" rows="5" aria-describedby="fs-detail-msg" required></textarea>
<p class="field__error" id="fs-detail-msg" hidden></p>
</div>
</fieldset>
<fieldset class="form-sections__group">
<legend>連絡先</legend>
<div class="field">
<label for="fs-name">お名前 <span class="req" aria-hidden="true">必須</span></label>
<input id="fs-name" name="name" type="text" autocomplete="name"
aria-describedby="fs-name-msg" required>
<p class="field__error" id="fs-name-msg" hidden></p>
</div>
<div class="field">
<label for="fs-mail">メール <span class="req" aria-hidden="true">必須</span></label>
<input id="fs-mail" name="email" type="email" autocomplete="email"
aria-describedby="fs-mail-msg" required>
<p class="field__error" id="fs-mail-msg" hidden></p>
</div>
<div class="field">
<label for="fs-tel">電話(任意)</label>
<input id="fs-tel" name="tel" type="tel" autocomplete="tel" aria-describedby="fs-tel-msg">
<p class="field__error" id="fs-tel-msg" hidden></p>
</div>
</fieldset>
<!-- 塗りの送信ボタンは、この画面に1つだけ。基本形・エラー表示・ボタン行と
重ねて組むときは、残す1つを決めてほかを消す -->
<button class="button button--primary" type="submit">送信する</button>
</form>
.form-sections {
display: flex;
flex-direction: column;
gap: var(--space-6);
max-inline-size: 32rem;
}
/* 入力画面でただ1つの見出し。章の legend は、この下の階層になる */
.form-sections h1 {
margin: 0;
font-size: var(--text-xl);
line-height: var(--leading-heading);
}
.form-note {
margin: 0;
font-size: var(--text-sm);
color: var(--color-text-muted);
}
.form-sections__group {
margin: 0;
/* fieldset は既定で min-content より狭くならない。textarea の既定の桁数が
そのまま最小幅になり、狭い画面で右へはみ出す */
min-inline-size: 0;
padding: var(--space-5);
border: 1px solid var(--color-border);
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.form-sections__group legend {
font-size: var(--text-lg);
font-weight: 700;
padding-inline: var(--space-2);
}
.field {
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.field label {
font-size: var(--text-sm);
font-weight: 700;
}
.req {
font-weight: 400;
font-size: var(--text-sm);
color: var(--color-text-muted);
}
.field input,
.field select,
.field textarea {
font: inherit;
padding: var(--space-2) var(--space-3);
border: 1px solid var(--color-border);
background: var(--color-bg);
color: var(--color-text);
min-block-size: 2.75rem;
}
.field textarea {
min-block-size: 7rem;
resize: vertical;
}
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
/* 不備が出たときだけ文字が入る。名前は全パターン共通の .field__error */
.field__error {
margin: 0;
font-size: var(--text-sm);
color: var(--color-danger);
}
.field--error input,
.field--error select,
.field--error textarea {
border-color: var(--color-danger);
outline-color: var(--color-danger);
}
/* .button の基底と派生は「出発点のCSS」にある */
.form-sections .button {
align-self: start;
}
確認する#
- legend が fieldset の最初の子になっている(div で包むと読み上げから外れる)
- 章と章の間の余白が欄と欄の間より広い
- 必須の凡例が先頭にあり、各欄のマークと表記が一致している
- 骨格をこちらにしたときは h1 もここが持つ(基本形と二枚重ねにしない)
- 塗りのボタンが画面に1つ(ほかのフォームのパターンと重ねたら、片方を消す)
- 選択肢の言葉が、ほかの画面のダミー文と同じ案件でそろっている