🎯

HTMLでボタンを作るとき使うべき要素は <input>?<button>?

2022/11/13に公開

🌼 はじめに

フロントエンドエンジニアなら誰でも一回はボタンコンポーネントを作ったこと、もしくは使ったことがあるのではないかと思います。私もUI実装のときよく触ってました。

最近 <input type="button" value="保存" /> のようなボタンコンポーネントを見かけて、「なんで buttonじゃないんだろう、てかなんでボタン作る要素が buttoninput の2つあるわけ?」という気持ちになりました。

気になったら調べるしかないので、今から調査結果を共有します。

1. input要素とbutton要素は似てる

さっそくフォームの中にinput要素とbutton要素でボタンを作ってみました。

<form action="">
    <label>
        好きな食べ物は?
        <input type="text" />
    </label><br />

    <div class="buttonArea">
        <div class="buttonAreaTitle">input タグのボタン</div>
        <input type="submit" value='type="submit"' /><br />
        <input type="button" value='type="button"' /><br />
        <input type="reset" value='type="reset"' /><br />
    </div>

    <div class="buttonArea">
        <div class="buttonAreaTitle">button タグのボタン</div>
        <button type="submit">type="submit"</button><br />
        <button type="button">type="button"</button><br />
        <button type="reset">type="reset"</button><br />
    </div>
</form>

ボタン自体はCSS何も書いてないのでデフォルトデザインが表示されてます。input要素と button要素の見た目が同じですね。

実は各typeごとの機能も同じです。テキスト入力欄に何か入力してからボタンを押してみるとその違いが観察できるので試してみてください。

  • type="submit"
    • ボタンを押したらフォームが送信される
    • フォームがリロードされ、テキスト入力欄も初期化される
  • type="button"
     - ボタンを押したら何も起きない
     - フォームも送信されず、入力した値も残ってる
  • type="reset"
    • ボタンを押したらフォームが初期化される
    • フォームは送信されない(リロードされない)
    • 入力欄を空欄にするのではなく、初期値に戻す(初期値がない場合空欄に戻す)

typeごとにこんな違いがあるとも知りませんでした。なるほど、これでボタンの目的に合うtypeを選べるようになりました。

それはいいですが、「見た目も機能も同じなら結局何が違うんだ?」という気持ちもあります。それもまた調べてきました。

2. 終了タグの有無が違う

1番の違いは終了タグの有無です。input要素は終了要素を持たないのでラベル文字列を value 属性で渡す反面、button要素は開始タグと終了タグの間にラベル文字列を入れるというところです。

それがなにか?と思うかもしれませんが、終了タグがあるということはタグの内容にimgなど画像データを入れ子にすることもできるし、疑似要素も作れるのでもっと柔軟なスタイリングができます。

試しにinput要素とbutton要素両方使って同じデザインのボタンを作ってみました。アイコンの幅は無視してテキストがボタンの真ん中に来る、アイコンはテキストの左隣という要件を想定してます(サイドバー開いたらコードも見れます)

button要素の場合、テキストを真ん中にするためにテキストにアイコンの幅分のmargin-rightを与えました(ベスプラかはわかりませんw)。これで文言が長くなっても短くなってもUIは崩れないのでよしとします!

input要素の場合はボタン内のアイコンをposition: absolute;で浮かせ、leftプロパティを固定値で指定することで位置を調整してます。今は一旦これでそれっぽくなりましが、ボタンラベルの文言が変わったらアイコン位置も一緒に調整しないといけなく、メンテコストが高くなります。また、固定値だとブラウザや端末によって表示が変わるかもしれないという不安が常に心の中に潜むことになるでしょう。ラベルテキストにスタイルを当てられないことが不便ですね。

input要素でも CSS を頑張ればスタイリングはできるけど button要素のほうがもっと柔軟にスタイリングできる、という感じですね。

3.button要素はinput要素の進化版

これで2つの要素の共通点と違いは理解できました。が、まだ「なぜボタン作る要素が2つなのか」という疑問は残ってます。

その答えはMDNにありました。

メモ: <input> 要素の button 型は完全に妥当な HTML ですが、より新しい <button> 要素が、ボタンの作成にはより好まれるようになりました。 <button> のラベル文字列は開始タグと終了タグの間に挿入され、ラベルに画像を含む HTML を含めることができます。
https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/button

なるほど、button要素のほうがinput要素より後で追加された要素ということですね。

ちなみにbutton要素は HTML4 で追加されたようです。「HTML 4.0 Specification」の17-5に明記されてました(もう20年以上前だった)。
https://www.w3.org/TR/1998/REC-html40-19980424/interact/forms.html#h-17.5

ということは、昔はinput要素でしかボタンを作れなかったけど、もっといい感じにボタンを作るためbutton要素が追加されたということですね!すっきりしました。

でもbutton要素を使うときは一つ注意点があります。

button要素にtypeを指定しない場合、自動的にデフォルト値であるsubmitのボタンになるということです。

<!-- 両方 type="submit" のボタン -->
<button>ボタン</button>
<button type="submit">ボタン</button>

ということは、フォーム送信目的じゃないボタンを作るときbutton要素のtype指定は省略できないということになります。(省略したらフォームを送信しちゃうから)

まあtype省略しても Javascript でフォーム送信せず望む動きだけさせることもできますが、面倒だしボタンの意味合い的にも合わない気がするのでtype=buttonを指定したほうがいいかなと思います。

4. まとめ

  • input要素のボタンとbutton要素のボタン両方妥当な HTML です。
  • button要素のほうがスタイリングが柔軟にできるので特に理由がなければbutton要素を使いましょう。
  • button要素デフォルトtypesubmitなので、フォーム送信目的のボタンじゃない場合はtype="button"を指定しましょう。

🌷 終わり

inputtype="image"もフォームを送信するボタンらしいですね(全然知らなかった)
https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/image

GitHubで編集を提案

Discussion