HTML:TDで記号は左寄せ、数値は右寄せ
htmlで対比表をtableやtd要素で作っていて、td内の数値の右寄した状態で±の記号をつけると、数値の桁数に併せて凹凸ができて見づらいので記号だけ左端にそろえてほしいという案件がありました。
記号専用の列を作成すれば解決しますが、CSSの疑似要素の:beforeあたりを使ってうまくできないかと考えて、方法を見つけたので書き残しておきます。
試行錯誤と答え
まず、疑似要素である::beforeを設定し、contentに文字列の+や-を指定する方法だと記号は数値のすぐ手前についてしまいます。
td.plus::before {
content: "+";
}
td.minus::before {
content: "-";
}
答えはfloatでした。記号部分をspanタグで囲ってその要素にfloat:leftをつけます。親要素のtdにはtext-align:rightをつけます。
こうすることで、記号だけはブロックの左端によります。
td {
text-align: right;
}
span.sign {
float:left;
}
しかし、単にfloat:leftを付けただけだと、文字のサイズによって今度は左端で凹凸ができてしまいます。
そこで、floatと一緒にtext-align:centerと、width:30pxを指定します。
ここで指定したspanは本来はインライン要素でwidthの指定は効かないはずですが、float:leftを設定したことにより暗黙のうちにブロック要素に置き換えられています。
ちなみに、::beforeや::afterの疑似要素をtdの左に寄せたい場合は、一旦floatにした要素(ここではspan)に対して::beforeやafterを設定することができます。これだと、中央寄せはできませんがCSSで一気に文字を変えられるので、「▲、△、-」といったように表現を変えたいという移り気なクライアントさんに対しては有効な手法かもしれません。
疑似要素
これ以降は今回利用したCSSに対する詳細です。
疑似要素は、要素の特定の部分にスタイルをつけるものです。
主なものは次の通りです。
- ::before
要素の手前を表します。contentで挿入したい文字列を指定します。
- ::after
要素の後を表します。contentで挿入したい文字列を指定します。
- ::first-letter
文字の先頭1字にスタイルを適用します。
- ::first-line
文章の最初の行にスタイルを適用します。
- ::selection
ユーザーが選択した範囲に対してスタイルを適用します。この疑似要素はcolorやbackground-colorなどや利用できるCSSプロパティが限られます。
float
floatは指定した要素を文字通り浮かせて、右端か左端に持っていくCSSです。
端となる基準は要素を包むブロックとなります。通常のページのフローからははずれますが、フローの一部であり続けます。ちなみにposition:fixedを指定した場合はフローから外れます。
後に続く要素にfloatが指定されている場合はleftまたはrightの指定された方向に積み上がります。
floatのあとに続く要素にfloatが指定されていない場合は、その要素は通常のフローとなりfloat要素と重なって配置されます。ただし要素の中のテキストは重ならずfloat要素に回り込み(積み上がり)ます。
次のような設定でHTMLを組んでみました。「イエロー」の領域はわかりやすいように半透明にしています。「ブルー」という文字は書き出す場所がなくなって下段にあふれ出ています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8"/>
<style>
.first{
background-color: rgba(255,255,0,0.5);
width: 300px;
height: 300px;
float: left;
}
.second{
display: block;
background-color: #9999ff;
width: 150px;
height: 150px;
}
.third{
background-color: #ffcccc;
width: 500px;
height: 100px;
}
.fourth{
display: inline;
color: #ffffff;
background-color: #000000;
}
</style>
</head>
<body>
<div class="first">イエロー</div>
<div class="second">ブルー</div>
<div class="third">レッド</div>
<div class="fourth">ホワイト</div>
</body></html>
このあたりの話は「今更聞けない!エンジニアのための CSS の基礎講座 横並び(float)レイアウト編」を参考にさせていただきました。ありがとうございました。先のサイトによれば、floatの後にfloatのないinline要素を表示させると、元の要素より手前になるそうです。通常inline要素はwidthやheightを持てないので、普通は上の図のようになりますが、ホワイトにmargint-left: 50px;をつけて、イエローに重なるようにするとイエローより前に来ます。
clear
先のfloatの設定で、後に続く通常のページのフローに入る要素をfloat要素と重ねたくない場合があると思います。
その際に、clearを使います。
floatの後に追加する、通常のフローに加えたい要素に対してclearのCSSを適用させます。
先行するleftのフロートから切り離すclear:left、rightのフロートから切り離すclear:right、両方の方向のフロートから切り離すclear:both等の設定があります。
後述するようにCSSで全プロパティが適用されるのはブロックレベル要素の時のみです。全ての要素に適用されるfloatとは違い、clearプロパティはブロックレベル要素にしか適用されません。そのためインライン要素(デフォルトのspan等)にclear: both;を設定しても効きませんので注意してください。
CSSのボックスモデル
インライン要素にclear: both;をつけても効かないという話を理解するために、CSSのボックスモデルについて話を広げます。
CSSにおいてコンテンツを表示するための領域をボックスといいます。これはCSSのdisplayの項目で登場しています。
「display: block」は「ボックスモデル」における「ブロックボックス」を指定しています。同様に、inlineは「インラインボックス」を指定しています。
CSSで指定した値が完全な形で反映されるのはブロックボックスに対してのみで、インラインボックスはその一部が適用されます。たとえばインラインボックスではwidthやheightのプロパティは適用されません。また、paddingやmargin、borderは適用されます。
ブロックボックスがCSSの値を完全に反映するといっても、ブロックボックスにheightやwidthを設定して思った通りにならない経験があると思います。これはwidthとheightプロパティが尊重されるべき値で強制するものではないためです。
外側と内側
ボックスモデルにはさらに「外側」と「内側」の表示タイプがあります。外側は先のようにブロックボックスと、インラインボックスだけですが内側はそれとは別のものも存在します。
たとえば、display:flexに指定した場合はブロックボックスを外側に作成し内側はFlexBoxのルールに基づきレイアウトされることなります。ちなみにinline-flexとすると外側がインラインボックスになります。
ボックスの構成
CSSのブロックボックスは4つの層で構成されています。まず、一番内側にあるコンテンツを表示させるためのボックス。次に、パディング用のボックス、その外側に、ボーダー用のボックス、一番外側にマージン用のボックスがあります。
通常widthやheightを指定すると、コンテンツ用のボックスのサイズを指定することになります。そこにパディングとボーダーを指定するとサイズはその分膨らみます。マージンはボックスの実際のサイズにはカウントされません。
代替ボックスモデル
上記ボックスモデルでは、たとえば100%という値をwidthに指定して親要素の内側に入れようと思った時、100%は親のコンテンツボックスと同じコンテンツボックスのサイズを持つことまではいいのですが、ボーダーは考慮されませんので、ボーダーがある場合はその太さの分だけ親要素をはみ出してしまいます。
それでは設定が面倒だろうということで出てきたのがbox-sizingプロパティです。
このプロパティを「border-box」とすると、widthはborderまでのサイズを指すようになります。これにより、先のような「はみ出し」は起きなくなりますが、今度はボーダーの太さが元のコンテンツのサイズを浸食するようになります。position:relativeやabsoluteで、コンテンツボックスに対する相対位置を得たい場合は従来の「content-box」の方がわかりやすいケースもあります。
border-boxをページ全体に適用させるには次のようにします。htmlに対して設定をし、他の要素と疑似要素には継承(inherit)を指定します。
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}