blue

世に言うclearing問題(直前のfloatだけをclearしたい)

  • Posted by: SOMA Hitoshi
  • February 6, 2007 10:14 PM
  • web

さて、上山君に質問をもらっていた件の、(私なりの)解答編。おさらいだが、質問は次のようなものだった。

4231のソースをテーブルからスタイルシートに書き換えているのですが、floatタグで英夫日記を左に寄せて、恭子日記を右に来るようにすると、恭子日記で写真がある後にclear:leftしたときに、次の行が英夫日記の下まで飛んでしまいます。

clearが一個上のfloatまでしか効かないようにするにはどうすればいいのでしょうか?

まず最初に断っておかないといけないのは、ブラウザのこの「気の利かない」挙動(CSS解釈)はべつにバグなのではなくて、CSSの仕様に従った正しいものであるということ。「clear」は基本的に、それ以前にあるすべての「float」を解除する(ただしもちろん「clear: left」は「float: left」のみを、「clear: right」は「float: right」のみを解除する)。

じゃああきらめざるを得ないかというとそんなことはなく、いくつかの方法があるが、まずは上山君が実現したいと思われるレイアウトを、以下に単純化して図示しておこう。

070206_layout.png

まず最初に、「position: absolute」はあまりいい手ではない

上山君の自己解決策は「position」指定を使うものだったが、上山君自身がすでに気づいているようにこれはあまりいい手ではない。「position: absolute」(絶対配置)と指定されたボックス要素は、他の要素とは完全に切り離されたものとして配置され、逆に他の要素たちはこれを「存在しないもの」として振る舞う。つまり、仮にHTML上で、

<div id="header">...</div> <div id="hideo">...</div> <div id="kyoko">...</div> <div id="footer">...</div>

という順番にボックスが並んでいたとしても、「#hideo」「#kyoko」が絶対配置されれば、その下にある「#footer」はそれらが無いものとして振る舞うから、「#header」が終わった直後に配置されることになる。

というような具合だから、こころおきなく絶対配置を使うことができる場面は限定される(独立したボックスとして存在してかまわない場合や、ボックスの高さを決めてかかれる場合など)。

サンプル1:もともと上山君が使っていたソース(上山君が何を悩んでいるのかについて)

さて、もともと上山君が使っていたソースは、まとめるとだいたい次のようなものである。(ブラウザでの表示結果を見やすく、わかりやすくするために本筋とは関係ない指定も加わっているが、重要なのは赤字部分。)

//HTML
<div id="wrapper">
  <div id="hideo">
    <p>英夫日記の本文</p>
    <div class="photo"><img src="photo.png" /></div>
    <p>回り込みテキスト回り込みテキスト</p>
    <p style="clear: left;">回り込みを解除して本文のつづき</p>
  </div>
  <div id="kyoko">
    <p>恭子日記の本文</p>
    <div class="photo"><img src="photo.png" /></div>
    <p>回り込みテキスト回り込みテキスト</p>
    <p style="clear: left;">回り込みを解除して本文のつづき</p>
  </div>
</div>

//CSS
#wrapper { width: 410px; }
#hideo { float: left; width: 200px; background: #ebebeb; }
#kyoko { margin-left: 210px; background: #ebebeb; }
.photo { float: left; margin: 0 1em 1em 0; }
p { margin: 0 0 1em; }

この

#hideo { float: left; width: 200px; }
#kyoko { margin-left: 210px; }

というのは、たしか以前に私が、スタイルシートで2コラム表示を実現するさいのソース例として上山君に教えたものじゃなかったかと思う。これ自体はまあべつに悪くないんだけど、おわかりのように、この「#kyoko」ボックスのなかに「clear: left」が用いられると、写真へのテキストの回り込みを解除するだけでなく、それより前にある「float: left」をすべて解除してしまうため、その本文のつづきは「#hideo」ボックスが終わったあとに置かれることになる。つまり、こう。

英夫日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

恭子日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

これを、上山君は「なんとかならないか」と思っているというわけ。

サンプル2:幅固定レイアウトならこうすればいい

「サンプル1」の場合には、「#hideo」だけに幅指定があり、「#kyoko」のほうは親要素(上記例では「#wrapper」、無ければドキュメントウィンドウ)のサイズによって幅が変わるという「リキッドレイアウト」になっている。つまり「サンプル1」のような書き方による2コラム表示は、一方のボックスがブラウザのウィンドウサイズによって伸び縮みするようにしたい場合により適している。↓こういう具合。

英夫日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

恭子日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

が、いま現在の「4231」(上山君のサイト)のデザインを見るに、べつにリキッドレイアウトになっているわけではない。幅を固定したデザインであるならば、

#hideo { float: left; width: 200px; }
#kyoko { float: right; width: 200px; }
というふうに、左右それぞれ、ともに「float」させてしまうのでも何ら問題ない(ボックスを「float」させるには、ボックスの「width」が指定されていなければならない)。そしてこうすれば、「#kyoko」ボックス内で「clear: left」が使われても、「#kyoko」ボックス自身の「float: right」は影響を受けない。

//HTML
<div id="wrapper">
  <div id="hideo">
    <p>英夫日記の本文</p>
    <div class="photo"><img src="photo.png" /></div>
    <p>回り込みテキスト回り込みテキスト</p>
    <p style="clear: left;">回り込みを解除して本文のつづき</p>
  </div>
  <div id="kyoko">
    <p>恭子日記の本文</p>
    <div class="photo"><img src="photo.png" /></div>
    <p>回り込みテキスト回り込みテキスト</p>
    <p style="clear: left;">回り込みを解除して本文のつづき</p>
  </div>
</div>

//CSS
#wrapper { width: 410px; }
#hideo { float: left; width: 200px; background: #ebebeb; }
#kyoko { float: right; width: 200px; background: #ebebeb; }
.photo { float: left; margin: 0 1em 1em 0; }
p { margin: 0 0 1em; }

↓ブラウザでの表示結果。

英夫日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

恭子日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき


サンプル3:画像への回り込み解除では「clear: left」しか使われない、というならリキッドレイアウトでも

「サンプル2」もそうだったが、「#hideo」「#kyoko」両ボックス内に出てくる回り込み解除が一律「clear: left」であるというならば、「サンプル1」同様のリキッドレイアウトでも小手先の対応が可能である。つまり、HTML側で「#kyoko」のほうを先に記述し、そっちを「float: right」にすれば、「clear: left」の影響を受けずに済む。

//HTML
<div id="wrapper">
  <div id="kyoko">
    <p>恭子日記の本文</p>
    <div class="photo"><img src="photo.png" /></div>
    <p>回り込みテキスト回り込みテキスト</p>
    <p style="clear: left;">回り込みを解除して本文のつづき</p>
  </div>
  <div id="hideo">
    <p>英夫日記の本文</p>
    <div class="photo"><img src="photo.png" /></div>
    <p>回り込みテキスト回り込みテキスト</p>
    <p style="clear: left;">回り込みを解除して本文のつづき</p>
  </div>
</div>

//CSS
#wrapper { width: 410px; }
#kyoko { float: right; width: 200px; background: #ebebeb; }
#hideo { margin-right: 210px; background: #ebebeb; }
.photo { float: left; margin: 0 1em 1em 0; }
p { margin: 0 0 1em; }

↓ブラウザでの表示結果。

恭子日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

英夫日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

サンプル4:そもそも「clear」を使わないという手もある

上記以外に私の知る方法としてはもうひとつ、そもそも「float」の解除に「clear」を使わないという手がある。これであればリキッドレイアウトでも、ボックス内に左寄せの画像と右寄せの画像が混じっていようとも、何でも来いということになる。

これにあたっては、「float」された画像とその回り込みテキストとを1セットにして包むボックス(.photoBox)を用意し、HTML側の構造を次のようにする(最後なので派手に2回ずつ繰り返してみた)。

//HTML
<div id="wrapper">
  <div id="hideo">
    <p>英夫日記の本文</p>
    <div class="photoBox">
      <div class="photoRight"><img src="photo.png" /></div>
      <p>回り込みテキスト回り込みテキスト</p>
    </div>
    <p>回り込みを解除して本文のつづき</p>
    <div class="photoBox">
      <div class="photoLeft"><img src="photo.png" /></div>
      <p>回り込みテキスト回り込みテキスト</p>
    </div>
    <p>回り込みを解除して本文のつづき</p>
  </div>
  <div id="kyoko">
    <p>恭子日記の本文</p>
    <div class="photoBox">
      <div class="photoLeft"><img src="photo.png" /></div>
      <p>回り込みテキスト回り込みテキスト</p>
    </div>
    <p>回り込みを解除して本文のつづき</p>
    <div class="photoBox">
      <div class="photoRight"><img src="photo.png" /></div>
      <p>回り込みテキスト回り込みテキスト</p>
    </div>
    <p>回り込みを解除して本文のつづき</p>
  </div>
</div>

そして「.photoBox」に対して次のようにスタイル指定する。

//CSS
#wrapper { width: 410px; }
#hideo { float: left; width: 200px; background: #ebebeb; }
#kyoko { margin-left: 210px; background: #ebebeb; }
.photoBox { overflow: auto; width: 100%; }
.photoLeft { float: left; margin: 0 1em 1em 0; }
.photoRight { float: right; margin: 0 0 1em 1em; }
p { margin: 0 0 1em; }

これで、「clear」を用いずに(表示上)画像の「float」を解除することができる。
↓ブラウザでの表示結果。

英夫日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

恭子日記の本文

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき

回り込みテキスト回り込みテキスト

回り込みを解除して本文のつづき


以上、これが私の知恵の全部。どれでもお好きなものをどうぞ。

関連記事

トラックバック(1)

トラックバックURL: https://web-conte.com/blue/mt-tb.cgi/147

以下のリストにある記事は、当記事 " 世に言うclearing問題(直前のfloatだけをclearしたい) " を参照しています :

続・clearing問題 from web-conte.com
 いまさらだが、友人の上山君に宛てたもう二年ちかくも前の記事「世に言うclearing問題(直前のfloatだけをclearしたい)」のつづき。一年越しで...

2008年12月26日 19:45