1.実現したいデザイン
Grid でレイアウトしていて、困ったことに直面した。それは次のような場面だった。
・上下に複数のボックス(BOX1、BOX2、BOX3とする)が並び、それらの全体を包含する親ボックス(container)がある。
・container と BOX2 はそれぞれ別々の事情で可変高、連動しない。BOX1 と BOX3 は高さ固定。
・BOX2 について、その中に収容するデータを下揃えで表示したい。データの量と BOX2 の高さは連動しない。
・BOX2 の中のデータ行数が少なくて余裕がある場合は、BOX1 との間にスペースが空く。
・BOX2 の中のデータ行数が増えて、満杯になると、下端の行からオーバーフロー非表示の処理を行う。その際、行の下半分が非表示といった乱れを避けるため、行単位でオーバーフロー処理を行いたい。
図にしてみると次のようになる。ここで、BOX2 は薄赤色に着色している。また、BOX2 の中に収容するテキストデータは緑色のボックスで表現している。また content-box で表現しているので border の幅 1px も考慮して見る必要がある。
■CSS主要部分■
#container {
height: 280px;
display: grid;
grid-template-rows: 50px 1fr 50px;
grid-template-columns: 1fr;
}
#box2 {
grid-row: 2/3;grid-column:1/2;
align-self: end;
}
#box4 {
}
図-1 データが少ない場合
図-1 はデータ量が 4 行と少ない場合で、BOX1 との間に隙間ができている状態。
2.直面した問題点
オーバーフロー処理が重要なテーマなので、データ量を増やしてみる。図-2 はデータ量を 10 行にした場合。Grid の定義による BOX2 の高さは、
・BOX2 の height = 280 - 50 - 50 = 180
BOX1 と BOX3 の height がそれぞれ 50px なので、border の上下で 2px 引いて、BOX2 の height は CSS の表現では 178px になる。しかし、データは、leine-height:20px で、10 行で計 200px と、BOX2 に収容しきれなくなる。つまり 20px 分溢れてしまう。この 20px がどのように表現されるかは図-2 で確認できる。
■CSS主要部分■
#container {
height: 280px;
display: grid;
grid-template-rows: 50px 1fr 50px;
grid-template-columns: 1fr;
}
#box2 {
grid-row: 2/3;grid-column:1/2;
align-self: end;
}
#box4 {
}
図-2 データが 10 行になった場合
図-2 では BOX2 の height が子要素の合計 height をそのまま継承し、container の height をオーバーして BOX3 を下方にずらしている。container の grid-template-rows 定義 1fr が無視された状態で、不可解としか言いようがない。これが Grid の仕様なのだろうか?
ちなみに、BOX2 の align-self:end を外したり、grid-template-rows の指定を相対指定にすると状況が変わるが主旨から外れるので、ここでは言及しない。(この稿の末尾に掲載する PDF で確認できる。)
次に BOX2 に overflow:hidden を加えたらどうなるか、図-3 をご覧いただきたい。
■CSS主要部分■
#container {
height: 270px;
display: grid;
grid-template-rows: 50px 1fr 50px;
grid-template-columns: 1fr;
}
#box2 {
grid-row: 2/3;grid-column:1/2;
align-self: end;
overflow: hidden;
}
#box4 {
}
図-3 BOX2 に overflow:hidden を加えた場合
container の height の中には納まったものの、BOX2 が拡大した分が BOX1 に被さっている。"container をはみ出せないなら上側の要素に重ねて配置する"ということか。これもどうにも理解できない結果だ。BOX2 が拡大した量は、200-(270-50-50)=30px となる。
3.解決策
色々と考えた結果、BOX2 の height の管理に問題があるのではと思い、BOX2 に対して動的に height 値を設定することとした。図-3 の場合だと 168px(content-box のため CSS 設定値は border の 2px 分差し引く)となる。結果は図-4 。
■CSS主要部分■
#container {
height: 270px;
display: grid;
grid-template-rows: 50px 1fr 50px;
grid-template-columns: 1fr;
}
#box2 {
grid-row: 2/3;grid-column:1/2;
align-self: end;
height: 168px;
overflow: hidden;
}
#box4 {
}
図-4 BOX2 に height を動的に設定
これで最初の目的が達成された。図-1と図-4の違いは、
・図-4では、BOX2 に height を動的に設定
・図-4 では、overflow:hidden を指定
このうち、overflow:hidden は図-1 に指定しておいても害はないので、あらかじめ固定的に CSS に書き加えておいて、BOX2 の height を動的に設定することでこの問題は解決できることが分かった。
最後に、オーバーフロー処理を行単位にする件については、動的に設定する height 値をデータの line-height 値の倍数に整正することで対応した。
■CSS主要部分■
#container {
height: 270px;
display: grid;
grid-template-rows: 50px 1fr 50px;
grid-template-columns: 1fr;
}
#box2 {
grid-row: 2/3;grid-column:1/2;
align-self: end;
height: 160px;
overflow: hidden;
}
#box4 {
}
図-4 BOX2 の height 設定を行高単位に整正
4.動的な設定の処理方法
BOX2 の height の設定をどのような条件の時に行うかについては、次の前提条件がある。
・レスポンシブ環境の中で container の height は独自の事情で変化する。
・BOX2 の中のデータ量も扱う個別のページの事情によって変化する。
・レスポンシブはターゲットを定めた @media による CSS 切り替え方式ではなく、どの様なデバイスであってもシームレスに対応したい。
上記の条件を満たす方法として、次の手順を考えた。
・container の height から逆算して BOX2 の取り得る最大の height 値を算出する。
・BOX2 の height 値を取得する。
両者を比較して、BOX2 の height 値の方が大きい、すなわちオーバーフローする条件の場合に、container の height 値から算出した値を BOx2 の height 値として設定する。
最後に、上の説明では省略した HTML/CSS の詳細や、Grid の定義を相対値で指定した場合などについて試行した結果を PDF にまとめたので、参考までに掲載することとしたい。
Grid の 1fr と overflow(PDF 別画面で開きます)