CSSは簡単にかじった程度の者ですが、ブロック要素を1行に左寄せおよび右寄せに配置したい場合のCSSってどう書くのが一番最強なのか検討してみました。
※ここでの「最強」とは私が考え・感じる「いい感じ」な表現方法になります。
もっと素敵な方法があるかもしれません。皆様他素敵な方法あったら教えてください。
発端
プロジェクトで作成された 1 行に左寄せ右寄せができるようになったスタイルテンプレートが読みにくくて仕方ない気がして気になってしまった。
やりたいこと
次のように、div タグの中に左寄せ右寄せができる領域を表現する div タグがあり(以下例であればalign-leftとalign-right)。そこにボタンなどを追加していけば左寄せの領域は左に、右寄せの領域は右にボタンが配置される。
<div class="parent-box">
<div class="child-box align-left">
<div>左寄せ領域</div>
<button class="btn">ボタンA</button>
<button class="btn">ボタンB</button>
</div>
<div class="child-box align-right">
<div>右寄せ領域</div>
<button class="btn">ボタンC</button>
</div>
</div>
■ 作りたい画面イメージ
この画面のように、左寄せの領域・右寄せの領域をもったテンプレートを作成して各実装者は作成する画面の設計に応じてボタン等を配置すればOK!みたいな画面を作成する。
なお、以降見やすさのため特に言及しないが以下cssを適応しているものとする。
※全体の領域をグレー、右寄せ左寄せの領域をブラックにして見やすくするためのみに利用しております。
div {
margin: 5px;
}
.parent-box {
background: gray;
width: 100%;
}
.child-box {
background: black;
color: white;
}
実装方法
1. float で頑張る
正直私は調査前は恥ずかしながらこの「float」でやる方法しか知りませんでした。
これは、私のような旧時代の人間が使う方法で、いたる所にわかりにくさが隠されている方法になります。実装する場合は例えば以下のようになります。
<div class="parent-box float">
<div class="child-box align-left">
<div>左寄せ領域</div>
<button class="btn">ボタンA</button>
<button class="btn">ボタンB</button>
</div>
<div class="child-box align-right">
<div>右寄せ領域</div>
<button class="btn">ボタンC</button>
</div>
</div>
<div class="clear"></div>
.float {
overflow: hidden;
}
.float .align-left {
float: left;
}
.float .align-right {
float: right;
}
.clear {
clear: both;
}
■画面
コードを見ていただけばわかる通り謎のclearが必要だったり、overflowを書かないとうまく動かなかったり、考えただけで吐き気がしますね。当然簡単ではないためこれは最強のcssではありません。詳細を知りたい方はfloatを使ったブロック要素の右寄せ、左寄せとclearの方法を参考にしてください。
2. FlexBoxのFlexアイテムを調整する
これが私が参画しているプロジェクトで使われていた方法です。そもそもflexBox?となっていた私からすると異常にハードルが高く、「右寄せ・左寄せ」という概念からすると全く「直感的にわからない」というのが問題です。そもそも、私と同じくflexBox?となった方は【備忘録】Flexboxを知り、未だにfloatを使っていたことを恥じる男などを参考にしてください。
私のプロジェクトの実際のコードは以下のようなものでした。
<div class="parent-box flex-box">
<div class="child-box align-left">
<div>左寄せ領域</div>
<button class="btn">ボタンA</button>
<button class="btn">ボタンB</button>
</div>
<div class="child-box align-right">
<div>右寄せ領域</div>
<button class="btn">ボタンC</button>
</div>
</div>
.flex-box {
display: flex;
}
.flex-box .align-left {
flex: 1 0 auto;
}
.flex-box .align-right {
flex: 0 1 auto;
}
■画面
ポイントはflex-boxの子要素である Flex アイテム用のプロパティである。「flex-grow」「flex-shrink」「flex-basis」を以下 1 行で表現し、左寄せ右寄せを実現している所になります。こうすることで、上記画面からもわかるようにalign-leftクラスのdivタグが使えるだけ領域を占領し、残りの領域をalign-rightクラスのdivタグが使うようになります。
※margin や padding と同じく flex は以下のようにスペース区切りで記載することで grow,shrink,flex の順で定義することができます。
flex: 1 0 auto;
flex-grow, flex-shrink, flex-flexそれぞれは以下を表します。
flex プロパティ | .align-left | .align-right | |
---|---|---|---|
flex-grow | Flex アイテムの横幅の比率 | 1 | 0 |
flex-shrink | Flex アイテムが縮小されるときにどういう比率で縮小されるか | 0 | 1 |
flex-basis | Flex アイテムの幅を直接指定 | auto | auto |
このとき、flex-growにおいてalign-leftは1でalign-rightは0なので、可能な限りalign-leftは領域を使おうとします。flex-shrinkでalign-leftは0なので縮小されませんがalign-rightは1のため縮小されます。
そのため、左寄せ右寄せが実現できるようになります。
そうです。なぜ左寄せ右寄せをするだけのために「比率」だの「縮小率」だの考えなければならないのか・・・
結果的に左寄せ右寄せになっているだけであって直感的ではない。それが私の感じた事でした。そのためこの方法も最強の css にはなりません。
3. FlexBox の justify-content: space-between をつかう
これが、僕が考える最強の左寄せ右寄せ CSS です。
恐ろしいことに、スタイルの指定はたったの 2 つのプロパティを指定すれば完了になります。(ほら最強でしょう笑)
<div class="parent-box flex-box-between">
<div class="child-box">
<div>左寄せ領域</div>
<button class="btn">ボタンA</button>
<button class="btn">ボタンB</button>
</div>
<div class="child-box">
<div>右寄せ領域</div>
<button class="btn">ボタンC</button>
</div>
</div>
.flex-box-between {
display: flex;
justify-content: space-between;
}
これの解説は簡単です。justify-contentのspace-betweenがそういう仕様だからです。
そもそもspace-betweenは1つ目と1番後ろのFlexアイテムは両端、残りは等間隔に配置するという仕様です。
そのため、Flexアイテムが2つの場合は勝手に左寄せ右寄せになります。
欠点
最強かに思える本スタイルにも欠点があります。
それは「html 上で左寄せ右寄せしていることを表現できていない」ということです。
space-between が優秀過ぎて「align-left」「align-right」のクラスが必要ではないため、html を見ただけでは左寄せ右寄せになっている div タグがどれなのか判断つきません。
class にマーカクラスとして「align-left」「align-right」を追加しておくことで一応の回避はできますが少し悩ましい所ではあります。
また、当然ですが「justify-content: space-between」を知らないメンバーが保守をした場合、おそらく子要素のdivタグを最初に確認し、なぜ左寄せ右寄せになっているのかと相当な時間をかけた後、親要素のdivタグに設定しているスタイルを見なければわからず、誰でも簡単にわからない実装になっている可能性があります。この点は他の方法であれば子要素のスタイルを参照すればなんとなくわかるので比較的メンバスキルに依存しない実装にはなるかと思います。
総括
ブロック要素を1行に左寄せおよび右寄せに配置したい場合はjustify-content: space-betweenを使うことでかなり良い感じに記述できるが、メンバーのレベルやコード規約に準じて実装方法は検討する必要がある。