よくJavaScriptで実装されるものをHTML・CSSのみで実装してみた

JavaScriptをあまり使いたくない、使えない。
速度の面やSEOとして、CSSで実装したい。
そんな方のために、JavaScriptで実装されがちなものを、HTML・CSSのみで実装してTipsにしてみました。

IE11〜、iOS Safari 9.2〜、Androidブラウザ4.4〜でだいたい動きます(ベンダープレフィックスが必要な場合も)。
デメリットもあるので、合わせて確認してみてください。

バルーン表示

demo

hoverでバルーン表示
バルーンの説明

HTML・CSS

<div class="hover-balloon">hoverでバルーン表示<div class="hover-balloon__text">バルーンの説明</div></div>

ポイント

「:hover」擬似クラス。トリガーになる要素の子要素などのdisplayプロパティの値を変える。

クリックで他の要素のデザインを変更

demo



ここの要素の色が変わる

HTML・CSS

<label for="check">click1</label>
<label for="check">click2</label>
<input type="checkbox" id="check"><span>ここの要素の色が変わる</span>

ポイント

CSSの「:checked」擬似クラス。

デメリット

タブキー移動に対応していない。これ系は、そのまま使うと全部タブキー移動に対応していないので注意してください。

高さが文字に合わせて可変する入力フォーム

demo

HTML・CSS

<div class="variable-area" contenteditable="true"></div>

ポイント

「contenteditable=”true”」

デメリット

送信ボタン押下時に値を渡せないため、結局JavaScriptが必要。これを使うものはぜんぶそんな感じです。

クレジットカード入力時の区切りのスペースを入れる

demo

HTML・CSS

<div class="credit-card" contenteditable="true"></div>

ポイント

等幅フォントと「column-count」プロパティ(段組み)の組み合わせ。

テキストフォームで補完

demo


HTML

<input name="yourname" autocomplete="on" list="yourname">
<datalist id="yourname">
  <option value="yoshikawa">
  <option value="yoshida">
  <option value="yoneda">
  <option value="yokoyama">
  <option value="yamada">
</datalist>

ポイント

datalist要素。

デメリット

Safari、iOS Safariなど非対応。

Formのバリデーション

demo

必須項目

数字とハイフンのみ



HTML

<input required="required">
<input pattern="^[-0-9]+$">

requiredなどを入れるだけでバリデートしてくれるようになりました。HTML5になって、「type=”tel”」や「type=”email”」やらいろいろ追加されました。

項目を入力したら1つ増やしたい

demo

HTML・CSS

<div class="item" contenteditable="true"></div>
<div class="item" contenteditable="true"></div>
<div class="item" contenteditable="true"></div>
<div class="item" contenteditable="true"></div>
<div class="item" contenteditable="true"></div>
<div class="item" contenteditable="true"></div>

ポイント

「contenteditable=”true”」と「:not(:empty)」の組み合わせ。

デメリット

本当の意味で要素を増やすのは無理なので、あらかじめ用意して「display:none」で隠しておく必要があります。

datepicker的なもの(カレンダー)を実装する

demo

HTML

<input type="date">
PCは未対応が多い。現時点(2017年6月)ではFirefox(PC)は、アドレス欄に「about:config」から「dom.forms.datetime」フラグONでそれっぽいものが表示できます。Macはバグってます。

アコーディオンメニュー

demo

    • 子メニュー1-1
    • 子メニュー1-2
    • 子メニュー2-1
    • 子メニュー2-2
    • 子メニュー2-3
    • 子メニュー2-4

HTML・CSS

<ul class="accordion">
  <li>
    <input type="checkbox" id="accordion-menu-1"><label for="accordion-menu-1">メニュー1</label>
    <ul>
      <li>子メニュー1-1</li>
      <li>子メニュー1-2</li>
    </ul>
  </li>
  <li>
    <input type="checkbox" id="accordion-menu-2"><label for="accordion-menu-2">メニュー2</label>
    <ul>
      <li>子メニュー2-1</li>
      <li>子メニュー2-2</li>
      <li>子メニュー2-3</li>
      <li>子メニュー2-4</li>
    </ul>
  </li>
</ul>

ポイント

「:checked」擬似要素。

Tweetボタン

demo

tweet

CSS

ポイント

Facebook等も同様に。

デメリット

公式の方法ではないため、仕様が変更された場合に対応しなければならない。

カード型デザインで、高さを列の一番高いものに揃える

demo

テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章テスト文章
テスト文章
テスト文章
テスト文章
テスト文章テスト文章テスト文章
テスト文章
テスト文章
テスト文章

CSS

ポイント

「display: flex」「flex-wrap: wrap」。

高さ可変のブロックに、開閉アニメーションをつける

demo

hoverで開閉。

吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。
『吾輩は猫である』

CSS

ポイント

max-heightプロパティに、「ビューポート」基準の値を設定。

デメリット

アニメーションが思いどおりにいかない。

ブロック内にきっちり画像を収める

demo

画像
画像

CSS

ポイント

画像のwidthとheightをautoにしつつ、max-heightとmax-widthに上限を設ける。
IE8にも対応。
「background-size: contain」を背景ではなくimg要素にしたいとき。

ブロック内にきっちり画像を収める2

demo

画像
画像

CSS

ポイント

新しめのプロパティ「object-fit: contain」を指定。
「object-fit: cover」で隙間なく広がる。

スライダー

demo

1
2
3

HTML・CSS

<input type="radio" name="slider-radio" class="slider-radio" id="check-slider-1" checked="checked">
<input type="radio" name="slider-radio" class="slider-radio" id="check-slider-2">
<input type="radio" name="slider-radio" class="slider-radio" id="check-slider-3">
<div class="slider-inner">
  <div class="slider slider-1"><label class="slider-label" for="check-slider-3"><</label><span>1</span><label class="slider-label" for="check-slider-2">></label></div>
  <div class="slider slider-2"><label class="slider-label" for="check-slider-1"><</label><span>2</span><label class="slider-label" for="check-slider-3">></label></div>
  <div class="slider slider-3"><label class="slider-label" for="check-slider-2"><</label><span>3</span><label class="slider-label" for="check-slider-1">></label></div>
</div>

ポイント

ラジオボタンの:checked による、animationの切り替え。

デメリット

スマホで、2回連続同じスライドに行くときに不安定。

モーダルウィンドウ(ポップアップウィンドウ)

demo

HTML・CSS

<label for="modal-check">Open</label><input type="checkbox" id="modal-check"><span class="modal"><label for="modal-check">Close</label></span>

ポイント

チェックボックスの「:checked」擬似クラス。

プレゼンスライド

demo

今回LTで発表した資料(若干修正加えています)。

スライド

ポイント

「:target」擬似クラス。ブラウザの戻る機能で戻れる。
今回のスライドはJavaScriptは使っていません。

デメリット

デメリットしかない。ちゃんとJavaScriptで楽しましょう。

HTML・CSSのみで実装するデメリット

保守性の低下

現在のCSSでは、トリガーになる(状態が変化する)要素の「子要素・子孫要素」や、トリガー要素以降の「兄弟要素(とその子要素・子孫要素)」にしか、変化を適用できない。

:hover、:checked、:target、:focus、:active……。

トリガーになる要素をdivで囲ってしまい、テスト時に動作に気づかずリリース……、なんてことも。

結局JSを使う場合も

編集可能にする「contenteditable属性」を使うと、結局submit時に値を取れないのでJavaScriptで取得する必要がある。また、けっこう使いづらい(コピペをするとスタイルが反映されてしまったりなど)。

ちなみに、Twitterの投稿フォームはこれで実装されています。

アクセシビリティやユーザビリティの低下

チェックボックスやラジオボタンなど、「display:none」で消してしまうと、タブキーで移動できない。

トリガーのためだけにチェックボックスを用意すると、論理構造としておかしなことになる。セマンティックじゃない(JavaScriptを使えば解決するわけでもないけど)。

使いどころ

実際にどういうときに使えばいいのか、というところがあると思うので列挙してみました。

  • ブログに投稿するのにJavaScriptが使えない
  • クライアントにJavaScriptを使わないように言われている
  • AMP対応でJavaScriptが使えない(使える擬似クラスなど限られていますが)
  • 描画速度を優先させたい(必ずしも速くなるわけではないけど、だいたい速い)
  • SEO対策で(一概にCSSのみで実装すればいいといえないですが)
  • ユーザーがスマホ中心なため、非力なスマホでもインタラクションを加えたい

まとめ

JavaScriptとHTML・CSS、どちらで実装するかは、プロジェクトによるかなと思います。
また、Hack的な使い方多いため、
メリット・デメリットをしっかり理解して実装しましょう。