スタイルシートによるレイアウト変更【floatとpositionという2つプロパティ】

2015/12/13

スタイルシート

人間世界で要素という言葉は「物・事を成り立たせるもとであるそれ以上は簡単なものに分析できないもの」というこれ以上分解できない絶対的な単位という意味がありますが、一方システムは人間の言葉をそのままでは理解できないので、理解できるようにタグを付けて範囲を明確にしてあげた後のカタマリを要素と考えます。

ジャカルタ

インドネシアのITサービス

インターネット技術の急速な発展と普及により、優秀なIT人材を輩出することで知られるジャカルタのビヌス大学(BINUS)やバンドゥンのバンドゥン工科大学、インドネシアコンピューター大学(UNIKOM)の学生の多くがインターネット・WEB業界やソフトウェア業界を志望するようです。

続きを見る

人間世界とシステムの世界での要素と属性

「人間にとって自明の要素をシステムに解釈させるためにタグを付けて範囲を明確にする」という行為は、人間が範囲を決める以上相対的なものにならざるを得ず、必然的にHTML要素は入れ子構造になります。

人間世界でプロパティ(属性)という言葉は「土地・資産・所有物」という意味であり、世の中のすべてのオブジェクトは属性を持っています。

不動産という意味ではProperty以外にReal estateという言葉がありますが、Propertyの場合personal property(動産)とreal property(不動産)を含む一般的言葉であるのに対し、Real estateは法的に守られたestate(資産)全般という意味合いが強いです。

ちなみに近いところでasset(資産)という言葉がありますが、有形固定資産がFixed assetであるのに対し、無形固定資産はIntangible assetであり、前者は間接法でDepreciation(減価償却)され、後者は直接法でAmortization(なし崩し償却)されます。

一方でシステムの世界の属性はオブジェクトが持つ「特徴・性質」という意味であり、HTML要素内の属性はDOMオブジェクトのプロパティに割り当てられ、CSSでセレクタというオブジェクトとして、プロパティと値を持っています。

セレクタはスタイルを適用する対象を示すものであり、中括弧の中にプロパティと値を宣言します。

そして要素とはHTMLの開始タグと終了タグで囲まれた意味のある単位であり、スタイルは要素に対して適用するときはHTMLタグをセレクタとして指定し、属性に対して適用するときは属性をセレクタとして記述します。

要素セレクタと属性セレクタ

セレクタはWEB上のオブジェクトに対して、装飾(CSSにてプロパティに値を設定)したり処理を実行(メソッドやイベント)したりするための仲介役ですが、セレクタになる資格のあるものはHTML要素またはHTML属性になります。

  1. 要素セレクタはそのまま記述「$('p')」
  2. 属性セレクタ
    idは「$('#yama')」、classは「$('.zou')」
    その他の属性は大括弧$(a['href="https://bahtera.jp"]')で囲む。
  3. ブランクは「それ以下の子要素」、カンマは「複数の要素」、プラス(+)は「隣接要素」、不等号(>)は「直下の子要素」

セレクタが処理するメソッドにはプロパティに値を設定する役割と値を取得する役割がありますが、記述上の違いはプロパティと値をセットで書くか、プロパティのみを書くかです。

  • 値を設定 : $('p').css('color', red);
  • 値を取得 : console.log$('p').css('color');

バリ島の不動産屋とセレクタの関係

WEBシステムの世界では、セレクタはオブジェクトの性格を定義するプロパティや、処理を行うメソッドとの仲介屋みたいな重要な機能を担っており、WEBサイトがブラウザ上でDOMにより要素単位でオブジェクト化されるタイミングで、要素セレクタや属性セレクタは、CSSやjQuery上で、プロパティによって値が代入されたり、メソッドによって処理されたりします。

要素とか属性とかいう言葉は日常生活の特殊なシーンでなんとなく聞くこともありますが、セレクタという言葉になると耳にする機会は俄然少なくなります。

MT車のギアチェンジを行うためのシフトレバーはAT車ではセレクター(セレクトレバー)と呼ぶそうですがあまり聞かないですね。

セレクタを説明するにはバリ島の不動産屋をイメージするとわかりやすいと思います。

バリ島(body要素)には、クタエリア(header要素)、ヌサドゥアエリア(nav要素)、デンパサールエリア(article要素)、ウブドゥエリア(footer要素)みたいにそれぞれエリアごとに不動産屋がありますが、各不動産屋のオフィスから遠いエリアへ行くには交通費等のコストがかかるため、だいたい専門外のエリアには手を出したがりません。

bodyタグ内を「ヘッダー領域」「サイドバー領域」「コンテンツ領域」「フッター領域」の4ブロックに区切るのがセクション要素であり、CSS上でそこに属するブロックレベル要素(perumahan 集合住宅)やインライン要素(VillaやCondominium)ごとに分類(プロパティに値を設定)し管理するのがセレクタ(不動産屋)の役割です。

オーナーは、不動産屋で自分の所有物件についての情報を専用フォーム(CSS)の「土地面積」「建物面積」「希望価格」等の項目(プロパティ)にデータ(値)を記入し、その情報を元に不動産屋が自社の物件管理機能付きWEBサイト(jQuery)上にストックとして登録します。

一方で賃貸や購入希望者は「バリ島 不動産」でググッて、不動産屋のWEBサイト(jQuery)に到達すると、エリア、価格等の条件で絞込み検索(メソッド実行)を行い、希望する物件を探します。

セレクタとはずばり、それがCSSではスタイルを適用する対象を示し、jQueryではメソッドやイベント発生時の処理対象になるものです。

配列の要素

簡単に言うと配列はお年玉用のルピア紙幣の入った封筒を束ねたようなものであり、封筒に連番が振ってあれば通常配列、渡す相手の名前が書いてあれば連想配列になります。

要素はこの場合のルピア紙幣の入った封筒全体であり、ルピア紙幣が値、封筒に振ってあるのが連番ならインデックス、相手の名前ならキーとなります。

封筒からルピア紙幣を出した後の相手の名前付きの空の封筒をプロパティと考えると、入れるものはルピア紙幣に限る必要はなく、車のキーでも手紙でもいいわけです。

ただし航空券が入っている場合は、「スカルノハッタ空港からバリ島に飛ぶ」というアクションを約束するものですので、航空券は関数リテラルという値であると考えられます。この場合は別の封筒には名義人の名前を入れておく(参照渡し)する必要があります。

style属性とstyle要素

 

//div要素(エレメントオブジェクト)のid属性がheaderという値を持つ
<div id="header"></div>

//p要素(エレメントオブジェクト)のstyle属性がmarginというプロパティと4pxという値を持つ
<p style="margin: 4px; padding : 2px"></p>

HTML文章はブラウザのDOMによって要素(エレメント)オブジェクト化され、要素が持つプロパティの値をJavaScriptで更新することでHTML文章上の表示が変化します。

CSSをインラインスタイルで書く場合、p要素オブジェクトの中のstyle属性に配列リテラルを代入しますが、style要素の中に書く場合にはp要素がCSSのセレクタ(Selector)となります。

<html>
<head>
  <style>
    p {
        margin : 4px;
        padding : 2px;
    }
  </style>
</head>

<body>
  <p></p>
</body>

インライン表記のstyle属性の場合はダブルコーテーションで囲むのがややこしいですが、これは昔HTMLタグにプロパティと値を指定するときにダブルコーテーションを使用したなごりではないでしょうか?

//HTMLタグにプロパティと値を指定
<p><font color="blue"></font></p>

属性の値がカスケード状に影響するCSS

DOMによってhtmlタグはdocumentオブジェクト化されツリー上にオブジェクト化された要素が繋がっていきますが、オブジェクトに対するプロパティと値を完全分離し、プロパティと値の組み合わせを変化させることにより、オブジェクトを修正することなく見栄えだけを変えるのがCSSの本来の目的です。

レスポンシブデザインのWEBサイトがまさにこれなんですが、ツリー状のオブジェクトの上位に設定されたプロパティの値は下位のオブジェクトにも影響するのがカスケード(滝の流れ)の本質になります。

親要素の高さが計算されずマージンの基点がおかしい

floatで横並び(右寄せ)

普通にブロックレベル要素を並べるとこのように縦並びですが・・・

なし
なし
なし

以下のようにfloatを指定(width必須)すると配置が変わります。

float:left; width: 150px
float:left; width: 150px
float:left; width: 150px
float:left; width: 150px
float:left; width: 150px
clear:left; width: 150px
float:left; width: 150px
float:left; width: 150px
なし width: 150px
//緑・青・赤の要素全部左寄せ
//子ブロック要素は全部浮いているので親ブロック要素の高さは0pxと見なされる。
//マージンの基点が親ブロック要素の左上、つまり0pxの位置と見なされる。
//親要素に擬似要素afterを使って、親ブロック要素の末尾にブランクの(content:””;)
//ダミーのブロックレベル要素(display: block;)を追加して、そこでクリア(clear: both;)する。
<div id="ABC1" style="width: 465px; margin-bottom: 10px;">
    <div id="A1" style="width: 150px; height: 20px; background-color: #009900; float: left;">float:left; width: 150px</div>
    <div id="B1" style="width: 150px; height: 20px; background-color: #0033ff; float: left;">float:left; width: 150px</div>
    <div id="C1" style="width: 150px; height: 20px; background-color: #ff0066; float: left;">float:left; width: 150px</div>
</div>

//青要素のfloatの流れを赤でクリア
<div id="ABC2" style="width: 465px; margin-bottom: 10px;">
    <div id="A2" style="width: 150px; height: 20px; background-color: #009900; float: left;">float:left; width: 150px</div>
    <div id="B2" style="width: 150px; height: 20px; background-color: #0033ff; float: left;">float:left; width: 150px</div>
    <div id="C2" style="width: 150px; height: 20px; background-color: #ff0066; clear: left;">clear:left; width: 150px</div>
</div>

//緑要素と青要素が浮いて空いたスペースにフロートなしの赤要素が入っているので緑要素に隠れて見えない。
//floatの後のコンテンツ「なし」は反対に回り込もうとするも赤要素のwidthが150pxしかないので下に追いやられる。
<div id="ABC3" style="width: 465px; margin-bottom: 10px;">
    <div id="A3" style="width: 150px; height: 20px; background-color: #009900; float: left;">float:left; width: 150px</div>
    <div id="B3" style="width: 150px; height: 20px; background-color: #0033ff; float: left;">float:left; width: 150px</div>
    <div id="C3" style="width: 150px; height: 20px; background-color: #ff0066;">なし width: 150px</div>
</div>

clearfixでfloat解除

これ、普通にマージンが10pxずつ空いていますけど、上述のとおりfloatを設定している子ブロック要素は全部浮いているので、親ブロック要素ABC1の高さは0pxと見なされ、マージンの基点が親ブロック要素の左上、つまり0pxの位置と見なされます。

よって親ブロック要素に設定するマージンの高さは、子要素の高さ20px以内では表示されず、20px以上ではじめて反映され始めます。

だから通常の配置の流れの中にfloatをクリアするブロックレベル要素を作れば、そこを基点にマージンが計算されます。

<p style="clear:both;"></p>

ただ格好悪いので、擬似要素afterを使って、親ブロック要素の末尾、つまり最後の子要素の後ろに

  1. 中身はブランクの(content:"";)
  2. ダミーのブロックレベル要素(display: block;)
  3. vertical-alignのベースラインをはみ出ないように(font-size: 0;)
  4. そこでクリア(clear: both;)しています。

ちなみにこのafter擬似要素とclearプロパティを使ってフロートを解除することをclearfixといいます。

<style>
	#ABC1:after, #ABC2:after, #ABC3:after{
		content:"";
		display:block;
		font-size: 0;
		clear:both;
	}
</style>

ちなみに擬似要素(after, first-lineなど)はHTMLソースには存在しない要素を表す要素であり、例えば「:after」なら「あるタグに含まれる内容の末尾」になり、このようなHTMLタグが実際に書かれているわけではありません。

似たものとして擬似クラスがありますが、これはある要素の状態(hover, activeなど)を指定するときに使います。

親要素が子要素を囲むことができず背景が消える

浮いた子要素を親要素が認識できない

子要素がfloatで浮いているので親要素は子要素の存在を認識できず、paddingによって子要素を囲むことができません。

#header1{
    padding: 10px;
}
<div id="header1" style="font-family: Meiryo UI; font-size: 12px; width=100%; background-color:yellow; padding: 10px;">
	<div id="left2" style="width: 50%; background-color: orange; float: left;">left</div>
	<div id="right2" style="width: 50%; background-color: #dda0dd; float: right;">right</div>
</div>
left
right

ダミー子要素(兄弟要素)でfloat解除

いちばん簡単なのはfloatしている子要素のダミーの兄弟要素を作って「clear:left;」でクリアすることですが、格好悪っ・・・。

#header5{
    padding: 10px;
}
<div id="header5" style="font-family: Meiryo UI; font-size: 12px; width=100%; background-color:yellow; padding: 10px;">
	<div id="left2" style="width: 50%; background-color: orange; float: left;">left</div>
	<div id="right2" style="width: 50%; background-color: #dda0dd; float: right;">right</div>
        <p style="clear:left; height:0px;"></p>
</div>
left
right

親要素に高さ指定

もっとも親要素に高さを設定していれば、背景色が表示されますが・・・

#header1{
    padding: 10px;
    height:30px;
}
<div id="header2" style="font-family: Meiryo UI; font-size: 12px; width=100%; background-color:yellow; height:30px; padding: 5px;">
	<div id="left2" style="width: 50%; background-color: orange; float: left;">left</div>
	<div id="right2" style="width: 50%; background-color: #dda0dd; float: right;">right</div>
</div>
left
right

clearfixでfloat解除

高さを正しく設定するためにエネルギーを費やすよりも、親要素が完了した時点でfloatを解除してあげれば親要素のpaddingが効くようになります。

これは親要素の中身の末尾(:after)、すなわちright子要素の後ろに、ダミーの兄弟ブロック要素(display: block;)を挿入して、中身としてブランクを挿入して(content:" ")、フロートをクリア(clear: both;)しています。

#header4{
    padding: 10px;
    height:30px;
}

#header4:after{
    content:" ";
    display: block;
    clear: both;
}

<div id="header4" style="font-family: Meiryo UI; font-size: 12px; width=100%; background-color:yellow; height:30px; padding: 5px;">
	<div id="left2" style="width: 50%; background-color: orange; float: left;">left</div>
	<div id="right2" style="width: 50%; background-color: #dda0dd; float: right;">right</div>
</div>

left
right

親要素のoverflowプロパティをhiddenにしてfloat解除

after擬似要素とclearプロパティでフロートを解除する方法をclearfixといいますが、もっと簡単に親要素にoverflowプロパティの値としてhiddenを設定する方法もあります。

#header5{
    padding: 10px;
    overflow:hidden;
}
<div id="header6" style="font-family: Meiryo UI; font-size: 12px; width=100%; background-color:yellow; padding: 10px; overflow:hidden;">
	<div id="left2" style="width: 50%; background-color: orange; float: left;">left</div>
	<div id="right2" style="width: 50%; background-color: #dda0dd; float: right;">right</div>
</div>
left
right

親要素に何も指定がない場合

親要素にpaddingも高さも指定されていないと、子要素が浮き上がって別フローになっているので、親要素は子要素を含有することにより確保していた高さを失い、背景色が表示されません。

#header1{

}
left

ブロック要素は親要素の横幅一杯に広がって配置される

ブロックレベル要素は、幅指定がなければ親要素の中で横幅一杯に広がって配置されますが、これは本来ブロックレベル要素の横に同一フロー内において他の要素を並べることができないからです。

<div class="boxA">
<div class="box1">1</div>
<div class="box2">2</div>
TESTEST</div>
.boxA{
    background-color:#66ccff;
    width:200px;
    height:200px;
}
  
.box1{
    background-color:#66cc99;
}
  
.box2{
    background-color:#ffcccc;
}

隣接する上下要素のマージンは相殺する

兄弟要素の上から40px、下から30pxずつマージンをとっても、相殺されて片方の40pxしかマージンは空きません。

.boxA{
    background-color:#66ccff;
    width:200px;
    height:200px;
}
  
.box1{
    background-color:#66cc99;
    margin-bottom:40px;
}
  
.box2{
    background-color:#ffcccc;
    margin-top:30px;
}

子要素がabsoluteの場合

position属性の値がabsoluteの場合、配置の基点は親要素の基点と同じく左上であり、magin-topとmargin-leftは効きますがmargin-bottomとmargin-rightは効きません。

しかも本来配置されていた領域を確保しないため、指定のボックスは必要最小限の領域しか確保せず、下の文字「YAMA3」が上にスライドします。

.boxA{
    background-color:#66ccff;
    width:200px;
    height:200px;
    position:relative;
}
  
.box1{
    background-color:#66cc99;
    margin-bottom:40px; /*効かない*/
    position:absolute;
}
  
.box2{
    background-color:#ffcccc;
    margin-top:20px;
    position:absolute;
}

親要素のpadding-topと子要素のmargin-topは両方とも有効

相殺が起こるのはmargin同士のみであり、padding同士やpaddingとmarginの間では相殺しません。この場合親要素のpadding-topと子要素のmargin-topが効いています。

.boxA{
    background-color:#66ccff;
    width:200px;
    height:200px;
    position:relative;
    padding-top:20px;
}
  
.box1{
    background-color:#66cc99;
    margin-top:20px;
    margin-bottom:40px; /*効かない*/
    position:absolute;	
}
  
.box2{
    background-color:#ffcccc;
    margin-top:30px;
    position:absolute;
}

positionがabsoluteの場合margin-rightが効かない。

positionがabsoluteの場合は基点が親要素の左上なので、margin-leftは親要素の左から離れますが、margin-rightが効きません。

.boxA{
    background-color:#66ccff;
    width:200px;
    height:200px;
    position:relative;
    padding-top:20px;
}
  
.box1{
    background-color:#66cc99;
    margin-top: 20px; 
    margin-bottom:20px; /*効かない*/
    position:absolute;	
    margin-right:20px; /*効かない*/	
}
  
.box2{
    background-color:#ffcccc;
    margin-top:20px;
    position:absolute;
    margin-left:20px; /*親要素のボーダーから20px離れる*/
}

positionプロパティ

floatとmargin-left(子ボックス)またはpadding-left(親ボックス)を使わずとも、positionとtopとleftで位置を動かすことができます。

  1. static : 何も指定しないのと同じ(staticを指定することはない)。
  2. relative : 親要素のpositionに関係なく、親要素のコンテンツ直下から相対的に位置をずらす
  3. absolute :
    1. 親要素のpositionがstatic(またはpositionなし)ならウィンドウの枠の左上が基準
    2. 親要素のpositionがrelativeまたはabsoluteなら親要素と同じ位置を基点
  4. fixed : ウィンドウの特定の位置に固定。

親ブロック要素がstaticの場合

 

  1. 親要素static、子要素staticは、position属性がないのと同じなので、親コンテンツの下に続く。
    <div id="box1" style="width: 200px; height: 200px; position: static;">
    <div id="box1-1" style="width: 100px; height: 100px; position: static;"></div>
    </div>

  2. 親要素static、子要素relativeは、親要素のコンテンツの下から位置をずらす。
    <div id="box2" style="width: 200px; height: 200px; position: static;">
    <div id="box2-1" style="width: 100px; height: 100px; position: relative; top: 80px; left: 80px;"></div>
    </div>

  3. 親要素static、子要素absoluteは、子要素はウィンドウ全体の枠を基点とする。
    <div id="box3" style="width: 200px; height: 200px; position: static;">
    <div id="box3-1" style="width: 100px; height: 100px; position: absolute; top: 80px; left: 80px;"></div>
    </div>

親ブロック要素がrelativeの場合

 

  1. 親要素relative、子要素staticは、position属性がないのと同じなので、親コンテンツの下に続く。
    <div id="box4" style="width: 200px; height: 200px; position: relative;">
    <div id="box4-1" style="width: 100px; height: 100px; position: static;"></div>
    </div>

  2. 親要素relative、子要素relativeは、親要素のコンテンツの下から位置をずらす。
    <div id="box5" style="width: 200px; height: 200px; position: relative;">
    <div id="box5-1" style="width: 100px; height: 100px; position: relative; top: 80px; left: 80px;"></div>
    </div>

  3. 親要素relative、子要素absoluteは、親要素の基点から位置をずらす。
    <div id="box6" style="width: 200px; height: 200px; position: relative;">
    <div id="box6-1" style="width: 100px; height: 100px; position: absolute; top: 80px; left: 80px;"></div>
    </div>

親ブロック要素がabsoluteの場合

親ブロックがabsoluteであれば親ブロックが配置の基準になるとはいえ、元の領域を確保しないので下の子ブロックが上詰めで浮き上がり重なり合います。

  1. 親要素absolute、子要素staticは、position属性がないのと同じなので、親コンテンツの下に続く。
    <div id="box7" style="width: 200px; height: 200px; position: absolute;">
    <div id="box7-1" style="width: 100px; height: 100px; position: static;"></div>
    </div>

  2. 親要素absolute、子要素relativeは、親要素のコンテンツの下から位置をずらす。
    <div id="box8" style="width: 200px; height: 200px; position: absolute;">
    <div id="box8-1" style="width: 100px; height: 100px; position: relative; top: 80px; left: 80px;"></div>
    </div>

  3. 親要素absolute、子要素absoluteは、親要素の基点から位置をずらす。
    <div id="box9" style="width: 200px; height: 200px; position: absolute;">
    <div id="box9-1" style="width: 100px; height: 100px; position: absolute; top: 80px; left: 80px;"></div>
    </div>