見出し画像

Day 7: Googleマップのボタンを雲の形にする

今制作しているwebアプリのボタンを、雲を連想させる形にデザインして実装した。

制作しているのはGoogleマップを用いた地図アプリなので、ユーザーのいる現在位置を表示させるためのボタンや、ユーザーが興味を持った場所を保存するためのボタンが必要である。

地図アプリにふさわしいボタンってなんだろう?と考えた結果、雲しかない、と思った。地図は、空高くから見下ろした街の風景であり、その街の風景には、所々雲がかかるから。

☁️ ☁️ ☁️

この記事では、私がどのようにして web アプリのボタンを雲を連想させる形にしたかを記録する。デザインだけでなく、HTML/CSS コードの話も含めて。さらに、雲形ボタンにどのようにして影をつけたか、また、フォーカス・ステートをどのようにデザイン・実装したか、も説明する。

web アプリのボタンをちょっと変わった形にしたい、と思った人の参考になれば幸いである。

1. なぜ雲のボタン?

雲のようなボタンを作るに至った経緯を、もう少し詳しく説明してみる。

My Ideal Map App (私が作成中のアプリ名)のデザイン・コンセプトは、"Dye Me In Your Hue From The Sky"(「空からあなた色に私を染めて」)。ユーザーが興味のある場所を保存することで、誰のものでもないGoogleマップを「自分色」に染める。その染める作業は空から行われる。なぜなら、地図は、空から見た街の景色だから。

画像2

空から見た街の風景(画像元:朝日航空

このコンセプトに基づいた UI デザインにふさわしいボタンは何だろう?

地図は画面いっぱいに表示され、その上にボタンが表示される。つまり、ボタンは、空から見た街の風景の上に表示される。飛んでいる飛行機の窓から下を見下ろした時に、大地の上に見えるものとは何か?

そう、雲である。

画像2

ロンドン中心部の航空写真(画像元: Wirestock via Freepick

ボタンが雲の形をしていれば、空から地図を自分色に染める、という My Ideal Map App のデザイン・コンセプトがより明確になる。

アプリを作り始める前に、主要な機能の本質を的確に表すデザインコンセプトを明確にしておいたのが、功を奏した(詳しくは過去記事を参照)。ボタンを雲の形にするなんてアイデアは、デザインコンセプトがなかったら思いつくことはなかっただろう。デザインコンセプトを作ることの大切さを改めて認識した。

2. 雲のような形のボタンをデザインする

しかし、ボタンはあくまでボタンであって、リアルな雲の形にしてしまえば、ユーザーはボタンと認識せず、タップしようとしないだろう。雲っぽいけどボタンだよな、とユーザーに思わせるようにデザインしなくてはならない。

紙にスケッチしてみる。増山修というスタジオジブリでアニメーション美術監督をしていた人が書いた本『学校では教えてくれない風景スケッチの法則』に、雲は様々な大きさの円を重ねた形として描ける、とのアドバイスがあったを思い出し、三つの大きさの異なる円を少しだけずらして重ねてみた。三つの円で十分なはず。四つ以上になると、「ボタン」よりも「雲」に近づいてしまう。

しかし、うまくいかない。。。

ふと、クラウドサービスによく使われる雲の形のアイコンはどんな形をしているのだろう、と疑問に思い、Google による Material Icons の雲アイコンを調べてみた。

画像3

Material Icons の雲アイコン(画像元: Google Fonts

三つの円が、高さをずらして横に並べられている。左側の円は真ん中の円よりも少し下に、右側の円はもっと下に、配置されている。

スケッチが上手なわけではないので、円を綺麗に書くことができないのも、うまくいかない理由っぽかったので、今度は、Sketch で三つの円を描き、配置をこの雲アイコンっぽくしてみた。

まず、直径36pxの円を描く。この円をコピーして、左側に10pxずらし、さらに下側に8pxずらす。最初の円をもう一度コピーして、今度は、右側に10px、下側に12pxずらす。そうしてできたのがこの形。

画像4

雲の形をしたボタン(著者作成)

異なる大きさの三つの円でも試したが、リアルになりすぎてボタンっぽくなくなった。シンプルに、同じ大きさの三つの円で作った方が、「ボタン」らしさと「雲」らしさのバランスがちょうどいい、とわかった。

3. ボタンのラベル

My Ideal Map App は四つのボタンを最初に表示するが、この記事ではそのうちの一つ、メニューボタンだけを取り扱う。そうしないと、ボタンの配置の話もしなくてはならなくなり、この記事を全部読むのに30分以上かかってしまう(汗)。

メニューボタンのラベルとしては、いわゆる「ハンバーガー」アイコンを使う。

画像8

Material Icons のメニューアイコン(画像元: Google Fonts

SVGデータを、Google Fonts からダウンロードし、Sketch にインポートして、雲ボタンの上に重ねる。縦横共に中央揃えにして、できたボタンをSVG画像としてエクスポート。このデータをもとに、HTMLコードを作る。

画像10

Sketch アプリで作成した雲形メニューボタン(筆者作成)

4. HTMLコードにSVGを埋め込む

SVG画像をボタンのラベルとして使うには、<button>タグで<img>タグを囲み、src要素の値としてSVG画像ファイルを指定するというやり方がある。

しかし、今回は、雲の形をしたSVG画像そのものをボタンにしたい。ユーザーがタップしたり、ダークモードにすることで、自由にボタンの色や影を変えるには、HTMLコードにSVGコードを埋め込む方法の方が、何かと都合がいい(詳しくは、Coyier 2013 を参照)。

ウェブ・プログラミング習いたての頃は、SVGコードに取っ付きにくさを感じていたが、ある時一念奮起して、W3Schools の SVG TutorialCopes (2018) を熟読することで、基本的なことを理解してからは、SVG画像を使う時は、HTMLコードに埋め込んで使うようになった。その結果、コードで実現できるウェブデザインの幅が随分と広がった。

さて、具体的なコード作業に入る。まずは、ボタン。

<button type="button">
</button>

<button>タグを用いることで、スペースキーを押すとボタンをクリックさせることができるようになる(Coyier 2020)など、色々便利なことがある。type属性は、"button"とする。何かデータをアップロードするボタンではないし(その場合は "submit")、フォームに入力した文字を消去するボタンでもない(その場合は "reset")から。

次に、<svg>要素を <button> の子要素として、以下のように書き込む。

<button type="button">
  <svg viewBox="0 0 56 48"
       width="56px"
       height="48px"
       role="img"
       aria-labelledby="accessible-name">
    <title id="accessible-name">
      Show menu
    </title>
    <--! SVG image data to be inserted -->
  </svg>
</button>

<svg>要素の属性のうち、一番重要なのは viewBox。SVG画像を収めるボックスの座標軸と大きさを指定する。最初の二つの数字がボックスの左上の座標を決め、残りの二つの数字がボックスの横と縦の長さを指定することで結果として右下の座標を決める。Sketch からエクスポートした雲形ボタンの場合は、ボックスの左上の座標が (0,0) で、右下が (56,48)。この座標を元に、様々な形の輪郭線が通る場所を指定するのが、SVGコードの基本原理。

width 属性と height 属性は、本来不要なはずなのだが、これを指定しないと、ボタンのラベルとして使うSVGアイコン画像を Safari が表示してくれない(理由は不明)。画像サイズの指定は、SVGの存在意義を否定してしまうのだが、ボタンはスクリーン幅が大きくなっても同じサイズにする予定なので、とりあえず問題はないと思う。

次の role="img" は、盲目・弱視の人が利用するスクリーンリーダーが画像を読み飛ばさないようにするため(Fischer 2021)。

aria-labelledby 属性は、SVG画像の内容説明としてスクリーンリーダーが読み上げる言葉(いわゆる alt text)が記述されているHTML要素の id 属性を指定する。ここでは、"accessible-name"と指定することで、その id 属性を持っている <title> 要素を指定している。この <title> 要素に、alt text を記述する。(詳細は、Migliorisi 2016 を参照)。

ここでは、メニューボタンなので、"Show menu" としている。画像がボタンやリンクの役割を果たしている時、alt text は画像の説明ではなく、ボタンやリンクの説明になる。この辺の alt text の詳しいことは、私が以前書いた英語ブログ記事(Kudamatsu 2021)を参照。

なお、Sketch などの画像編集ソフトから SVG 画像をエクスポートすると、<svg>要素の属性が他にも色々くっついてくる。HTMLコードに埋め込んで使う場合には、そのどれも必要ない。SVG画像ファイルとして使う場合には、xmls属性が必要になる。詳しくは、Longson (2013) を参照。

ここまでが前置きで、ようやくSVG画像データそのものについての話ができる。Sketchからエクスポートされたのは以下の二つの <path> 要素。これを、<title>要素の後、</svg>タグの前に挿入する。

<path
  d="M45.4620546,13.6147645 C51.6790144,16.4506152 56,22.7206975 56,30 C56,39.9411255 47.9411255,48 38,48 C32.9385058,48 28.3649488,45.9108926 25.09456,42.5479089 C22.9175971,43.482463 20.5192372,44 18,44 C8.0588745,44 0,35.9411255 0,26 C0,17.9805361 5.24437759,11.1859622 12.4906291,8.85878199 C15.6225135,3.55654277 21.3959192,0 28,0 C36.428553,0 43.5040602,5.79307725 45.4620546,13.6147645 Z"
  id="cloud"
/>
<path
  d="M4.5,27 L31.5,27 L31.5,24 L4.5,24 L4.5,27 Z M4.5,19.5 L31.5,19.5 L31.5,16.5 L4.5,16.5 L4.5,19.5 Z M4.5,9 L4.5,12 L31.5,12 L31.5,9 L4.5,9 Z"
  id="material-icon-menu" 
  transform="translate(10.000000, 6.000000)"
/>

一つ目が、雲形ボタン。雲の色を指定するときに必要になるので、id属性を"cloud"とする(詳しくは後述)。

二つ目が、ボタンのラベルとしてのメニューアイコン。何のアイコンかわかるようにid属性を付けておいた。transform属性は、<svg>要素のviewBox属性が設定した座標軸上で、アイコンをx軸に10、y軸に6、移動させて、中央揃えにしている。

<svg>要素は、一つ目の子要素の上に二つ目の子要素を重ねて描画するので、雲形ボタンの上にアイコンを表示させるには、アイコンの方を二つ目に記述する。

この二つの<path>要素のd属性の値として出てくる、コンマを挟んで隣り合う二つの数字は、<svg>要素のviewBox属性が設定した座標軸上の点。その前にくっついているアルファベットは、その点に移動する(M)のか、ベジエ曲線を描く(C)のか、線を引く(L)のか、といったことを指定する。詳しくは、MDN Contributors (2021) を参照。こういうことを理解しておくと、ちょっとした画像修正を自分でできるようになるのでオススメ。

以上でHTMLコードは完成。次はCSS。

5. Styled Components を使って CSS コードを指定する

CSS の使い方は人それぞれだが、私は Styled Components を愛用している。最近、Styled Components などの、いわゆる CSS-in-JS (JavaScript を使って CSS を指定する方法論)は、Webページの表示速度を遅くする、という記事を幾つか読んだ(Arvanitakis 2019Dodds undated)。しかし、表示速度が遅くなるのは、CSS-in-JS の特定の使い方のためであり、CSS-in-JS そのものには問題がない、と理解している。

私の Styled Components の利用の仕方は、他の人と異なるかもしれない。まず、目的ごとに CSS declarations をまとめて、JavaScript の変数として定義する。そして、それらの変数を用いて、コンポーネントを作る。具体的には以下の通り。 

まず、<button>要素を指定するとデフォルトで表示される border を消して、ボタンの色を透明にするためのCSSコードを`resetStyle`として保存する。

import {css} from 'styled-components';

const resetStyle = css`
  background-color: rgba(255,255,255,0);
  border: none;
`;

雲の形をしたボタンに見せたいので、その外側に表示されてしまうデフォルトの四角いボタンを消す必要があるから。

次に、ボタンの大きさを指定するCSSコードを `setClickableArea` として保存。

const setClickableArea = css`
  height: 48px;
  width: 56px;
`;

こうすることで、雲形ボタンの周りの縦48px、横56pxの四角い範囲をユーザーがタップ(またはクリック)するとボタンが押されるようになる。この大きさならば、ボタンは少なくとも縦横44pxの大きさにするべき、という WCAG 2.1 の要件を満たす(WCAG 2.1 第2.5.5節を参照)。また、Google による縦横48pxの要件も満たす(Gash et al. 2020)。

そして、SVG画像が、この縦48px、横56pxの四角い範囲の真ん中に来るようにするためのCSSコードを`alignButtonLabel`として保存する。

const alignButtonLabel = css`
  align-items: center;
  display: flex;
  justify-content: center;
`;

これを指定しないと、SVG画像が左寄せになってしまう。

最後に、以上三つの変数を用いて、<button>要素のスタイルを指定して、<Button>という、React コンポーネントと同様に扱えるコンポーネントを作る。

import styled from 'styled-components';

const Button = styled.button`
  ${resetStyle}
  ${setClickableArea}
  ${alignButtonLabel}
`;

このようにコードを書くことで、<Button>コンポーネントがどのようにスタイルされているのかが、すぐわかる。

このコードの書き方は、最近話題になった Cube CSS という方法論を参考にした。Cube CSS では、一つ一つの目的ごとに class を作る。Styled Components で同じことをするにはどうすればいいか、と考えた結果、JavaScriptの変数にすればいいと思いついた。

さて、後するべきは、ボタンの色と影の設定である。

6. ボタンの色指定

塗りつぶしの色は、rgba(255, 255, 255, 0.93)。つまり、透明度が7%の純白。

雲は白い。そして、半透明にすることで、その下の地図をうっすらを見せることで、地図の上に雲が浮かんでいるという印象を与える。透明度7%という値は、ボタンとして認識されるかどうか(透明すぎるとボタンではなくなる)、及び、浮かんでいるように見えるかどうか、という二つの要件のバランスがちょうどいい値として選んだ。

雲形ボタンのSVGデータは、<button>要素の子要素である<svg>要素内の<path id="cloud">という要素で定義している(上記参照)ので、以下のように色を指定する。

button #cloud {
 fill: rgba(255, 255, 255, 0.93);
}

ラベルの色は、rgb(90, 90, 90)。このグレーは、真っ黒(#000000)との明度比が 3.04:1 である。後述するが、ユーザーがマウスカーソルをボタンの上に動かした時(hover state)、及び、Tabキーでボタンを選択した時(focus state)に、ラベルの色を真っ黒に変更することで、変化を十分に認識してもらうため。

ボタンラベルの色指定は以下のようにする。

button svg {
  fill: rgb(90, 90, 90);
}

<svg>要素の fill プロパティーを設定することで、その子要素である <path> 要素にも適用させる。ただし、雲の形を指定する <path id="cloud"> 要素には、既に fill プロパティーを直接指定しているので適用されない。

輪郭線の色は、rgb(148, 148, 148)。これは、雲の白色と、地図中の道路の白色(Day 4 を参照)が区別できるようにするため。

地図の配色には、道路の純白 (#ffffff) から市街地のグレー (#898989) までの明度差がある。雲の半透明の白は、このグレーを背景にしたとき、明度差が十分にあるので、雲と市街地が重なっても、雲ボタンをはっきり認識できる。

画像7

rgba(255,255,255,0.93) と #898989 の明度比(画像元:contrast-ratio.com

しかし、白い道路を背景にすると、当然区別がつかなくなる。明度比が 3:1 を満たすようなグレーを選んだ結果、rgb(148,148,148)となった。

画像8

rgb(255,255,255) と rgb(148,148,148) の明度比(画像元:contrast-ratio.com

雲の形の輪郭線の色をCSSで指定する方法は以下の通り

button #cloud {
 stroke: rgb(148, 148, 148);
}

しかし、ここまで明度がはっきりと異なるグレーを輪郭線に用いると、正直言ってダサい。。。

そこで、雲形ボタンに影をつけることで、輪郭線と影の境界をボカして、地図の上に浮いて見えるようにしたい。

7. ボタンに影をつける

ボタンに影をつけることには、見栄えの悪い輪郭線をごまかすだけでなく、ボタンとして認識してもらいやすくするという効果がある。Google が、15人の弱視の人にインタビューした結果、影や輪郭線がある方が、クリックしたりできるUI要素だと認識しやすい、と答えたそうだ(Google undated)。

CSS で影をつけるには、影の位置、影のぼかし具合、そして、影の色を指定する必要がある。通常は、box-shadow という プロパティーを利用するが、四角ではないSVG画像に影をつけるには、filterプロパティーを用いて、drop-shadow()というCSS関数をプロパティー値に設定する(Olawanle 2021)。

影の位置を決めるには、(想像上の)光源がどこにあるのかを決める必要がある。多くの場合、光源はwebページの上側、ないし、左上側に設定される。人間は上からの光が作る影を見ると、奥行を認識するそうだ(Livingstone 2014, chap 11)。太陽はいつも上から大地を照らすからだろう。

しかし、My Ideal Map App のデザイン・コンセプトは、光がユーザーの後ろから、すなわち、スクリーンの手前から差し込んでいる、という設定を要求する。地図は、空から真下を見下ろした時の風景である、という解釈を前提としているから。太陽は頭の後ろ側にある。

従って、My Ideal Map App では、光源がスクリーンの手前にあると想定し、影をボタンなどのUI要素の四方八方に薄く広がるようにする。つまり、drop-shadow()関数の最初の二つの引数は (0 0) になる。影の中心は、ボタンの中心と一致する。

影のぼかし具合は、blur radius と呼ばれる値で設定する。これが 0px であれば、ボタンと同じ大きさの影が、ボタンの下に輪郭のぼかし無しに描かれる。しかし、現実には影の端っこははっきりしない。影を作る物体から離れれば離れるほど、四方八方から降り注ぐ反射光(空気中の水分子や、室内の天井や壁が反射した光)が物体に遮られることなく地面を照らす度合いが増えるから。これをスクリーン上で再現するための方法が blur radius。例えば、1px と設定すると、影の端から1px内側で、影の色の透明度が0%となり、影の端から1px外側で透明度100%、影の端では透明度50%となる。

しかし、実際の影は、影の端へ向かうに従って一定率で透明度が増えるわけではない。透明度の増加率はだんだん減少する。これを表現するために、Ahlin (2019) は、影を幾つか重ねて、blur radius をだんだん加速度的に増やしていく方法を提案している。それに倣って私が設定したCSSコードは以下の通り。

button svg {
 filter: 
   drop-shadow(0 0 1px rgba(0,0,0,0.33)) 
   drop-shadow(0 0 2px rgba(0,0,0,0.33))  
   drop-shadow(0 0 4px rgba(0,0,0,0.33));
}

影の色を rgba(0,0,0,0.33) (透明度67%の黒)として(理由は後述)、三枚の影を重ねている。こうすることで、重ね合わされた結果としての影の濃さが、ボタンから離れていくほど薄くなり、その薄くなる速度はだんだん遅くなる。

影の色は、基本、半透明の黒であるべき。影は、反射して目に届く光の量が周辺と比べて少ないことによって、地面などの表面の色が暗く見える現象。スクリーン上では、半透明の黒を重ねることで、表面の色を残しつつ、光の量を減らすことができる。

では透明度は幾つにするべきか。

影が一番濃いボタンの端の部分で、透明度を58%にしたい。なぜなら、透明度58%の黒(rgba(0, 0, 0, 0.42))は、白を背景とした時に、上述のボタンの輪郭線の色(rgb(148, 148, 148))と同じ明度になるから。

画像9

画像10

rgba(0, 0, 0, 0.42) 及び rgb(148, 148, 148) の白に対する明度比(画像元: contrast-ratio.com

こうすることで、輪郭線と影の境目を曖昧にし、ボタンの輪郭線を影の一部として認識させることが可能になる。

しかし、rgba(0, 0, 0, 0.42) をそのまま drop-shadow() 関数の引数として指定する影の色にしてしまうと、ボタンの端の部分の影の透明度はもっと低くなってしまう。これには二つ理由がある。まず、上述の blur radius の説明で書いた通り、例えば、blur radius が 1px であれば、指定した影の色になるのは、影の「端」から 1px 内側。影の「端」では、rgba(0, 0, 0, 0.21) になる。もう一つの理由は、上述の通り、影を三枚重ねにしているので、実際に見える影の濃さは、rgba(0, 0, 0, 0.21) の三倍になる。

これらを考慮して計算した結果、影の色を rgba(0, 0, 0, 0.33) にすれば、ボタンの端で、rgba(0, 0, 0, 0.42) と同等の濃さの影にできることがわかった。詳しい計算過程は省くが、基本となる考え方は、透明度50%(rgba(0, 0, 0, 0.5))の影を二つ重ねると、0.5x0.5=0.25 なので、透明度25%(rgba(0, 0, 0, 0.75))になる、という仮定。厳密に正しいかどうかわからないが、近似値としてはそれほど間違っていないと思う。計算には透明度を用いて、でも色の指定には透明度を1から引いた値を用いるので、頭が混乱しやすいのだが、冷静になれば計算できる。

というわけで、影の指定のための CSS コードは、再掲になるが、以下のようになる。

button svg {
 filter: 
   drop-shadow(0 0 1px rgba(0,0,0,0.33)) 
   drop-shadow(0 0 2px rgba(0,0,0,0.33))  
   drop-shadow(0 0 4px rgba(0,0,0,0.33));
}

そして、雲形ボタンは以下のように表示される。

画像15

Googleマップの上に表示された雲形ボタン(筆者によるスクリーンショット)

☁︎ ☁︎ ☁︎

しかし、ボタンのデザインはまだ終わっていない。UIデザインにおいて重要なのは、ユーザーによる操作へのフィードバック。ボタンにまつわるユーザーの操作に対応した色の変化をデザインする必要がある。

8. フォーカス・ステート(及びホバー・ステート)

「フォーカス・ステート」(focus state)とは、マウスではなくキーボード操作でwebサイトを閲覧する人(盲目・弱視のためスクリーンリーダーを利用する人を含む)が、Tabキーを何度か押して、Enterキーで押したいボタンを選択した時に、表示される UI のことである。大多数のマウスやスマホでwebサイトを見る人にとっては無関係なのだが、だからといって無視していいことではない。ボタンやリンクのデザインでは必ずデザインすべきことである(Bailey 2018, Sticka 2018)。

また、マウスを使って閲覧する人のために、「ホバー・ステート」もデザインしなくてはならない。マウスがボタンの上を通った時に、ボタンが反応するようにすることで、ボタンが押せる、というシグナルを出す。スマホが普及する前は、この「ホバー・ステート」のデザインにウェブデザイナーがこだわっていたが、2021年の今となっては、「フォーカス・ステート」と同じで良い、という意見が多く(例えば、Maza 2019)、それに従う。

フォーカス・ステートのデザインにはいつも悩む。とりあえず選択肢を全部見たい。そうすれば、その中でどれが使えそうかの判断ができる。そんな時に役立つのが、Maza (2019) によるデザイン例の一覧。大きく分けて5通りある。背景色を変える、文字の色を変える、影を加える、サイズを大きくする、アウトラインをつける。

背景色は変えたくない。雲は白い。他の色にしてしまったら雲ではなくなる。影を加えるのも無理。もう既に加えてしまっている。サイズを大きくするのは、2010年代のウェブデザインで、少しダサいし、My Ideal Map App のデザイン・コンセプトにそぐわない。

文字の色を変えるのは可能。文字ではなくてアイコンだが、上記の通りデフォルトでグレー(rgb(90, 90, 90))なので、これを黒に変更することができる。

button:focus svg,
button:hover svg {
  fill: rgb(3, 3, 3);
}

黒といっても、rgb(0, 0, 0) は避ける。有機EL(OLED)スクリーン上で生じる "black smear" (「黒い油っぽい汚れ」) と呼ばれる現象を防ぐため(Edwards 2018 などを参照)。なお、フォーカス・ステートとホバー・ステートを同様にデザインしたいので、button:focus と button:hover の両方をセレクターとして指定している。

しかし、これだけでは、ボタンがフォーカスされた合図としてはインパクトが弱い。そこで、もう一つの手段、アウトラインをつける必要がある。

アウトラインをデザインする上で参考にしたのが Coyier (2012)。2012年当時の Twitter で、書き込みをする時にテキスト入力欄に表示されるアウトラインを再現するCSSコードを紹介している。方法としては、Twitter のブランドカラーである青で、1pxの幅の border を付け、さらに同じ色の「影」(位置はテキスト入力欄の真下、blur radius は 5px)を付ける。こうすることで、青い光が、テキスト入力欄の周りに点灯する。この方法を踏襲することにした。

画像14

テキスト入力欄にフォーカスされていることを示す青い光の枠(画像元: Coyier 2012

でも問題は色である。配色に困った時は、デザイン・コンセプトを視覚化したムードボードに立ち返るのが鉄則。雲の周りを光らせるのにふさわしい色として、この写真の湖に映る空の色を採用した。

画像11

アイスランド北部のアルデイヤルフォスの滝(画像元:Shivesh Ram via National Geographic

Mac OS の Digital Colour Meter で色を採取し、自作の web アプリ Triangulum Color Picker で RGB コードを入力。色相を一定にし、純色の割合も一定にしたまま、雲形ボタンの色である白との明度比が1:3になるように、明度を調節した結果、rgb(69, 159, 189) という値を得た。

画像12

Triangulum Color Picker で rgb(69, 159, 189) を指定した時のスクリーンショット(筆者作成)

この色を、雲の輪郭線、および影の色として、<button>要素が focus された時、および hover された時のスタイルとして指定する。

button:focus #cloud,
button:hover #cloud {
 stroke: rgb(69,159,189);
}

button:focus svg,
button:hover svg {
 filter: drop-shadow(0 0 5px rgb(69,159,189));
}

SVGの場合、輪郭線をスタイルするには、border プロパティーではなくて、stroke プロパティーを使う。この stroke プロパティーを svg 要素に指定しまうと、アイコンラベルの輪郭線も色が変わってしまうので、雲の形を指定する <path id="#cloud"> 要素だけに指定するようにする。 

以上の結果、雲形ボタンのフォーカス・ステートはこのように表示される。

画像16

雲形ボタンのフォーカス・ステート(筆者によるスクリーンショット)

と、ここまで終えてから気づいたのが、色盲のユーザーにとっては、このフォーカス・ステートはデフォルトと全く同じように見えるのではないか、ということ。rgb(69, 159, 189) は、デフォルトの影と明度がほぼ同じ(どちらも白との明度比が3:1になるように選んだから)。かつ、どちらもぼやけている。。。

いい方法がすぐに思いつかないので、このままアプリの開発を続けつつ、いずれフォーカス・ステートについて再考することにする。何かのきっかけでパッと思いつくかもしれないので。

フォーカス・ステートのデザインにはいつも悩む。。。

そして、ボタンのデザインはまだ終わらない。最後にボタンが押された時のスタイルを決める必要がある。

9. アクティブ・ステート

「アクティブ・ステート」とは、ボタンやリンクが押された直後の0.1秒ぐらいの瞬間のUIのこと。ボタンが押された、ということをユーザーに知らせるために必ず必要なスタイルである。

Google が ripple effect と呼ばれる水の波紋のようなアニメーションを「アクティブ・ステート」に採用して以来、多くのウェブサイトが真似している。個人的にも好きなデザインなのだが、My Ideal Map App のデザイン・コンセプトに合うか、というと微妙なので今のところ却下。

ボタンが押され、約0.1秒間の「アクティブ・ステート」が表示される直前に、スマホなどキーボード操作をしない場合でも「フォーカス・ステート」が瞬間的に表示される。また、「アクティブ・ステート」が終了した後は「フォーカス・ステート」になる。したがって、「フォーカス・ステート」のスタイルを「アクティブ・ステート」において無効にすると、一瞬だけ点滅したようになり、視覚的にボタンが押されたことを表現できる。そのための CSS コードはこちら。

 button:active #cloud {
   stroke: none;
 }
 
 button:active svg {
   filter: none;
 }

ボタンのラベルであるアイコンの色も瞬間的に無効にするために、デフォルトのグレーに戻す。

button:active svg {
 fill: rgb(90, 90, 90)
}

以上で、ボタンのデザインが、とりあえずひと段落した。

画像13

左:デフォルト、中:フォーカスおよびホバー・ステート、右:アクティブ・ステート(筆者作成)

次のステップ

しかし、ボタンについてはデザインすべきことがまだ二つ残っている。まず、複数のボタンを画面上にどのように配置するか。そして、ダークモード用の配色を影やフォーカス・ステートも含めてどうするか。

この二つについてもこの記事で書こうとすると、読み終わるのに40分以上もかかる記事になってしまう(汗)ので、次回以降、二回に分けて書いていきます。

ここまで読んでくれて、ありがとうございました。簡単に作れそうに見えるwebアプリのボタンには、色々な判断の積み重ねが隠れている、ということが伝われば幸いです。

注: この記事は、英語で書いた同内容の記事を和訳すると同時に日本人向けに編集したものです。

Changelog

Oct 4, 2021 (v1.0.1): viewBox属性について説明している段落を修正。

引用文献

Ahlin, Tobias (2019) “Smoother & sharper shadows with layered box-shadows”, tobiasahlin.com, Sep 19, 2019. 

Arvanitakis, Aggelos (2019) “The unseen performance costs of modern CSS-in-JS libraries in React apps”, Web Performance Calendar, Dec 9, 2019.

Bailey, Eric (2018) “Focusing on Focus Styles”, CSS-Tricks, Mar 29, 2018.

Copes, Flavio (2018) “An in-depth SVG tutorial”, flaviocopes.com, Apr 6, 2018.

Coyier, Chris (2012) “Glowing Blue Input Highlights”, CSS-Tricks, Apr 11, 2012.

Coyier, Chris (2013) “Using SVG”, CSS-Tricks, Mar 5, 2013.

Coyier, Chris (2020) “A Complete Guide to Links and Buttons“, CSS-Tricks, Feb 14, 2020.

Dodds, Kent C. (undated) “Use CSS Variables instead of React Context”, Epic React, undated.

Edwards, Marc (2018) “I’m not a fan of pure black in UI…”, Twitter, Oct 20, 2018.

Fischer, Carie (2021) “Good, Better, Best: Untangling The Complex World Of Accessible Patterns”, Smashing Magazine, Mar 16, 2021.

Gash, Dave, Meggin Kearney, Rachel Andrew, and Rob Dodson (2020) “Accessible tap targets”, web.dev, Mar 31, 2020.

Kudamatsu, Masa (2021) “Mastering the art of `alt` text for images”, Web Dev Survey form Kyoto, May 19, 2021.

Livingstone, Margaret S. (2014) Vision and Art: the Biology of Seeing (Revised and Expanded Edition) (Abrams).

Longson, Robert (2013) “All user agens (browsers) ignore the version attribute...”, Stack Overflow, Aug 27, 2013.

Maza, Lari (2019) “Having a Little Fun With Custom Focus Styles”, CSS-Tricks, Dec 2, 2019. 

MDN Contributors (2021) “d”, MDN Web Docs, Sep 24, 2021 (last updated).

Migliorisi, Heather (2016) “Accessible SVGs”, CSS-Tricks, Jul 6, 2016.

Olawanle, Joel (2021) “Adding Shadows to SVG Icons With CSS and SVG Filters”, CSS-Tricks, Jun 11, 2021.

Sticka, Tyler (2018) “Designing Button States”, Cloud Four, March 13, 2018.



この記事が気に入ったらサポートをしてみませんか?