隙間に線を引くcolumn-rule/row-rule 最終回 線の見え方を作り込むrule-visibility-itemsとrule-inset
最終回は、空いている領域に線を出さない指定、線の端の調整、隙間ごとに違う線を引く方法を解説します。
前回までのおさらい
前回は、CSS GridやFlexboxでのcolumn-ruleとrow-ruleを解説しました。
- 折り返すリストの区切り線は、
column-ruleなら行の先頭と末尾に線が残らない - 機能検出には
column-ruleではなくrow-ruleを使う - 交点での線の切れ方は
rule-breakで決まり、初期値のnormalはコンテナーの種類で挙動が変わる
最終回の今回は、線の見え方を作り込むプロパティを見ていきましょう。
空いている領域に線を出さない:rule-visibility-items
auto-fillのカード一覧のように列数が画面幅で変わるレイアウトでは、アイテム数によって最終行に空きが出ます。デモで見てみましょう。
アイテム数を7にすると、3列表示なら最終行に2つぶんの空きができ、初期状態ではそこにも縦線が伸びています。これを制御するのがrule-visibility-itemsです。
最終行の空きに線を出さない
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
gap: 2rem;
rule: 1px solid #c00;
rule-visibility-items: around;
}
このデモはrule-breakを初期値のnormalのままにしています。前回の表のとおりCSS Gridのnormalは十字の交点を貫通するので、縦線は行をまたいだ1本の連続した線になります。ですので、値の違いは「最終行の空きにその線をどこまで伸ばすか」という形で現れます。
all:隣にアイテムがあるかに関係なく描く。CSS Gridでは初期値のnormalも同じ挙動で、最終行の空いている領域まで縦線が伸びるaround:隣接する2つの領域のうち少なくとも片方にアイテムがあれば描く。空セル同士のあいだの線は消えるbetween:両方にアイテムがあるときだけ描く。最終行の空きに面した線は消える
カード一覧ならaroundかbetweenが自然でしょう。
なお、このプロパティが適用されるのはCSS GridとMulti-columnだけで、Flexboxでは無視されます。前回のタグリストはFlexboxでしたが、そちらでは使えないのです。
線の端を調整する:rule-inset
線を出す場所を決めたら、次は線の長さです。隙間いっぱいに引かず、少し内側で止めたい場面もあります。
線の端には2種類あります。コンテナーの外周側にある端をcap、ほかの線と出会う交点側の端をjunctionと呼びます。
外周側だけ縮めて交点はつなげる
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 3rem;
rule: 2px solid #c00;
rule-break: intersection;
rule-inset: 8px / overlap-join;
}
rule-insetは/の前がcap、後ろがjunctionです。rule-inset-cap / rule-inset-junctionで別々に書くこともできます。値は正なら端が内側に縮み、負なら外側に伸びます。
ここでrule-break: intersectionを指定しているのには意味があります。CSS Gridのnormalでは十字の交点を線が貫通してしまい、そこに端が存在しません。rule-break: intersectionで交点ごとに線を切ることで、はじめてjunction側の端が生まれるわけです。なお、第2回の表のとおりnormalはT字の交点では線を開始・終了するので、T字の交点にはもともとjunction側の端があります。
デモで表現すると次のようになります。
junctionに指定しているoverlap-joinが、格子をきれいに見せるための値です。交点で出会う線同士が接合するところまで端を伸ばし、cap側では0として扱われるので外周にはみ出しません。上のコードは「内部の格子はつながり、外周には8pxの余白がある」という定番の形です。デモで表現すると次のようになります。
なお、パーセンテージの基準は交差する側の隙間の幅です。コンテナーの辺では交差する隙間の幅が0と定義されるため、-50%でも辺では0に解決され、外にはみ出しません。
overlap-joinは仕様にあとから追加された新しい値で、筆者の環境のChrome 151では動作を確認できました。
交点でどちらの線が上になるか
縦線と横線が重なる交点でどちらを上に描くかはrule-overlapで決まります。値はrow-over-columnとcolumn-over-rowで、初期値はrow-over-columnです。
隙間ごとに違う線を引く
ここまではすべての隙間に同じ線を引いてきましたが、罫線を引くUIでは「ここだけ太く」という要求がよく出てきます。
時間割風のUIで、時刻列との境目だけ太い線にし、行方向は実線と破線を交互にしています。
隙間ごとに違う線を指定する
.schedule {
display: grid;
grid-template-columns: 4rem repeat(5, 1fr);
gap: .75rem;
/* 1本目だけ太く、残りは細く */
column-rule-width: 3px, repeat(auto, 1px);
column-rule-style: solid;
column-rule-color: #333, repeat(auto, #bbb);
/* 行方向は実線と破線を交互に */
row-rule-width: 1px;
row-rule-style: repeat(auto, solid, dashed);
row-rule-color: #bbb;
}
これらのプロパティは、カンマ区切りのリストを受け取ります。3px, repeat(auto, 1px)なら1本目の隙間だけが3pxです。
repeat(auto, ...)は、リストのほかの部分で値が割り当てられなかった隙間を埋める書き方です。隙間が何本になるかわからなくても、「最初だけ特別扱いして残りは同じ」と書けるわけです。
複数の値を渡せば、実線と破線が交互に繰り返されます。アイテム側にクラスを振らずに交互パターンを作れるのは、borderにはできなかったことです。
なお、線の色や太さ、rule-insetはアニメーションできる値として定義されています。ホバーしたときだけ線の色を変える、といった動きも付けられます。
先ほどの時間割にtransitionを足したものです。時間割にマウスカーソルを乗せるか、チェックボックスを切り替えると、線の太さと色が変化します。
線の変化をアニメーションさせる
.schedule {
transition: column-rule-width .4s, column-rule-color .4s;
}
線にグラデーションや画像は使えるか
borderにはborder-imageがあるので、線にもグラデーションや画像を使いたくなるかもしれません。しかしcolumn-ruleやrow-ruleの色に指定できるのは<color>だけで、border-imageにあたるプロパティはありません。
とはいえ<color>ですから、color-mix()やoklch()といった色の書き方はそのまま使えます。上のリスト値と組み合わせて隙間ごとに色を変えれば、少しずつ色が変わっていくような見せ方も作れます。
どうしてもグラデーションの線が必要なら、隙間に線を引くのをあきらめて、コンテナーの背景で代用する手があります。gapを線の太さぶんだけ空け、コンテナーの背景にグラデーションを敷きます。アイテム側に不透明な背景を置くと、隙間からグラデーションが覗いて線のように見えます。
コンテナーの背景をグラデーションの線に見せる
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2px;
background: linear-gradient(135deg, #c00, #06c);
}
.grid > * {
background: #fff;
}
ただしこの方法では、線の太さがgapの値そのものになり、太い隙間に細い線を引くことはできません。縦横の一方だけに線を引くこともできないので、細い格子状の罫線に限られます。
なお、画像を指定できるようにする提案自体はCSSWGに出ています(csswg-drafts #5080)。今後の仕様の広がりに期待したいところです。
使いどころを見極める
ここまで見てきたように便利な場面は多い一方で、適用しないほうがよい場面もあります。使わないほうがよいケースを整理してみましょう。
| ケース | 理由と代替 |
|---|---|
| 線をアイテムの端に付けたい | 必ず隙間の中央に描かれ、横にずらせない。borderを使う |
gap: 0のレイアウト |
線を描く場所がない。borderを使う |
| 折り返さない単純な1本線 | border-leftで足りる |
| 線にグラデーションや画像を使いたい | 色に指定できるのは<color>だけ。コンテナーの背景で代用する |
判断の目安は、そのレイアウトで折り返しが起きるかどうかです。flex-wrapやauto-fillで行数や列数が変わるならCSS Gap Decorationsにしかできない仕事があり、固定レイアウトの1本線ならborderのほうが素直です。
まとめ
3回にわたって、CSS Gap Decorationsを解説しました。第1回は段組みのcolumn-ruleを題材に、線が隙間の中央に描かれてレイアウト上の幅を取らないというborderとの違いを押さえ、第2回はCSS GridとFlexboxでの区切り線と機能検出の落とし穴を見ました。今回は、線を出す場所と端、隙間ごとの見た目を作り込みました。
Chromiumベースのブラウザ以外では未対応である以上、当面は@supportsとフォールバックが前提です。ですが、区切り線のためにアイテム側のセレクターと格闘してきたことを思うと、「隙間に線を引く」という発想が標準になったのは筆者としてはうれしいものです。