簡単にCSSレイアウトできるフレームワークを考えてみる

これからの時代はCSSレイアウトということで、Webアプリを作る際はなるべくfloatベースのCSSレイアウトを使うようにしてます。最近でこそそれなりに慣れてきましたが、はじめは clearfix やら カラム落ちで何度も同じような苦労をしてたような気がします。
今、職場ではアプリ開発運用業務の見直しの一環としてWebアプリ開発の勉強会や標準化の検討などを行っており、内作・外注にかかわらずある程度統一性をもった保守しやすいソースコードの作成をいかにして実現するかが一つの課題になっています。
そんな事情もあり今回はCSSレイアウトをフレームワーク化(標準化/規約化)することで誰でも簡単にCSSレイアウトを組めるようにできないか考えてみました。

垂直配置コンテナ

Webページのレイアウトといえばヘッダ、ボディ、フッタが大抵あるので、そのような場合以下のクラスを使用します。

    • div.my-head-container
    • div.my-body-container
    • div.my-foot-container
    • div.my-container ←汎用的に使用

これをHTMLで順番に段組するとこんな感じになります。(サンプルはレイアウトを分かりやすくするため着色してます。)

<div class="my-head-container">
</div>
<div class="my-body-container">
</div>
<div class="my-foot-container">
</div>


サンプルページ

水平配置コンテナ(2カラム) | 比率幅指定

垂直配置コンテナ内に水平方向に分割配置するコンテナとして、メイン、サブ、拡張が定義してあります。

    • div.my-main-container
    • div.my-sub-container
    • div.my-ext-container

これら水平配置コンテナの幅や配置は、コンテナの包括要素(つまりdiv.my-body-containerなど)に各水平配置コンテナの幅や配置を表す以下例のようなレイアウトクラス名を追加することで指定できます。

    • div.my-layout_1m_1s
    • div.my-layout_3m_2s
    • div.my-layout_3s_7m

こんな感じになります。(my-layout_3m_2sの適用例)

<div class="my-head-container">
</div>
<div class="my-body-container my-layout_3m_2s">
    <div class="my-main-container">
    </div>
    <div class="my-sub-container">
    </div>
</div>
<div class="my-foot-container">
</div>


サンプルページ

また、以下のように垂直配置コンテナを入れ子にし混在させることもできます。この場合はmy-containerを使用します。my-container が my-body-container 内において ヘッダ、フッタの役割をします。

<div class="my-head-container">
</div>
<div class="my-body-container my-layout_3m_2s">
    <div class="my-container">
    </div>
    <div class="my-main-container">
    </div>
    <div class="my-sub-container">
    </div>
    <div class="my-container">
    </div>
</div>
<div class="my-foot-container">
</div>


サンプルページ

my-layout_3m_2sを例にレイアウトクラスの命名規約から位置と幅を読み取ってみます。

位置

3mm が my-main-container を指し、2ss が my-sub-container を指します。つまり 3m,2s の順で並んでるので、my-main-containerが左配置、my-sub-containerが右配置になります。

3m の 32s の 2 の合計値である 5 で包括要素の幅を分割し(5分割)、3 と 2 は各コンテナに対する分割幅の割り当て比率になります。つまりmy-main-containerの割当幅が 3/5 で 60% 、my-sub-containerの割当幅が 2/5 で 40% になります。

レイアウトクラスの配置と幅

したがって、先の例で挙げた各レイアウトクラス名の水平配置コンテナの配置と幅は、以下のようになります。

my-layout_1m_1s

  div.my-main-container div.my-sub-container
位置 left right
50% 50%

my-layout_3m_2s

  div.my-main-container div.my-sub-container
位置 left right
60% 40%

my-layout_3s_7m

  div.my-sub-container div.my-main-container
位置 left right
30% 70%

水平配置コンテナ(3カラム) | 比率幅指定

3カラムの場合は3つ目の水平配置コンテナとしてdiv.my-ext-containerを使用します。以下にレイアウトクラスにmy-layout_1e_2m_1sを適用した場合の例を示します。条件は2カラムの場合と同様で1eの部分がmy-ext-containerに相当します。

<div class="my-head-container">
</div>
<div class="my-body-container my-layout_1e_2m_1s">
    <div class="my-ext-container">
    </div>
    <div class="my-main-container">
    </div>
    <div class="my-sub-container">
    </div>
</div>
<div class="my-foot-container">
</div>


サンプルページ

my-layout_1e_2m_1s

  div.my-ext-container div.my-main-container div.my-sub-container
位置 left center right
25% 50% 25%

水平配置コンテナ(カラムの組み合わせ) | 比率幅指定

以下のように入れ子にして組み合わせることも可能です。

<div class="my-head-container">
</div>
<div class="my-body-container my-layout_3m_2s">
    <div class="my-container">
    </div>
    <div class="my-main-container my-layout_1m_1s">
        <div class="my-container">
        </div>
        <div class="my-main-container">
        </div>
        <div class="my-sub-container">
        </div>
        <div class="my-container">
        </div>
    </div>
    <div class="my-sub-container">
    </div>
    <div class="my-container">
    </div>
</div>
<div class="my-foot-container">
</div>


サンプルページ

フレームワークCSS定義

フレームワークCSSは以下のよう定義されてます。

コンテナ関連
/*
============================================================================
Define Container Parts
============================================================================*/  
/*
vertical-container
/----------------------------------------------------------------------------*/  
div.my-container ,
div.my-head-container ,
div.my-body-container ,
div.my-foot-container {
	width:100%;
	clear:both;
	overflow:hidden;
	zoom:1;
}
/*
horizontal-container
/----------------------------------------------------------------------------*/  
div.my-main-container ,
div.my-sub-container ,
div.my-ext-container {
	overflow:hidden;
	zoom:1;
}
レイアウト関連
/*
============================================================================
Define Layout Parts
============================================================================*/  
/*
div.my-layout_1m_1s
/----------------------------------------------------------------------------*/  
div.my-layout_1m_1s{
	width:100%;
	clear:both;
	overflow:hidden;
	zoom:1;
}
div div.my-layout_1m_1s div.my-main-container,
div.my-layout_1m_1s div.my-main-container{
	width:50%;
	float:left;
	margin-right:-1px; /*for IE Bug*/
	overflow:hidden;
	zoom:1;
}
div div.my-layout_1m_1s div.my-sub-container,
div.my-layout_1m_1s div.my-sub-container{
	width:50%;
	float:right;
	overflow:hidden;
	zoom:1;
}
/*
div.my-layout_3m_2s
/----------------------------------------------------------------------------*/  
div.my-layout_3m_2s{
	width:100%;
	clear:both;
	overflow:hidden;
	zoom:1;
}
div div.my-layout_3m_2s div.my-main-container,
div.my-layout_3m_2s div.my-main-container{
	width:60%;
	float:left;
	overflow:hidden;
	zoom:1;
}
div div.my-layout_3m_2s div.my-sub-container,
div.my-layout_3m_2s div.my-sub-container{
	width:40%;
	float:right;
	overflow:hidden;
	overflow:hidden;
	zoom:1;
}
/*
div.my-layout_3s_7m
/----------------------------------------------------------------------------*/  
div.my-layout_3s_7m{
	width:100%;
	clear:both;
	overflow:hidden;
	zoom:1;
}
div div.my-layout_3s_7m div.my-sub-container,
div.my-layout_3s_7m div.my-sub-container{
	width:30%;
	float:left;
	overflow:hidden;
	zoom:1;
}
div div.my-layout_3s_7m div.my-main-container,
div.my-layout_3s_7m div.my-main-container{
	width:70%;
	float:right;
	overflow:hidden;
	zoom:1;
}
概要説明

先の具体例で挙げたとおり各コンテナの幅が垂直配置コンテナの場合は100%、水平配置コンテナの場合は各カラム幅の合計が100%になるようにしています。
レイアウト定義で以下の様に

div div.my-layout_1m_1s div.my-main-container,
div.my-layout_1m_1s div.my-main-container{

クラス指定の無いDIVを親としたセレクタの指定をしてるのは、先の「水平配置コンテナ(カラムの組み合わせ) | 比率幅指定」の例で示した様に入れ子で水平配置コンテナを使用した場合、直近の親のレイアウトクラス名の指定が適用されるようにするためです。
div.my-layout_1m_1s の margin-right:-1px は IEの場合のみ発生するカラム落ちの対策です。(他にいい方法が見つけられなかった..)
すべての定義に記述されてるのが、overflow:hidden;zoom:1 ですがこれは主に clearfixの代替として定義しています。詳しくは以下エントリを参照ください。

え!たったこれだけで clearfix いらなくなるってこと?ほんと?
ということで私のもう一つのブログで、サンプルHTMLを作って各ブラウザで確認してみました。

clearfixの無いリスト要素(ul,li)ベースのフォーム(form) - Cyokodog::Diary

clearfixの使用目的というと、

    • float要素を包括する要素にはfloat要素の高さが含まれてないので、高さを含ませたい
    • float要素を包括する要素に後続する要素を回り込み表示をさせたくない

などが挙げられますが、ここでは、

    • margin要素を包括する要素にはmargin分の高さ含まれないので、高さを含ませたい

という意図もあります。

margin要素の相殺と包括要素の関係

例えばこんなHTMLの場合だと

<style>
	.head{
		background:#ddeeff;
	}
	.body{
		background:#ccc;
	}
</style>
<body>
	<div class="head">
		<h1>site name</h1>
	</div>
	<div class="body">
		<h2>page name</h2>
	</div>
</body>

h1、h2にmarginが効いてるため以下のように包括要素間に隙間ができます。

包括要素の div に overflow:hidden;zoom:1 を加えると以下のように包括要素に margin 分の高さがでて包括要素間に隙間が無くなります。

隣り合った要素が互いにmarginをかけてた場合、margin量を相殺するというルールがありますが、上の最初の例のようにmargin要素に包括要素があっても相殺は行われます。但し、包括要素にoverflow:hidden;zoom:1やborderあるいはclearfixを与えると、包括要素にmargin分の高さが含まれ相殺は行われません。
ちなみに同じ意図のことをclearfixで行うには、.clearfix:after以外にも.clearfix:beforeの定義が必要になります。overflow:hidden;zoom:1の方が楽でいいですね。
marginの相殺については to-R さんのこちらの記事がわかりやすいです。

CSSにおけるmarginプロパティはボックスに対して余白部分を生成するというシンプルなものなのですが、『marginの相殺』という特徴があります。

marginの相殺 - to-R

ダウンロード

こちらからどうぞ。

以下クラスが定義されています。
コンテナ

    • my-container
    • my-head-container
    • my-body-container
    • my-foot-container
    • my-main-container
    • my-sub-container
    • my-ext-container

2カラムレイアウト(main:left sub:right)

    • my-layout_1m_1s
    • my-layout_2m_1s
    • my-layout_3m_1s
    • my-layout_3m_2s
    • my-layout_7m_3s

2カラムレイアウト(sub:left main:right)

    • my-layout_1s_1m
    • my-layout_1s_2m
    • my-layout_1s_3m
    • my-layout_2s_3m
    • my-layout_3s_7m

3カラムレイアウト(ext:left main:center sub:right)

    • my-layout_1e_2m_1s