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

[Memo]:visitedクラスを利用した行動ターゲティング広告

とても興味深い内容だったのでメモ。

id:Hamachiya2さんのデモのソースを見るとCSSの:visited擬似クラスと、JavaScriptを併用した形で、動的にコンテンツを入れ替える方法が分かります。

まずCSSで:visited擬似クラスに別のスタイルを書いておいて

a {
display: block;
height: 22px;
overflow: hidden;
}
a:visited {
height: 16px;
}

JavaScriptの以下のようなコードで、訪問の有無を調べています。

var defHeight = 22;
var visHeight = 16;
...中略...
// 引数にはa要素ノードを入れる
// その高さがデフォルトでない(既訪問リンク)ならtrueを返す
// その高さがデフォルト(未訪問リンク)ならfalse返す
function checkVisited(elm) {
return (elm.offsetHeight != defHeight);
}

実行はwindow.onloadのイベントで。なるほど。

自らの意図しない情報が、このように簡単に取得されてしまうのかと思うと、気持ちが悪いな・・・と思うと同時に、簡単であるが故に防ぎようがないと思いました。

ネガティブマージンによる段組みレイアウト

18_webcresample.gif web creators 2008年10月号の巻頭特集に寄稿したネタの中から、サンプルを紹介してみよう企画、第1弾。
ネタ概要は本を買って誌面で見てね^^というところなので、ここでは書きません。

ポイントは、ある要素の上marginをマイナスにすることにより、レイアウトをずらして直前の要素に重ねているところ。

サンプルでそれをしているのは、見出しとリンクボタンが横並びになっているところなのですが、サンプルを見れば分かる通り、両方とも画像です。

上にレイアウトをずらしているに過ぎないので、テキストなどの縦幅が可変の要素が中に入っていると、フォントの異なる環境での閲覧や、文字サイズ変更などによって、後続のレイアウトに影響が出ます。そんなわけで、縦幅可変になる要素のレイアウトにはあまり向いてません。

何だかここまで書くと、絶対配置でいいような気がしますね^^;floatも絶対配置も使いたくない、けれども段組にしなきゃならない、というレアなケースで活躍する・・・かもしれません・・・。

LineNumberWriter開発メモ

LineNumberWriterを作るに当たって気づいた点やその他補足など。自分で書いていて改めて気付きましたけど、かなりの欠陥品です…orz

基本設計

行番号を振るための処理は、基本的にsyntaxhighlithter.jsとほとんど同じ。というか、syntaxhighlighter.jsを参考にして作りました。

処理の流れとしては、

  1. まずページ内に<pre><code>とマークアップされている部分を取得します。
  2. それら個々を<ol><li>番号順リストのマークアップに変換します。それら個々を<ol><li>番号順リストのマークアップに変換したものと、そのままのもの(プレーンテキスト)、それぞれ二つづつを生成します。プレーンテキストの方はデフォルトで非表示にします
  3. 奇数行と偶数行のli要素それぞれに別のclass属性値を設定します。
  4. 変換後のコードとプレーンテキストとを切り替えるヘッダー部分を生成します。
  5. 最後にdiv要素で包みます(後でスタイルを整える都合)。最後にこれらをdiv要素内に書き出し、元の<pre><code>部分と差し替えます。
<pre><code>function sample() {
alert("sample");
}</code></pre>

これが

<div class="LNW">
<div class="header" style="display:none">
<a href="#" class="ctrl1">with line number</a>
<span class="ctrl2">plain text</span>
</div>
<div class="header">
<span class="ctrl1">with line number</span>
<a href="#" class="ctrl2">plain text</a>
</div>
<ol>
<li class="odd">function&nbsp;sample()&nbsp;{</li>
<li class="even">&nbsp;&nbsp;alert(&quot;sample&quot;);</li>
<li class="odd">}</li>
</ol>
<pre style="display:none"><code>function sample() {
alert("sample");
}</code></pre>
</div>

こうなります。

Continue reading