GMail のボタンに関する考察

お久しぶりです。id:moshimonry です。

3 ヶ月ぶりくらいの日記ですが、ちゃんと生きてました。会社をクビになったわけでもありません。

ファンの方は心配されたかも知れませんが、id:moshimonry は今日も元気に会社に泊まってますw

さて、本題

最近、障害などもあって、モテモテな GMail が結構素敵なことになっています。

まだ Google Apps の方がテーマ対応してはいないものの、細かい所でデザインが洗練されています。

特に今回着目したのが「ボタン」です。

と言っても「立てば芍薬、座れば牡丹、歩く姿は百合の花」のボタンではありません。

………ごめんなさい。

「検索」とか「移動」とかのボタンです。

かなり、OS 標準のボタンっぽい感じになっており、視覚的に「あ、これはボタンだな」って分かりやすいように感じます。

しかも、背景がグラデーションしてるので、盛り上がった感じの表示です。

「画像でやってるのかなぁ?」と思ったら、流石は Google 先生。なんと div タグと CSS (とちょっとの JavaScript) で構築されています。(たぶん)

勝手に色々解読してみたので、以下に記したいと思います。

HTML

完全に解析した訳じゃないので、一部想像が入っていますので、突っ込みお待ちしています。

流石に本家のソースを丸っと表現するのもアレな感じなので、我流にアレンジしたモノで概要説明します。*1

大枠では以下のような構造になっています。

  • ボタンの元となる div タグ (div.mds-button) を構築
  • div.mds-button 内にボタンの外側を表現する div タグ (div.mds-button-outer) を構築
  • div.mds-button-outer 内にボタンの外側を表現する div タグ (div.mds-button-inner) を構築
  • div.mds-button-inner 内にレイアウト制御用の div タグ (div.mds-button-layout) を構築
  • div.mds-button-layout 内に影用の div タグ (div.mds-button-shadow) とボタンテキスト表示用の div タグ (div.mds-button-content) を構築

ソースで書くとこんな感じ。

<div class="mds-button">
  <div class="mds-button-outer">
    <div class="mds-button-inner">
      <div class="mds-button-layout">
        <div class="mds-button-shadow">
          &nbsp;
        </div>
        <div class="mds-button-content">
          テキスト
        </div>
      </div>
    </div>
  </div>
</div>

CSS

で、これだとタダの箱なので、CSS で一気に装飾していきます。

ここで、素敵なアイデアが連発です。

まずはソースコードを。

div.mds-button {
  cursor: pointer;
  position: relative;
  display: inline-block;

  /* IE6, IE7: IE に inline-block が効かない */
  *display: inline;

  /* IE6: 横幅が無いと背景がおかしくなる */
  _width: expression(this.clientWidth + 'px');
}

/* IE7: hasLayout があると inline-block っぽいレイアウトになる */
*+html div.mds-button {
  zoom: 1;
}

div.mds-button div.mds-button-outer {
  border-color: #939393;
  border-style: solid;
  border-width: 1px 0;
  display: inline-block;
}

div.mds-button div.mds-button-inner {
  border-color: #939393;
  border-style: solid;
  border-width: 0 1px;
  background-color: #e0e0e0;
  margin: 0 -1px;
  display: inline-block;

  /* IE6: 横の罫線が切れるので */
  _position: relative;
}

div.mds-button div.mds-button-inner div.mds-button-layout {
  height: 100%;
  position: relative;
  display: inline-block;
}

div.mds-button div.mds-button-inner div.mds-button-layout div.mds-button-shadow {
  height: 1.1em;
  left: 0;
  top: 0;
  right: 0;
  overflow: hidden;
  position: absolute;
  background-color: #f9f9f9;
  border-bottom: solid 0.2em #eeeeee;
  display: inline-block;

  /* IE6: absolute だと横幅計算されないっぽいので expression で強引に */
  _width: expression(this.parentNode.parentNode.clientWidth + 'px');
}

div.mds-button div.mds-button-inner div.mds-button-layout div.mds-button-content {
  color: #000000;
  line-height: 2.2em;
  padding: 0 12px;
  position: relative;
  text-align: center;
  vertical-align: middle;
  white-space: nowrap;
  display: inline-block;
}

div.mds-button-hover {
}

div.mds-button-hover div.mds-button-outer {
  border-color: #606060;
}

div.mds-button-hover div.mds-button-inner {
  border-color: #606060;
  background-color: #e0e0e0;
}

div.mds-button-hover div.mds-button-inner div.mds-button-layout {
}

div.mds-button-hover div.mds-button-inner div.mds-button-layout div.mds-button-shadow {
  background-color: #f9f9f9;
  border-bottom: solid 0.2em #eeeeee;
}

div.mds-button-hover div.mds-button-inner div.mds-button-layout div.mds-button-content {
  color: #000000;
}

div.mds-button-active {
}

div.mds-button-active div.mds-button-outer {
  border-color: #606060;
}

div.mds-button-active div.mds-button-inner {
  background-color: #f9f9f9;
  border-color: #606060;
}

div.mds-button-active div.mds-button-inner div.mds-button-layout {
}

div.mds-button-active div.mds-button-inner div.mds-button-layout div.mds-button-shadow {
  background-color: #e0e0e0;
  border-bottom: solid 0.2em #eeeeee;
}

div.mds-button-active div.mds-button-inner div.mds-button-layout div.mds-button-content {
  color: #000000;
}

要点っぽいところを解説していきます。

  • div.mds-button-outer
    • border-width: 1px 0;
      • 外側の div に上下の線が付きます
  • div.mds-button-inner
    • border-width: 0 1px;
      • 内側の div に左右の線がつきます
    • margin: 0 -1px;
      • 左右のマージンを 1px 分広げることで丸角っぽい罫線を演出します
      • 4 つの角が 1px × 1px 分空くことになるので、結果として丸角に見えるわけですね
    • background-color: #e0e0e0;
      • グラデーション中で最も濃い色を指定
      • 実際にはコッチがボタンの影に該当する
  • div.mds-button-shadow
    • background-color: #f9f9f9;
      • グラデーション中で最も薄い色を指定
      • これがハイライト部分に該当する
    • border-bottom: solid 0.2em #eeeeee;
      • グラデーションの中間色を指定
      • border-bottom のみ指定することで段階的に色を変化させているように見せている
  • div.mds-button-content
    • line-height: 2.2em;
      • ボタンの高さを決定すると共に真ん中に寄せるために行高を確保
    • vertical-align: middle;
      • ここで縦真ん中寄せを確定
    • padding: 0 12px;
      • 横に余裕を持たせる

IE ハックに関してはボクが勝手に付けた感じなので、IE を無視するなら削って下さい。

IE ハックの詳細は他のサイト見て下さいw

JavaScript

で、最後に JavaScript でボタンの挙動を制御します。*2

Event.observe(
  window,
  'load',
  function() {
    $$('.mds-button').each(
      function(button) {
        button.observe(
          'mousedown',
          function() {
            this.addClassName('mds-button-active');
          }.bind(button)
        );
        button.observe(
          'mouseup',
          function() {
            this.removeClassName('mds-button-active');
          }.bind(button)
        );
        button.observe(
          'mouseover',
          function() {
            this.removeClassName('mds-button-active');
            this.addClassName('mds-button-hover');
          }.bind(button)
        );
        button.observe(
          'mouseout',
          function() {
            this.removeClassName('mds-button-active');
            this.removeClassName('mds-button-hover');
          }.bind(button)
        );
      }
    );
  }
);

大本の div.mds-button に mds-button-hover とか mds-button-active とかを着脱する感じです。

もちろん、実際にはボタンを押したときにアレコレする必要があるので onclick にも書く必要はありますが。

Internet Explorer 6, Internet Explorer 7, Firefox, Safari で動作確認しています。

終わりに

確かに、書いてみれば「ああ、なるほどね」って感じではありますが、border-bottom でのグラデーション表現とか見ると「流石 Google 先生!!」って感じですね。

思い付けば書くのは難しくないけど、「思い付く」ってことが凄いっす。

追記 @2009-03-09

実際にブラウザにレンダリングさせてみたモノをサンプルとして掲載してみます。





左から順に、「通常表示」「マウスオーバー表示」「クリック表示」となっております。





拡大表示してみた。

ちゃんと角の 1px が欠けてて、丸角っぽく見える。

背景のグラデーションも 3 色グラにも関わらずちゃんと認識出来る。

人間の視覚情報に於ける自動補正って凄いのね。

*1:CSS のクラス名とかは弊社流にアレンジしたモノを使って説明しています。

*2:Prototype.js 前提なのであしからず