Like Button

特定の対象に対する「いいね!」の気持ちを表すボタンです。

May 14, 2019

Code

HTML

<button class="like-button" type="button" aria-label="いいね!" aria-pressed="false">
  <span class="like-button__inner">
    <svg class="like-button__icon like-button__icon_like" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <use xlink:href="/images/markups/like-button/like.svg#icon-like"></use>
    </svg>
    <svg class="like-button__icon like-button__icon_liked" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <use xlink:href="/images/markups/like-button/like.svg#icon-liked"></use>
    </svg>
    <span class="like-button__label">いいね!</span>
  </span>
</button>

CSS

.like-button {
  display: inline-block;
  padding: 0 5px;
  color: #000;
  border: 1px solid currentColor;
  background-color: #fff;
  font: inherit;
}

.like-button__inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.like-button__icon {
  width: 1.5em;
  height: 1.5em;
  fill: currentColor;
}

.like-button__icon_liked {
  display: none;
}

.like-button__label {
  margin-left: 5px;
}

.like-button_pressed {
  color: #fff;
  background-color: #000;
}

.like-button_pressed .like-button__icon_like {
  display: none;
}

.like-button_pressed .like-button__icon_liked {
  display: block;
}

JavaScript

function likeButton(button) {
  const pressedClass = "like-button_pressed";
  let pressed = button.classList.contains(pressedClass);

  function press() {
    pressed = true;
    button.classList.add(pressedClass);
    button.setAttribute("aria-pressed", "true");
  }

  function unpress() {
    pressed = false;
    button.classList.remove(pressedClass);
    button.setAttribute("aria-pressed", "false");
  }

  button.addEventListener("click", function(e) {
    pressed ? unpress() : press();
  });
}

Array.prototype.slice
  .call(document.querySelectorAll(".like-button"))
  .forEach(likeButton);

Usage

コードをコピペして使う

コードをコピペし、使用してください。必要に応じて内容を修正してください。

CDN経由でカスタム要素として使う

使用したいページの <head>内に次のタグを貼り付けます。

<script async src="https://unpkg.com/@micromarkups/like-button@1/markup-like-button.js"></script>

<markup-like-button>タグで要素を使います。詳細な使い方は解説を参照してください。

<markup-like-button label="いいね!" pressed></markup-like-button>
インストールしてカスタム要素として使う

npm installコマンドを使ってコンポーネントをインストールします。

npm install --save @micromarkups/like-button

JavaScriptに読み込んで使用します。

import '@micromarkups/like-button'

<markup-like-button>タグで要素を使います。詳細な使い方は解説を参照してください。

<markup-like-button label="いいね!" pressed></markup-like-button>

Explanation of Markup

Sorry, the description is currently only available in Japanese.

いいねボタンは、押されているかどうかの状態を持っているボタンです。同様なボタンに、お気に入りに登録・解除するボタンや、再生・一時停止ボタンなどがあります。このような性質のボタンはトグルボタンや、フリップフロップボタンとも呼ばれます。

いいねボタン実装上の観点は、マークアップからスタイリングまで多岐にわたります。分量が多いですが、ひとつずつ解説していきます。

マークアップ

button 要素を使う

いいねボタンは「クリックできるボタン」なので、マークアップには button 要素を使います。 a はあくまでも別の場所を参照するためのハイパーリンクです。 button 要素を使うと、ボタンに適切に意味付けがなされます。また、キーボードフォーカスが当たるようになり、Enterキーやスペースキーを使ってボタンのクリックができるようになります。状態が切り替わるという観点で type="checkbox"input 要素を使う選択肢もありますが、ここでは押せるボタンを目指しているため、 button 要素を使って進めていきます。

type="button" 属性を常に付けることをおすすめします。デフォルトの type 属性の値は submit であるため、先祖要素に <form> がある場合、そのフォームが送信されてしまうからです。多くの場合は意図しない動作です。

ボタンの名前を指定する

aria-label 属性を使ってそのボタンを表す名前を付けます。たいていの場合、ボタンの中に表示されているテキストと同じテキストになります。いいねボタンの場合、ボタンの名前は「いいね!」とします。これをスクリーンリーダーで読み上げると「オフ いいね ボタン」などと読まれます。

押された状態を表現する

ボタンが押された状態を aria-pressed 属性を使って表現します。押されている場合 true を、押されていない場合 false を値に使います。 aria-pressed 属性はWAI-ARIA 1.0の仕様で定義されています。HTMLがもともと持っているセマンティクスを拡張して、ボタンが押されている状態を表現できます。

加えて、ボタンが押されているときは button 要素のクラス名に like-button_pressed モディファイアを追加します。このクラス名を使ってCSSでスタイルを割り当てます。

button 要素直下に span 要素を配置する

現実的なプラクティスとして、 button 要素直下に span 要素を配置すると役に立つことがあります。手癖のように書くようにしておくといいでしょう。具体的には、IEで button 要素がFlexコンテナになれないバグがあります。同じくIEで、ボタン押下時に内容が右下に押し下がる効果を無効化するためにも必要です。

.like-button__inner {
  position: relative; /* IE でボタン押下効果を無効化する */
}

アイコンフォントを避け、SVGでアイコンを表示する

手軽にアイコンを利用する手段としてアイコンフォントが知られています。ですが、アイコンフォントにはアクセシビリティと堅牢性の観点で弱点があります。

  • スクリーンリーダーに予期しない読まれ方をする可能性がある
  • ユーザーが独自のフォントを設定していると表示されない可能性がある

SVGアイコンにこれらの弱点はありません。SVGアイコンを積極的に使うようにしましょう。SVGアイコンでも色を変化させたり、大きさを変えることは可能です。

このコードでは、SVGアイコンの表示のために、 svg 要素と use 要素を組み合わせて使用しています。いわゆるSVGスプライトと呼ばれるテクニックです。複数のアイコンデータを収めたSVGファイルをあらかじめ用意しておき、 use 要素を使って参照しています。

<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
  <use xlink:href="images/like.svg#icon-like"></use>
</svg>
<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="icon-like" viewBox="0 0 24 24">
    <path d="...省略..."/>
  </symbol>
  <symbol id="icon-liked" viewBox="0 0 24 24">
    <path d="...省略..."/>
  </symbol>
</svg>

SVGアイコンの作り方は紹介したSVGスプライト以外にも、SVGを直接記述する方式や img タグを使う方式があります。それぞれ特徴や制約が異なります。SVGスプライトを自動的に生成する仕組みもしばしば使われます。興味があれば調べてみるとよいでしょう。

ラベルのないボタン

ボタンにテキストラベルが不要な場合、 like-button__label をトルツメするだけでOKです。ボタンの名前は aria-label 属性で指定されているため、ラベルをトルツメしてもアクセシビリティ上の問題にはなりません。

スタイリング

ボタンのスタイルをリセットする

button 要素が持っているスタイルは上書きできます。見た目を気にして button 要素を避ける必要はありません。次のコードは button 要素のスタイルを打ち消す指定です。

.like-button {
  padding: 0;
  color: inherit;
  border: 0;
  background-color: transparent;
  font: inherit;
}

アイコンの色とサイズを変える

CSSの fill プロパティを使うと、SVGの図形の塗りに色を指定できます。 fill のデフォルト値は黒です。 fill: currentColor を設定すると、現在の color プロパティの値を使うようになります。

.like-button__icon {
  fill: currentColor;
}

この指定により、テキスト色の設定とアイコン色の設定が連動するようになります。

/* テキストとアイコン両方がピンク色になる */
.like-button {
  color: hotpink;
}

widthheight の単位に em を使うと、フォントサイズとアイコンサイズが連動します。

/* フォントサイズとアイコンサイズが連動する */
.like-button__icon {
  width: 1.5em;
  height: 1.5em;
}

押された状態を色だけで表現しない

押されたか、押されてないかを表すために、色以外の要素も使いましょう。コード例ではアイコンを「✔」に切り替えて押下状態を表現しています。より多様なユーザー、環境で使えるボタンになります。参考: WCAG 1.4.1

動作や状態をラベルにしない

「いいね! しない」「いいね! 済み」といった動作や状態をラベルにするとユーザーを混乱させることがあります。色や形によるボタンの見た目の変化と相まって、ラベルが現在の状態を表すのか、押した後の状態を表すのか不明瞭になるからです。混乱を招かないために、ラベルにはボタンや機能の名前を表示しましょう。また、状態は見た目で判別できるようにするといいでしょう。

判断に迷ったら、ボタンがチェックボックスだった場合に置き換えて考えるとわかりやすくなるでしょう。例えば次のようなチェックボックスだったら違和感を感じます。

いいね! いいね! 済み

この場合、「済み」を削除すれば違和感はなくなります。

いいね! いいね!

フォーカス状態をわかるようにする

ブラウザが表示するフォーカスリングをできるだけ消さないようにしましょう。あるいは、フォーカス状態の表現を検討してください。フォーカスリングは、キーボードで操作しているユーザーにとっては極めて重要な存在です。

しかし、マウスやタッチでボタンをクリックしたときにフォーカスリングが出てしまう挙動がどうしても許容されないケースはあるでしょう。その場合、focus-visibleというJavaScriptライブラリを使用することをおすすめします。

focus-visibleを使用するには、次のコードをHTMLに埋め込みます。

<script src="https://unpkg.com/focus-visible"></script>

CSSには次のようなスタイルを追加します。このようにすると、クリック時のフォーカスリングを非表示にし、キーボードを使ったときのみフォーカスリングが表示されるようになります。

.js-focus-visible :focus:not(.focus-visible) {
  outline: 0;
}

Internet Explorer対応

サンプルではSVGスプライトを別ファイルとして用意し、use 要素の xlink:href 属性を使って読み込んでアイコンを表示していました。この手法は実はIEでは動作しません。IEでも外部のSVGスプライトを利用するにはポリフィルライブラリを使います。次のコードをHTMLに埋め込むことで、IEでもアイコンが表示されるようになります。

<script src="https://unpkg.com/svg4everybody"></script>
<script>svg4everybody()</script>