模写修行メディア

コピペで使える!HTML・CSSでフォームをおしゃれにカスタマイズする方法

コピペで使える!HTML・CSSでフォームをおしゃれにカスタマイズする方法

この記事をシェア:

コーディングをしていて意外と面倒なのがフォームのカスタマイズです。

ブラウザによって見た目がまちまちで、サイトのデザインとマッチしないことも多くあります。ただ、デフォルトのスタイルをリセットしてカスタマイズしようにも、HTMLの他の要素と違って色々と面倒な点もあります。

また、カスタマイズする際はアクセシビリティにも考慮しなければいけません。

昔の自分もそうでしたが、アクセシビリティを無視したカスタマイズ方法を紹介しているサイトも多くあります。

フォームのデザインは、オシャレにする必要はありません。ユーザにとってわかりやすいものにすることがベストです。

一度作ればその後もコピペで使いまわせるので、効率的です。

この記事では最低限のアクセシビリティを意識した、フォームのカスタマイズを紹介します。

フォームをカスタマイズする際に気をつけること

カスタマイズする際に1番見落としがちなことが、アクセシビリティへの考慮です。

  • 何らかの理由でキーボードのみで操作している方
  • 視覚に障がいがあり音声読み上げ機能を使っている方

例えば、webサイトはこのような方も使うことを考慮して、誰でもなるべく便利に使えるように作るべきです。

ここではアクセシビリティ対応を含め、最低限気を付けないといけないことを紹介します。

outlineを消さない

  • デフォルトのスタイルをリセットするため
  • フォーカスリングの見栄えが悪い

主にこれらの理由より、outline: none;outline: 0;を使っているケースがありますが、これはNGです。

キーボードのみで操作している方は、tabキーでフォーム内を移動します。outline: none;outline: 0;を使ってしまうとフォーカスが当たらず、現在どこにいるのかわからなくなってしまいます。

それでもやっぱりフォーカスリングの見栄えが悪いのでoutlineを消したいこともあります。

  1. :focus-visible を使う
  2. what-input を使う

キーボード操作以外ではフォーカスリングを消したい場合、上のどちらかで対応出来ます。(もしかしたら他にも方法あるかも?)

1はSafariとIEが対応していないので、Polyfillを使います。この記事の解説では1を使っています。

display: none;にしない

詳しくは後述しますが、ラジオボタンやチェックボックスをカスタマイズする際は、デフォルトの input タグを見た目上消します。

その際にdisplay: none;を使ってしまうと、tabキーでのフォーカスや選択が出来なくなります。

inputを見た目上消したい場合は、display: none;ではなく、opacity: 0;positionで画面外に飛ばして消しましょう。

フォントサイズは16px以上にする

iOSではフォントサイズが16pxより小さいとフォーム入力時に画面がズームされます。個人的にこのズームは結構煩わしさを感じます。

16px以上にすることが無難ではありますが、どうしても16pxより小さくしたい場合は、transform: scale();でスケーリングすれば、ズームされずに小さく出来ます。

HTML・CSSでフォームをカスタマイズする方法

まずは制作したデモページをご覧ください。シンプルなデザインになっています。

  • テキスト
  • ラジオボタン
  • チェックボックス
  • セレクトボックス
  • テキストエリア
  • 送信ボタン

カスタマイズする要素は上の6つです。フォームで使う要素は他にもありますが、この記事ではよく使うこれら6つに絞って解説します。

リセットCSSはハード系を使えばほぼ見た目は同じになるはずです。

html {
    color: #000;
    background: #fff;
}

body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
code,
form,
fieldset,
legend,
input,
textarea,
p,
blockquote,
th,
td {
    margin: 0;
    padding: 0;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

fieldset,
img {
    border: 0;
}

address,
caption,
cite,
code,
dfn,
em,
strong,
th,
var {
    font-style: normal;
    font-weight: normal;
}

ol,
ul {
    list-style: none;
}

caption,
th {
    text-align: left;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-size: 100%;
    font-weight: normal;
}

q:before,
q:after {
    content: "";
}

abbr,
acronym {
    border: 0;
    font-variant: normal;
}

sup {
    vertical-align: text-top;
}

sub {
    vertical-align: text-bottom;
}

input,
textarea,
select,
button {
    font-family: inherit;
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    *font-size: 100%;
}

legend {
    color: #000;
}

*::before,
*::after {
    box-sizing: border-box;
}


/* base */
/* ---------------- */

* {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-family: "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
    box-sizing: border-box;
}

body {
    line-height: 1.8;
    line-height: 2;
    font-size: 18px;
}

a {
    text-decoration: none;
    color: inherit;
}

img {
    width: 100%;
    height: auto;
    vertical-align: bottom;
}

全く同じように作りたい方は、上のリセットCSSを使ってみてください。

OSブラウザ
MacSafari、Chrom、Firefox
WindowsChrom、Firefox、Edge 、IE
iOSSafari、Chrom
AndroidChrom

ブラウザ対応はこの通りです。全て最新版でチェックしました。

<script src="https://cdn.jsdelivr.net/npm/focus-visible@5.2.0/dist/focus-visible.min.js"></script>

前述した通り、focus-visibleのPolyfillを使うので、上のコードを読み込んでください。バージョンが最新かどうかは、こちらでご確認ください。

テキスト編

inputテキストのカスタマイズ
<input type="text" name="" value="" class="m-form-text" />
.m-form-text {
    height: 2.4em;
    width: 100%;
    padding: 0 16px;
    border-radius: 4px;
    border: none;
    box-shadow: 0 0 0 1px #ccc inset;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
}

.m-form-text:focus {
    outline: 0;
    box-shadow: 0 0 0 2px rgb(33, 150, 243) inset;
}

appearance: none;を入れることでデフォルトのスタイルをいくつか取り除くことができます。

  • 通常時はボーダーを1px
  • フォーカス時はボーダーを2px

フォーカス時はボーダーを目立たせるために2pxにしています。これをborderでやるとフォーカス時にがたつくので、ボーダーはbox-shadowで付けています。box-shadowでフォーカスがわかるようにしているので、outline: 0;しても大丈夫です。

ラジオボタン編

ラジオボタンのカスタマイズ
<div class="">
    <label>
        <input type="radio" name="radio" value="1" />
        <span class="m-form-radio-name">
            <span class="m-form-radio-text">ラジオボタン1</span>
        </span>
    </label>
</div>

<div class="">
    <label>
        <input type="radio" name="radio" value="2" />
        <span class="m-form-radio-name">
            <span class="m-form-radio-text">ラジオボタン2</span>
        </span>
    </label>
</div>
.m-form-radio input {
    position: absolute;
    white-space: nowrap;
    width: 1px;
    height: 1px;
    overflow: hidden;
    border: 0;
    padding: 0;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    margin: -1px;
}

.m-form-radio-name {
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    color: #666;
}

.m-form-radio-name:before {
    content: "";
    display: inline-block;
    width: 1em;
    height: 1em;
    border: 1px solid #ccc;
    border-radius: 50%;
    margin-right: 4px;
    flex-shrink: 0;
}

.m-form-radio input:checked + .m-form-radio-name:before {
    border: 0.3em solid rgb(33, 150, 243);
}

.m-form-radio input:checked + .m-form-radio-name {
    color: rgb(33, 150, 243);
}

.m-form-radio input:focus + .m-form-radio-name {
    color: rgb(33, 150, 243);
}

.m-form-radio input.focus-visible + .m-form-radio-name .m-form-radio-text {
    background: linear-gradient(transparent 90%, rgba(33, 150, 243, 0.3) 90%);
}

まずはinputを消しています。前述した通り、ここでdisplay: none;を使ってはいけません。

あとは擬似要素のbeforeを使って、ラジオボタンを作っているだけです。

選択された時のスタイルは隣接セレクタを上手く使えばOKです。

.m-form-radio input.focus-visible + .m-form-radio-name .m-form-radio-text {
    background: linear-gradient(transparent 90%, rgba(33, 150, 243, 0.3) 90%);
}

上のコードはtabキーで操作してフォーカスした際はテキストに下線を引くようにしています。マウスやトラックパットでの操作でもこのスタイルを付けてしまうと、フォーカスが外れたときに、選択も外れてしまったように見えてしまうので、tabキーでの操作に限定しています。

focus-visibleのPolyfillを使えば、.focus-visibleを付けた時が、:focus-visibleと同じになります。つまりtab キーで操作した時だけ適応されるということです。

チェックボックス編

チェックボックスのカスタマイズ
<div class="">
    <label>
        <input type="checkbox" name="checkbox" value="checkform-item1" />
        <span class="m-form-checkbox-name">
            <span class="m-form-checkbox-text">チェックボックス1</span>
        </span>
    </label>
</div>

<div class="">
    <label>
        <input type="checkbox" name="checkbox" value="checkform-item2" />
        <span class="m-form-checkbox-name">
            <span class="m-form-checkbox-text">チェックボックス2</span>
        </span>
    </label>
</div>

<div class="">
    <label>
        <input type="checkbox" name="checkbox" value="checkform-item3" />
        <span class="m-form-checkbox-name">
            <span class="m-form-checkbox-text">チェックボックス3</span>
        </span>
    </label>
</div>
.m-form-checkbox input {
    position: absolute;
    white-space: nowrap;
    width: 1px;
    height: 1px;
    overflow: hidden;
    border: 0;
    padding: 0;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    margin: -1px;
}

.m-form-checkbox-name {
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    color: #666;
    position: relative;
}

.m-form-checkbox-name:before {
    content: "";
    display: inline-block;
    width: 1em;
    height: 1em;
    border: 1px solid #ccc;
    border-radius: 3px;
    margin-right: 6px;
    flex-shrink: 0;
}

.m-form-checkbox input:checked + .m-form-checkbox-name:before {
    border: 1px solid rgb(33, 150, 243);
    background-color: rgb(33, 150, 243);
}

.m-form-checkbox input:checked + .m-form-checkbox-name:after {
    content: "";
    position: absolute;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    left: 0.3em;
    top: 0;
    bottom: 0;
    margin: auto;
    width: 0.4em;
    height: 0.6em;
    transform: translateY(-2px) rotate(45deg);
}

.m-form-checkbox input:checked + .m-form-checkbox-name {
    color: rgb(33, 150, 243);
}

.m-form-checkbox input:focus-visible + .m-form-checkbox-name .m-form-checkbox-text {
    background: linear-gradient(transparent 90%, rgba(33, 150, 243, 0.3) 90%);
}

.m-form-checkbox input.focus-visible + .m-form-checkbox-name .m-form-checkbox-text {
    background: linear-gradient(transparent 90%, rgba(33, 150, 243, 0.3) 90%);
}

ラジオボタンとほぼ同じなので説明は割愛します。

セレクトボックス編

セレクトボックスのカスタマイズ
<div class="m-form-select">
    <select>
        <option value="select1">セレクト1</option>
        <option value="select2">セレクト2</option>
        <option value="select3">セレクト3</option>
        <option value="select4">セレクト4</option>
        <option value="select5">セレクト5</option>
        <option value="select6">セレクト6</option>
    </select>
</div>
.m-form-select {
    position: relative;
}

.m-form-select:before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
    right: 12px;
    width: 8px;
    height: 8px;
    border-top: 2px solid #333;
    border-right: 2px solid #333;
    transform: rotate(135deg);
    pointer-events: none;
}

.m-form-select select {
    height: 2.4em;
    width: 100%;
    padding: 0 8px;
    border-radius: 4px;
    border: none;
    box-shadow: 0 0 0 1px #ccc inset;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    cursor: pointer;
}

.m-form-select select::-ms-expand {
    display: none;
}

.m-form-select select:focus {
    outline: 0;
    box-shadow: 0 0 0 2px rgb(33, 150, 243) inset;
}

IE以外はappearance: none;を入れるとデフォルトの矢印は消えます。IEでも消すためには、::-ms-expanddisplay: none;する必要があります。

テキストエリア編

テキストエリアのカスタマイズ
<textarea name="name" class="m-form-textarea"></textarea>
.m-form-item-textarea textarea {
    height: 300px;
}

.m-form-textarea {
    display: block;
    width: 100%;
    padding: 4px 16px;
    border-radius: 4px;
    border: none;
    box-shadow: 0 0 0 1px #ccc inset;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    resize: vertical;
}

.m-form-textarea:focus {
    outline: 0;
    box-shadow: 0 0 0 2px rgb(33, 150, 243) inset;
}

テキストとほぼ同じです。

textareaはほとんどのブラウザで、ユーザーがリサイズできるようになっています。resize: vertical;を入れておくと横方向のリサイズを、向こうにできます。

サブミットボタン編

サブミットボタンのカスタマイズ
<!-- inputタグを使う場合 -->
<input type="submit" name="" value="送信" class="form-submit-button" />

<!-- buttonタグを使う場合 -->
<button type="submit" class="form-submit-button">送信</button>
.m-form-submit-button {
    display: inline-block;
    width: 100%;
    padding: 8px;
    border: none;
    border-radius: 4px;
    background-color: #333;
    color: #fff;
    font-weight: bold;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    cursor: pointer;
    border: 2px solid transparent;
}

.m-form-submit-button:hover {
    background-color: #000;
}

.m-form-submit-button:focus {
    outline: 0;
    background-color: #000;
    border: 2px solid rgb(33, 150, 243);
}

特別難しいことはしていません。デフォルトのスタイルを消して、独自にスタイリングしているだけです。

Netlifyを使えばサーバーサイドの知識0でフォームを実装することも可能!

サイトを制作する際にフォームを設置する機会は多くあります。

NetlifyのForms機能を使うと、サーバーサイドの知識0でも簡単にオリジナルのデザインでフォームの実装が可能です。興味がある方は、ぜひ下記の記事も覗いてみてください。

NetlifyのForms機能でフォームを作る方法!サーバーサイドの知識0で実装可能!

コーディングの練習が出来るサービス「模写修行」を作りました 🎉

模写修行のトップページのスクリーンショット

「模写修行」はこんな方におすすめ!

  • 基礎学習を終えて実践的な経験を積みたい
  • 破綻しない書き方を学びたい(= CSS設計を意識したコーディングを学びたい)
  • 実務と同じようにXDのデータを見ながらコーディングの練習をしたい
  • 現役で制作をやっている人のコードを見たい

基礎学習を終えた方が次にやるべきことは、実践に近い形でたくさん練習することです。そして、わからないことがあれば、その都合調べて理解する。この繰り返しでコーディングやプログラミングは上達します。

「模写修行」ではデザインデータ(XD) / web上で見れる解説 / サンプルコードを配布しています。ご自身でデザインを見ながらコーディングに挑戦し、解説とサンプルコードで深く学ぶことができるサービスです。

この記事をシェア:

模写修行のトップページのスクリーンショット
模写修行

駆け出しエンジニアのためのコーディング練習教材