GoogleのボタンをCSSだけでほぼ完璧につくる

五倍に拡大したGoogle検索ボタン

Google のボタンをCSSだけでつくるをDelicious経由で見て、もうちょっと出来るんじゃないかなーと思ったので、background-imageで複数のlinear-gradient()を使ってグラデーションにプラスアルファする方法の啓蒙も兼ねてほぼ完コピするCSSの書き方を解説しようかなとか何とか。このエントリの別名は「CSSグラデーションのちょっとしたテクニック #3」になる。

View Demo: Google Style Button

まずはデモを参照。パッと見ではどっちか画像か分からない程度にはコピーできていることと思う。もちろんフォント(というかOS)によっては文字が違く見えることと思うが。CSSは以下のような感じになっている(簡略化するためにベンダー拡張は省略、詳しくはデモのソースを参照)。

button {
  padding: 1px 6px;
  border-top: 0;
  border-right: 1px solid rgb(231, 231, 231);
  border-bottom: 1px solid rgb(231, 231, 231);
  border-left: 0;
  height: 33px;
  background-color: rgb(204, 204, 204);
  background-image: linear-gradient(
    top,
    rgb(192, 192, 192) 0px, rgb(192, 192, 192) 1px,
    rgb(153, 153, 153) 1px, rgb(153, 153, 153) 31px
  ),
  linear-gradient(
    top,
    rgb(255, 255, 255) 0px,  rgb(255, 255, 255) 1px,
    rgb(241, 241, 241) 1px,  rgb(223, 223, 223) 29px, 
    rgb(215, 215, 215) 29px, rgb(215, 215, 215) 30px,
    rgb(153, 153, 153) 30px, rgb(153, 153, 153) 31px
  );
  background-position: right top, 1px 1px;
  background-size: 1px 31px, auto;
  background-repeat: no-repeat;
  font-size: 15px;
  font-family: Arial, sans-serif;
}

ポイントとなる点は以下の3つ。

パーツごとに分けて説明していく。

上端と左端

border-topborder-leftを使っても良いが、背景色をその部分の色(rgb(204, 204, 204))に指定し、background-position1px 1pxとすることで、背景画像(ここではグラデーション)を左上から右に1px下に1pxの位置から開始させることができる。もちろんbackground-repeat: no-repeat;として背景画像を繰り返さないようにする必要がある。

右端と下端

これはborder-rightborder-bottomで普通に線を引けば良い。背景画像でも出来ないことはないが、次に説明する右端から1px手前のボタンの影にあたる部分の位置決めが面倒になるのでborderが良い。

右端から1px手前

ボタンの影にあたるこの部分は、最初の1pxがrgb(192, 192, 192)で残りがrgb(153, 153, 153)になっている。こういうベタ塗り→ベタ塗りの場合は上記のコードまたは以下の例のように、二点間を同じ色にしてしまえば良い

linear-gradient(
  top,
  red   0px, red   3px,
  green 3px, green 6px,
  blue  6px, blue  9px
)

この例では上から1~3pxまでは赤(red)、4~6pxまでは緑(green)、7~9pxまでは青(blue)でそれぞれベタに塗られることになる。このようにグラデーションの開始と終了を同じ行に書いたりすると少しは見やすく、あとで読んでも分かりやすくなると思う。

またbackground-positionright topbackground-size1px 31pxをそれぞれ指定することによって右端の縦方向に1pxの線を引くような感じにする。

background-image: linear-gradient(
  top,
  rgb(192, 192, 192) 0px, rgb(192, 192, 192) 1px,
  rgb(153, 153, 153) 1px, rgb(153, 153, 153) 31px
);
background-position: right top;
background-size: 1px 31px;

ボタンの影にあたる部分のコードをまとめると以上のようになる。

ボタン中央のグラデーション

グラデーションの構成はベタ塗り(rgb(255, 255, 255))→グラデーション(rgb(241, 241, 241) ~ rgb(223, 223, 223))→ベタ塗り(rgb(215, 215, 215))→ベタ塗り(rgb(153, 153, 153))なので、linear-gradient()のコードは以下のようになる。

linear-gradient(
  top,
  rgb(255, 255, 255) 0px,  rgb(255, 255, 255) 1px,  /* 1px目(最初)はベタ塗り */
  rgb(241, 241, 241) 1px,  rgb(223, 223, 223) 29px, /* 2~29pxがグラデーション */
  rgb(215, 215, 215) 29px, rgb(215, 215, 215) 30px, /* 30px目はベタ塗り */
  rgb(153, 153, 153) 30px, rgb(153, 153, 153) 31px  /* 31px目(最後)もベタ塗り */
)

上端と左端で説明済みのように開始位置を左上から右に1px下に1pxにして背景色を一部見えるようにしたいので、

background-position: 1px 1px;

このグラデーションのサイズはボックスのサイズに従ってフレキシブルに変化して欲しいので、

background-size: auto;

これらのプロパティを既にポイントとして説明した複数の値が取れることを利用して、すぐ前の右端から1px手前でまとめたコードのbackground-*プロパティそれぞれに,(カンマ)で区切って追加することになる。

background-image: linear-gradient(
  top,
  rgb(192, 192, 192) 0px, rgb(192, 192, 192) 1px,
  rgb(153, 153, 153) 1px, rgb(153, 153, 153) 31px
),
linear-gradient(
  top,
  rgb(255, 255, 255) 0px,  rgb(255, 255, 255) 1px,
  rgb(241, 241, 241) 1px,  rgb(223, 223, 223) 29px, 
  rgb(215, 215, 215) 29px, rgb(215, 215, 215) 30px,
  rgb(153, 153, 153) 30px, rgb(153, 153, 153) 31px
);
background-position: right top, 1px 1px;
background-size: 1px 31px, auto;

複数の値を指定した場合に先に書いた方が手前に来るのは覚えていたほうが良い。つまり、

background-image: url("front.png"), url("back.png");

だとfront.pngがback.pngの上になる。

最後に

最後に上端と左端のコードや右端と下端のコード、その他paddingheightfont-*などをGoogleの検索ボタンと同じようにすれば良い。


Safari 5など古いWebKitのブラウザでは-webkit-linear-gradientはないので、-webkit-gradient(linear)を使うことになる。この場合色指定をcolor-stop()で行うのだが、これにはpx単位での位置指定が出来ないので計算機で頑張って計算してください。詳しくはデモのソースを参照。

calc(1/33)とかcalc(100% - 1px)とか早く気軽に使えるようになるといいな。