Firefox 3.0.xでも背景画像が1pxズレる

下記のようなHTML構造で、bodyタグに背景画像をbackground-position: center top;みたいに中央配置したい場合があったりします。

<body>
  <div id="header"></div>
  <div id="content"></div>
  <div id="footer"></div>
</body>

でもこれbodyタグに指定すると1pxズレちゃうんですね。
IEだと1pxズレる問題は各所で「bodyタグにpadding-left: 1px;を指定したら回避できるよ」って感じで紹介されてるけど、実はFirefox 3.0.xやSafariなどにも同じような問題があって久しぶりにハマってしまった。

まずはググって調べてみたところSoh Tanakaさんのブログから参考になる記事を発見。
垂直スクロールバーの幅のサイズが奇数になってるのが原因みたいだ。
随分と解決に近づいた気もしたけど、記事内のView Final Demoでは解決できてないみたいなのでさらに調査してみた。

update
Firefox 3.5で解決されたようです。WebKit系のブラウザーでの解決が待たれますね。

update
Soh Tanakaさんのサイトがドメインを乗っ取られているようなので、リンクをはずしています。

IEだけを考慮した場合

とりあえず失敗しているサンプルをご覧ください。

IEメモ

  • IEでは右に1pxのズレ(後方互換モードでレンダリングされるIEで発生?)。
  • 問題のあるIEにはbodyタグにpadding-left: 1px;を指定で解決(CSSハックを使用)。
  • ただしIE7はFF 3.0.xと同様の条件でズレるため、padding-left: 1px;では回避できない(後述のFFメモ参照)。
  • 後方互換モードなブラウザーに対応しないでいいならハックも必要ないかな。
  • Mac IEはサポートしない。

CSSサンプルコード

html {
  height: 100%;
  background-color: #f5f6f7;
}

body {
  min-height: 100%;
  height: auto !important;
  height: 100%;
  background: #f5f6f7 url(../images/bg.png) repeat-y scroll center top;
  color: #333;
}

/* for IE(Quirks Mode) */
* html body {
  padding-left: 1px;
  text-align: center;
}

#header,
#content,
#footer {
  width: 980px;
  margin: 0 auto;
  text-align: left;
}

IEは概ね問題を回避できた。ただし#header,#content,#footerにmargin: 0 auto;だとIE、Firefox、Operaなどのzoom機能を使って拡大するとコンテンツ領域がはみ出す感じで拡張される問題が残る。

Firefox 3.0.xにも対応させてみる

FFメモ

  • #header,#content,#footerにmargin: 0 auto;だとFF3.0.xで左に1pxのズレ。
  • Soh Tanakaさんによれば、ブラウザーのスクロールバーの幅の違いによって生じる問題とのこと。
  • FF3.0.xではサイドバー(ブックマークとか履歴)やスクロールバーの表示・非表示、ウィンドウのサイズによってズレるので厄介。
  • 要するに表示領域の幅のサイズが奇数になってると発生。例えばサイドバーの幅の可変で発生したりしなかったり(IE7も同様)。
  • WindowsとMacで挙動が違う。
  • Firefoxは投稿時点での最新バージョン3.0.8で検証。
  • FF2以下はサポートしない。

成功しているサンプルではbodyタグに幅を持たせてセンタリングした(その際、IE6、IE7ではposition: relative;で基準位置の指定をしないとウィンドウ幅の可変時にナビゲーション部分のみが取り残されてしまいます)。
Safari、Opera、Google Chromeの最新バージョンも大丈夫なはず。上述のzoom機能での問題もなくなった(ただし拡大率によっては1pxズレる問題が残った)。
ちなみにhtmlにheight: 100%;、bodyにmin-height(IE6対応版)を指定しないと文字拡大時に背景がリピートしない。

CSSサンプルコード

html {
  height: 100%;
  background-color: #f5f6f7;
}

body {
  position: relative;
  width: 994px;
  min-height: 100%;
  height: auto !important;
  height: 100%;
  margin: 0 auto;
  background: #f5f6f7 url(../images/bg.png) repeat-y scroll center top;
  color: #333;
}

/* for IE(Quirks Mode) */
* html body {
  padding-left: 1px;
  text-align: center;
}

#header,
#content,
#footer {
  width: 980px;
  margin: 0 auto;
  text-align: left;
}

その他の解説

常に垂直スクロールバーを表示させとく?

html {
  overflow-y: scroll;
}

/* for gte Opera9.51 */
html:not(\*|*) {
  overflow: auto;
  margin-bottom: 1px;
}

上記のように垂直スクロールバーを常に表示させるってのもいいけど、どのみち表示領域の幅のサイズが奇数になれば破綻するのでoverflow-y: scroll;は指定しない。IE独自実装だったoverflow-yを先行実装しているブラウザーもあるけど、Opera(投稿時点での最新バージョン9.64)はoverflow-yを採用していないので却下。
Opera対応でhtmlにheight: 100%; margin-bottom: 1px;ってのもあるけど、これは微妙な気がするなぁ。

全体を包括する

#header,#content,#footerを包括するdiv(#wrapや#containerみたいなの)に横方向中央配置の背景画像を指定すれば1pxのズレはないので、それも一つの方法論と思います。こういうのってデザインの為の不要なタグとか言われそうですが、包括するdivについては個人的に推奨もしないですが、取り立てて否定もしません。
今後のブラウザーのバージョンアップへの対策などを考えると、包括するdivを使うのが一番の安全策かもしれません。