PNG8でアルファチャンネルが使えることを最近知った件

続・ハイパフォーマンスWebサイト ―ウェブ高速化のベストプラクティスを読んで、今ではPNG8がデフォルトですよ、みたいな内容が書いてあったのでPNG形式を敬遠してきた自分はたいそう驚きました。

写真にはJPEG、アニメーションにはGIF、その他すべてのものにはPNG(可能な限りPNG8)を使う

ということだそうです。

同書でも紹介されていたsitepointの記事、PNG8 – The Clear Winnerを読むと、「PNG8最高だよ!」みたいなことが書いてあります。要約(というか超訳)すると

  • PNG8はGIFのような256色パレットベースのカラーモデルを持っている
  • GIFのようにアニメーションはできない
  • GIFのように一部の色を完全に透明にすることができる

しかしなんと、Fireworksを使えばアルファチャンネル付きのPNG8を書き出すことができる。少なくともバージョン3から実装されている。
アルファチャンネル付きで書き出した部分はIE6などの未対応ブラウザでは完全に透明なピクセルとして表示される。境目はジャギってしまうけど、そこまで見た目を損なうものではない。

なんと、Fireworksしかこのアルファチャンネル付き書き出しには対応していないそうです。しかもバージョン3からって・・・本当に目から鱗です・・・。
とりあえず実践してみようということでデモを作成しました。

デモ – PNG8 with Alpha Channel Test

はい、ドラゴンボールです。ドラゴンボールの影の部分がアルファチャンネル付きになっています。PNG8、PNG32、GIF、JPEGを比較のため、並べてみました。ちょっとサンプル画像の色数が多いため、ファイルサイズではJPEG(画質80)が最も軽くなっています。
特筆すべきはGIFと比べてファイルサイズが小さいこと。約20KBと約14KBなので、その差は歴然。
もっと色数が少なくていい画像ならそんなに違和感(グラデーション部分のガタガタ感とか)も出ないだろうし、PNG8の良さがもっと引き出せたのではないでしょうか。

ちなみにデモをIE6で見ると、以下のスクリーンショットのようになります。

ドロップシャドウ部分がまるまるなくなっています。PNG32(filterハックなし)の場合、透明部分がグレーになって表示されてしまうのはご存知の通りです。

透明度が必要なデザインの対応として、PNG32とfilterベースのハックを使って完全な表現を目指すのか、PNG8を使ってProgressive Enhancement的な制作を行うのか、というように選択肢が増える感じでしょうね。
filterプロパティを使った対応はその代償としてパフォーマンスを大幅に下げてしまいます。"ハイパフォーマンスWebサイト"を目指すのであれば、アルファチャンネル付きPNG8を使うという選択肢を検討してもいいかもしれません。

iPhoneのiPodアプリ風見出しインターフェースをJSで作ってみた

昨日のSugamo.cssで発表したコネタをポストします。

デモ:iPhoneのiPodアプリ風のインターフェースを再現するJS
JSファイル:iPhoneのiPodアプリ風のインターフェースを再現するJS

これはiPhoneにプリインストールしてあるiPodアプリのインターフェースを再現するJavaScriptです。要jQuery。

スクリーンショット:iPhoneのiPod風のインターフェースを再現するJS

iPodアプリで曲目リストやアーティストのリストを閲覧する際、「あ行」「か行」「さ行」みたいに並んでいるリストをスクロールしていくと、「あ行」のリストを見ているときは「あ」という見出しが画面上部に固定され、現在見ているリストがどの見出しに属するものなのかが見て分かるようになっています。つまり見出しがスクロールアウトされず、スクロールに着いてくる形になっているわけです。おそらく、一つのリストがとても長い場合は特に効果を発揮するかと思います。地味ですが確実にユーザビリティは向上するだろうという、粋な効果です。さすがApple。
何を言っているかよく分からない、という人はとりあえずデモを見てください・・・。

Continue reading

img要素を使ったCSSロールオーバー+α

画像をリストで配置したグローバルナビゲーションにロールオーバーを設定する時の話。JavaScriptを使わずCSSだけで実現するロールオーバーはいくつかやり方があると思いますが、以下のパターンをよく使っています。

パターン1

完成イメージ

パターン1のスクリーンショット

デモ

img要素を使ったCSSロールオーバー+α デモ1

XHTML

<ul id="globalNav">
<li><a href="#"><img src="/img/nav1.gif" alt="ナビ1" /></a></li>
<li><a href="#"><img src="/img/nav2.gif" alt="ナビ2" /></a></li>
<li><a href="#"><img src="/img/nav3.gif" alt="ナビ3" /></a></li>
<li><a href="#"><img src="/img/nav4.gif" alt="ナビ4" /></a></li>
<li><a href="#"><img src="/img/nav5.gif" alt="ナビ5" /></a></li>
</ul>

CSS

#globalNav {
height: 30px; /* ナビ画像の高さ */
background: url(nav_active.gif) no-repeat 0 0;
overflow: hidden;
}
#globalNav li {
float: left;
width: 90px;
}
#globalNav li a {
display: block;
*zoom: 1; /* ie6,7 */
}
#globalNav li a:hover,
#globalNav li a:active {
text-indent: -9999px;
}

全てのナビがロールオーバーした状態の画像を用意し、#globalNavの背景に設定します。

パターン1 スライスを切る様子

li要素に明示的な幅指定を行っておき、その子であるa要素にdisplay:block;を設定。
a:hover時にtext-indent:-9999px;を設定することでimg要素を画面外に飛ばし、背景画像を見せることでロールオーバーさせています。

この手法の欠点は、各ボタンを格納するli要素に明示的に幅を指定しないと意図した表示にならないという点。仮に、各ボタンの横幅が異なっている場合、各li要素にclassとかidを振って別々の幅を指定してやらないといけないということになります。

パターン2

各ボタンの横幅が異なっているけれど、各li要素にclassやidを書きたくない場合・・・このシチュエーションって結構経験していて悩んでいたのですが、どうにか実現することができたのがこのパターンです。

XHTMLはパターン1と同じとして。

完成イメージ

パターン2のスクリーンショット

デモ

img要素を使ったCSSロールオーバー+α デモ2

XHTML

<ul id="globalNav">
<li><a href="#"><img src="nav_products.gif" alt="ナビ1" width="82" height="18" /></a></li>
<li><a href="#"><img src="nav_gallery.gif" alt="ナビ2" width="64" height="18" /></a></li>
<li><a href="#"><img src="nav_blog.gif" alt="ナビ3" width="39" height="18" /></a></li>
<li><a href="#"><img src="nav_about.gif" alt="ナビ4" width="56" height="18" /></a></li>
<li><a href="#"><img src="nav_contact.gif" alt="ナビ5" width="71" height="18" /></a></li>
</ul>

CSS

#globalNav {
height: 18px; /* ナビ画像の高さ */
overflow: hidden;
background: url(nav_active.gif) no-repeat 0 0;
font-size: 10px;
}
#globalNav li {
float: left;
margin-right: 20px;
*zoom: 1; /* ie6,7 */
}
#globalNav a {
display: -moz-inline-box;
display: inline-block;
*zoom: 1; /* ie6,7 */
vertical-align: bottom;
}
#globalNav a:hover,
#globalNav a:active {
padding-top: 9999px;
}

li要素には幅指定を行いません。そして、右のボタンとの余白をmargin-rightで設定しますが、全てのボタンでこれが同一になるように画像のスライスを調節します。一番右のmarginが領域を飛び出してしまうケースもあると思いますが、その辺は適当にうまくやります。

パターン2 スライスを切る様子

a要素はdisplay:inline-block;になるようにします。 そしてinline-blockなのでvertical-alignの調整も行っておきましょう。 inline-blockについてはCSS Nite in Ginza, Vol.27での小山田さんのセッション(のスライド)が参考になります。

また、img要素にwidth、height属性をそれぞれ明示的に指定をする必要があります。これはFirefox2で正しく表示するために必要です。

そしてa:hoverpadding-topに大きな値を指定して、含んでいるimg要素を追い出すようにしてやれば、完了です。追い出した部分を非表示にするために、#globalNavにheightの明示的な指定とoverflow:hidden;の指定が必要なのでお忘れなく。(この2つはfloat解除の意味合いもありますが)

Continue reading

MTのコンテキストについての考察と解説

MovableTypeのテンプレートを書くにあたってまず理解すべきなのは、MTタグやテンプレートの種類よりも、まずコンテキストなのではないかと思います。CSSによるレイアウトを学ぶにあたって、ブロックモデルを理解すべきであるのと一緒です。というわけで、このコンテキストについて解説しようと試みます。

コンテキストとは

直訳すれば「文脈」です。ここではテンプレートにおける前後の文脈のことをそう呼びます。自然言語における人間の会話や文章にも前後の文脈というものが存在しますから、会話を例に挙げます。

Aさん:今日は天気がいいですね。
→「今日の天気」のコンテキスト

MTのテンプレートでは現在のコンテキストに適合しないMTタグを使おうとすると、エラーが出るようになっています。

コンテキストに適合しないタグを使おうとするとエラーが出る

人間の会話において、文脈に沿っていない話題や発言をすると会話が成立しなくなるのと同じです。

Aさん:今日は天気がいいですね。
→「今日の天気」のコンテキスト
Bさん:はい、僕はハンバーグが好きです。
→コンテキストに沿っていないのでエラー

コンテキストの種類と、テンプレートとの関係

MTのコンテキストは大別すると「ブログ記事」・「ブログ記事リスト(アーカイブ)」・「ウェブページ」の3つです。そしてこれはテンプレート一覧の「アーカイブテンプレート」の種類でもあります。これらのテンプレートは、最初から該当のコンテキストを持っており、「ブログ記事」アーカイブは最初から「ブログ記事」コンテキストを持っています。

「アーカイブテンプレート」の一覧の例

「ブログ記事リスト」では「日付別」・「ユーザー別」・「カテゴリ別」という、大別して3つの分類を「アーカイブマッピング」で与えることができます。このテンプレートに該当するコンテキストが与えられるだけでなく、この指定を元にページファイルが生成されます。

例えば「カテゴリ」アーカイブマッピングを選択したテンプレートでは、最初から「ブログ記事リスト」コンテキストと、「カテゴリ」コンテキストを持ちます。

コンテキストの指定方法

任意のコンテキストを作り出すために使用するのがMTEntriesや、MTArchivesMTPagesなどのブロックタグです。これらのタグで囲んだ部分はそのタグが表すコンテキストが設定され、指定の回数分繰り返されます。例えば以下の例は、「最新5件の記事のタイトル」を出力します。

<mt:Entries lastn="5">
<p><$mt:EntryTitle$></p>
</mt:Entries>

<mt:Entries>に囲まれた部分が5回繰り返されますが、その内容は「ブログ記事」コンテキストの最新5件であることを<mt:Entries lastn="5">が表しています。

このように、任意のコンテキストを作り出すMTタグは数多く存在しており、その全てはブロックタグです。ブロックタグで囲んだ内容はそのタグの属するコンテキストになる、と覚えておけばよいでしょう。

コンテキストは入れ子にできる

ブロックタグを入れ子にしたり、特定のアーカイブテンプレート内にブロックタグを記述することによって、コンテキストを入れ子にすることができます。入れ子にしたコンテキストでは、特に指定をしない限り、親のコンテキスト内で対象を絞り込んだものとなります。

例えば以下は記事ごとに、記事本文に続いてコメント一覧を表示するための記述です。

<mt:Entries lastn="5">
<div class="entry">
<h3><$mt:EntryTitle$></h3>
<div class="entry-body">
<$mt:EntryBody$>
</div>
<div class="comments">
<h4>記事へのコメント</h4>
<ul>
<mt:Comments>
<li>
<$mt:CommentAuthor$>さんのコメント:<br />
<$mt:CommentBody$>
</li>
</mt:Comments>
</ul>
</div>
</div>
</mt:Entries>

<mt:Entries><mt:Comments>を入れ子にすることによって、「特定のエントリーへのコメント」に絞り込んで出力させています。なお、特にコンテキストの指定がない状態で<mt:Comments>タグを使用すると、そのブログに対して投稿されたコメント全てが対象となります。

このエントリーの内容はMovableType4(現時点での最新製品版:Version 4.261)におけるものです。まもなく出荷となるMovableType5では「ウェブサイト」という概念が追加されるそうですし、コンテキストの種類には追加や修正があるかもしれません。

電話番号入力フォームのmaxlength

次のような電話番号入力フォームは正しくできていると言えるでしょうか?

<input type="text" size="20" maxlength="4" value="" name="tel1" id="tel1" /> -
<input type="text" size="20" maxlength="4" value="" name="tel2" id="tel2" /> -
<input type="text" size="20" maxlength="4" value="" name="tel3" id="tel3" />

答えはNo。その理由は maxlength="5" にすべきだから、と職場のTDさんが教えてくれました。5桁の市外局番が存在するなんて、知らなかったです・・・。