Home JavaScript Greasemonkey PHP

プログラマにも書ける!画像を使わずCSS3でつくる今風のタブ+ツールバー2011-09-06


TwitMgr (閉鎖済) のリニューアルに際して、今風のタブとツールバーを CSS3 だけで書いたので、その内容を順を追って説明してみます。

完成品

こんな感じのタブとツールバーを、CSS 3 だけで書いていきます。

フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

マークアップ

実際の TwitMgr で使ってるものとは違いますが、説明の都合上 HTML は下記のようなマークアップで行います。まだ何も CSS を適用していない状態なので、何がなにやらという状態ですね。
<div class="tab selected">フォローしている</div>
<div class="tab">フォローされている</div>
<div class="toolbar">
<ul class="pager">
  <li class="button enable">1</li>
  <li class="button enable">2</li>
  <li class="button current">3</li>
  <li class="button enable">4</li>
  <li class="button enable">5</li>
  <li class="period">...</li>
  <li class="button enable">≫</li>
</ul>
</div>
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

レイアウト

各部品の場所を決めていきます。位置関係が分かりやすいよう、仮で青のボーダーを入れました。ここはあまり特筆する点がありませんね。display と float を使って、適切な位置に要素を配置していくだけです。

.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
}
.toolbar {
  clear: both;
  height: 30px;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

色の指定

文字の色と背景色を指定しました。普通に color と background-color を指定しただけですが、css3 らしい事としては、選択中のページを表す li.current に半透明の白色を指定する事で、その部分がハイライトされたような効果を出しています。
このようにする事で、背景色が変わったとしてもハイライト色を変える必要が無くなります。


.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
}
.selected {
  background-color: #5a5;
  color: #fff;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

ボーダーの指定

今度は各要素のボーダーを指定していきます。
いわゆる角丸を多用しています。四隅の特定の角だけを丸める事もできるので、タブっぽいデザインを書く時に便利です。ここまでくると何となくそれらしくなってきますね。

ページャー部分のボーダーは、背景色に合わせて半透明の白色にしています。背景色も文字もそれに含まれる要素も、全て一斉に半透明にする時は opacity で、背景色・ボーダーなど部分に応じて半透明にする時は rgba という使い分けをすると吉です。

またベンダープレフィックスとしてここでは、webkit (Chrome / Safari 等) と moz (Firefox 等) を付けています。他にも o (Opera) や ms (IE8+) もあるので、必要に応じて使い分けて下さい。

ただ、この状態では当たり前なのですが、選択中のタブとツールバーの間にも線が見えてしまっていますね。ここは綺麗に繋がってくれないと困ります。この問題は後で解決します。


.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
  border-style: solid;
  border-color: #383;
  border-width: 1px 1px 0 1px;
  -webkit-border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  border-top-left-radius: 5px;
}
.selected {
  background-color: #5a5;
  color: #fff;
  border-color: #373;
  border-bottom: 1px #5a5;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
  border: solid 1px #373;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
  border: solid 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.toolbar .pager li.enable {
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
  border: 0;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

グラデーションの指定

ツールバー部分にグラデーションをかけました。グラデーションの上端の色を選択中のタブの色と合わせる事で、シームレスに繋がるようにします。
このグラデーションの指定ですが、手作業で書くにはちょっと辛いので、Ultimate CSS Gradient Generator のようなジェネレータを使って書くのが良いかと思います。
ベンダープレフィックス付きの css を出力してくれるので、そのまま貼り付けるだけになります。

.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
  border-style: solid;
  border-color: #383;
  border-width: 1px 1px 0 1px;
  -webkit-border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  border-top-left-radius: 5px;
}
.selected {
  background-color: #5a5;
  color: #fff;
  border-color: #373;
  border-bottom: 1px #5a5;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
  border: solid 1px #373;
  background: -webkit-linear-gradient(top, #5a5 1%, #383 100%);
  background: -moz-linear-gradient(top, #5a5 1%, #383 100%);
  background: linear-gradient(top, #5a5 1%,#383 100%);
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
  border: solid 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.toolbar .pager li.enable {
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
  border: 0;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

1px ラインの追加

デザイン系の記事で良く取り上げられる、1px の魔法を css で追加します。
具体的には右に 1px、下に 1px、ぼかし無しの状態で、要素の内側にボックスシャドウをかけます。こうするとちょうど、左上に 1px のラインを引いたような効果が出せます。

.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
  border-style: solid;
  border-color: #383;
  border-width: 1px 1px 0 1px;
  -webkit-border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  border-top-left-radius: 5px;
}
.selected {
  background-color: #5a5;
  color: #fff;
  border-color: #373;
  border-bottom: 1px #5a5;
  padding-right: 8px;
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
  border: solid 1px #373;
  background: -webkit-linear-gradient(top, #5a5 1%, #383 100%);
  background: -moz-linear-gradient(top, #5a5 1%, #383 100%);
  background: linear-gradient(top, #5a5 1%,#383 100%);
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
  border: solid 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.toolbar .pager li.enable {
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
  border: 0;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

タブとツールバーをつなぐ

ボーダーを追加して以来ずっと気になっていた、選択中のタブとツールバーの間の線を隠します。
まずタブの高さ自体がそもそも 14px になっているので、選択中のタブはそれにボーダー幅 1px と、ボックスシャドウ幅 1px を足した 16px にします。
そのままだと、非選択のタブと選択中のタブの高さが変わって、片方が浮いてしまう感じになるので、さらに margin-bottom を -2px にします。

こうする事で選択中のタブが占める高さは非選択のタブと同じ高さになるものの、背景の描画自体は 2px 分下に伸びる形になるので、ツールバーとの間にあった線を隠す事ができます。

.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
  border-style: solid;
  border-color: #383;
  border-width: 1px 1px 0 1px;
  -webkit-border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  border-top-left-radius: 5px;
}
.selected {
  height: 16px;
  margin-bottom: -2px;
  background-color: #5a5;
  color: #fff;
  border-color: #373;
  border-bottom: 1px #5a5;
  -webkit-border-bottom-right-radius: 2px;
  -moz-border-radius-bottomright: 2px;
  border-bottom-right-radius: 2px;
  padding-right: 8px;
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
  border: solid 1px #373;
  background: -webkit-linear-gradient(top, #5a5 1%, #383 100%);
  background: -moz-linear-gradient(top, #5a5 1%, #383 100%);
  background: linear-gradient(top, #5a5 1%,#383 100%);
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
  border: solid 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.toolbar .pager li.enable {
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
  border: 0;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

テキストの書式を調整する

残りは微調整になりますが、テキストの書式を指定していきます。
センタリングやフォントサイズの調整の他、選択中のタブやページを強調するためにテキストシャドウを指定しました。
下に 1px の位置にぼかし無しのシャドウを付けています。あまり離したり、ぼかしすぎたりすると 90 年代テイストの野暮ったさになってしまうので気を付けたいところです。

ところでこのテキストシャドウ、本当は 1px 程度はぼかした方が見た目が柔らかくなっていいのですが、XP 上の Chrome 限定で、「本来アンチエイリアスがかかっていないフォントに、テキストシャドウをぼかして適用するとアンチエイリアスがかかる」という仕様 (バグ?) があって、隣のシャドウ無しのフォントと見た目が変わってしまうので、あえてぼかし無しにしています。
自分が XP 上で Chrome を使っていて気になるというだけなので、気にせずぼかしを適用しても良いかも知れません。

.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
  border-style: solid;
  border-color: #383;
  border-width: 1px 1px 0 1px;
  -webkit-border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  border-top-left-radius: 5px;
}
.selected {
  height: 16px;
  margin-bottom: -2px;
  background-color: #5a5;
  color: #fff;
  border-color: #373;
  border-bottom: 1px #5a5;
  padding-right: 8px;
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
  text-shadow: 0 1px 0 #333;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
  border: solid 1px #373;
  background: -webkit-linear-gradient(top, #5a5 1%, #383 100%);
  background: -moz-linear-gradient(top, #5a5 1%, #383 100%);
  background: linear-gradient(top, #5a5 1%,#383 100%);
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
  text-align: center;
  font-size: 90%;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
  border: solid 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.toolbar .pager li.enable {
  border-color: rgba(255, 255, 255, 0.5);
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
  border-color: rgba(255, 255, 255, 0.5);
  text-shadow: 0 1px 0 #333;
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
  border: 0;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

ユーザビリティを向上させる

静的な見た目についてはすでに完成していますが、オンマウス時の挙動を指定する事でユーザビリティを向上させます。

まずクリック可能な要素に対して cursor を pointer にするのは基本中の基本です。a 要素を使えばデフォルトのスタイルがそうなるのですが、HTML の思想からしてページ遷移 (ページ内ジャンプを含む) 以外で a 要素を使うのは正しいとは言えません。
余談ですが、a 要素の name 属性も HTML5 で廃止されました。要素に名前を付けるために a を使うなという事です。

なお、クリック時の動作自体は、JavaScript で動的に付与します。onclick 属性は Ajax で HTML を差し込む時に便利だったのですが、jQuery の live を使えば、後から追加される要素にも動的にイベントを付与出来るので、昔ながらの手法はそろそろ終わりにしましょう。

後は、hover 時のスタイルを追加します。タブが上に伸びたようになるのは、padding-top を増やした分、margin-top を減らす事で表現しています。
この時 transition を使えばさらにアニメーションさせる事もできるかと思ったのですが、padding と margin を同時に変化させると、アニメーションがガタガタしてしまうことが分かったので適用していません。
.tab {
  margin: 10px 5px 0 0;
  padding: 5px 7px;
  float: left;
  height: 14px;
  color: #383;
  border-style: solid;
  border-color: #383;
  border-width: 1px 1px 0 1px;
  -webkit-border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  border-top-left-radius: 5px;
  cursor: pointer;
}
.tab:hover {
  padding-top: 7px;
  margin-top: 8px;
}
.selected {
  height: 16px;
  margin-bottom: -2px;
  background-color: #5a5;
  color: #fff;
  border-color: #373;
  border-bottom: 1px #5a5;
  padding-right: 8px;
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
  text-shadow: 0 1px 0 #333;
}
.toolbar {
  clear: both;
  height: 30px;
  background-color: #5a5;
  border: solid 1px #373;
  background: -webkit-linear-gradient(top, #5a5 1%, #383 100%);
  background: -moz-linear-gradient(top, #5a5 1%, #383 100%);
  background: linear-gradient(top, #5a5 1%,#383 100%);
  -webkit-box-shadow: 1px 1px 0 #9c9 inset;
  -moz-box-shadow: 1px 1px 0 #9c9 inset;
  box-shadow: 1px 1px 0 #9c9 inset;
}
.toolbar .pager {
  display: block;
  float: right;
  margin: 6px;
}
.toolbar .pager li {
  display: block;
  float: left;
  margin-left: 2px;
  color: #fff;
  text-align: center;
  font-size: 90%;
}
.toolbar .pager li.button {
  width: 20px;
  padding: 1px;
  border: solid 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.toolbar .pager li.enable {
  border-color: rgba(255, 255, 255, 0.5);
  cursor: pointer;
}
.toolbar .pager li.enable:hover {
  background-color: rgba(255, 255, 255, 0.3);
}
.toolbar .pager li.current {
  background-color: rgba(255, 255, 255, 0.3);
  border-color: rgba(255, 255, 255, 0.5);
  text-shadow: 0 1px 0 #333;
}
.toolbar .pager li.period {
  width: auto;
  padding: 1px 2px;
  border: 0;
}
フォローしている
フォローされている
  • 1
  • 2
  • 3
  • 4
  • 5
  • ...

さいごに

CSS3 を使う時は、ついつい派手に使いたくなるのですが、さりげなくワンポイントずつ使うと、比較的こなれた仕上がりになるようです。

また、例によって IE のようなレガシーブラウザでは、意図したとおりの見た目にはなりません。
IE6 でのキャプチャは以下のようになります。



このままだと厳しそうですが、選択中のページの背景色を半透明以外にも指定しておけば、ぎりぎり意図は伝えられるレベルですね。
プログレッシブエンハンスメント (長すぎ!略称募集) も意識したデザインをやっていければいいなと思います。

カテゴリ: Development タグ: css html