こなさんみんばんわ。
2 月 2 日に公開した記事の締めのところで今回のサンプルには当初の主目的からすると完全に欠けてる部分
があるとして、auto-fill
と auto-fit
の切り替え機能が実装されてないことに言及しておりましたが、本日さっそくその機能を追加しましたので、前回同様にその作業内容をまとめてみました。有言実行してえら〜い!(cv: コウペンちゃん)
あと、その際に中途半端にしか説明をしてなかった 2 つのキーワードの挙動の違いにつきましても、この機能追加したサンプルでのスクリーンショットを交えつつ説明をしております。えっもちろん実際に見ながらの方が理解しやすいかなーと思ってあえてそうしたんですよ、当たり前やないですか🤪
その前に、なぜこの機能を付けてなかったか
それは単純に、キーワード部分はカスタム・プロパティで置き換えることができないのでは? という認識不足からですね。つまり、次のように書いても通らないだろうと思ってたんですよ。
:root {
--repeat-mode: auto-fill;
}
ul {
grid-template-columns: repeat(var(--repeat-mode), minmax(var(--grid-min-size, 100px), 1fr));
}
で、そうなると直接 grid-template-columns
の部分の宣言そのものを書き換えないといけない訳で、それは書くことが長すぎてめんd…大変だよなぁと思って、とりあえず後回しにしておりました。
ですが、先日の記事を書いてる途中でふと試してみると、カスタム・プロパティに置き換えても普通に通ることが確認できてなーんや! となりましたので、それだったら付けてみようということになった訳です。
機能追加…の前に、モバイル・ファーストっぽく書き換えておく
それではさっそく実装していきましょう! なのですが、その前に前回までのコードを若干変更しまして、モバイル・ファーストというか、狭い画面のスタイルを基準に、広い画面の場合にスタイルを上書きするようにしておきます。あと、そうなるとあえて Range 書式を使う意味もなくなるので、メディアクエリーの書き方も旧来のものに戻しておきます。これで意図した表示が適用されるブラウザが少し増えるかと思います。
修正したところ抜粋。順に CSS, HTML, JavaScript。
:root {
/*
--small-image-size をベースに、幅 640px 以上で
--large-image-size が適用されるように変更
*/
--grid-min-size: var(--small-image-size);
@media (min-width: 640px) {
--grid-min-size: var(--large-image-size);
}
}
<form>
<label>画像の最小幅:
<!-- デフォルトの変更に合わせて value を 50 に、max を 120 に -->
<input type="range" min="20" max="120" value="50" id="slider">
</label>
<!-- 変更した value に合わせて 50px に -->
<output id="monitor">50px</output>
</form>
// 幅 640px 以上の画面では max を 240 に
if (window.matchMedia("(min-width: 640px)").matches) {
slider.max = 240;
}
切り替え用のチェックボックスを付ける
今回は簡単にチェックボックス 1 つで対応しようと思います。デフォルトは auto-fill
で、チェックが入った状態では auto-fit
になるようにしてみます。
ということで、まずは切り替え用のチェックボックスを追加します。あとでスクリプトからチェックするのはもう分かりきってることなので、最初から id
属性も振っておきましょう。
<form>
<!-- 省略 -->
<output id="monitor">50px</output><br>
<!-- 以下を追加 -->
<label><input id="mode-switch" type="checkbox"> <code>auto-fit</code> に変更する</label>
</form>
auto-fill
キーワードをカスタム・プロパティに置き換える
次に --repeat-mode
というカスタム・プロパティを定義して、デフォルトを auto-fill
にします。
:root {
/* これ以外は変更がないので省略 */
--repeat-mode: auto-fill;
}
そして grid-template-column
のところをこのカスタム・プロパティを使って書き換えます。
ul {
/* これ以外は変更がないので省略 */
grid-template-columns: repeat(var(--repeat-mode, auto-fill), minmax(var(--grid-min-size, 100px), 1fr));
}
あっちなみにプロパティ値の方もフォールバック値の方も、どちらも "auto-fill"
って引用符で括っちゃダメですよ。括ると文字列にされてしまって repeat()
関数内で使える有効なキーワードじゃなくなっちゃいますからね。気をつけましょう!(そんな勘違いをされる方はおられないかと思いますが、念のために書いておきました)
切り替えコードを実装して、完成
あとは JavaScript ですね。こんな感じでいかがでしょう。
// 前準備の最後に追加
const modeSwitch = document.getElementById("mode-switch");
// 初期化処理の最後に追加
// Firefox が再読み込みで状態をリセットしてくれないのを Fix
modeSwitch.checked = false;
// スライダーメイン処理の後ろに追加
// チェックボックスの状態によって auto-fill / auto-fit を切り替える
//(チェックあり → auto-fit・なし → auto-fill)
modeSwitch.addEventListener("input", (e) =>{
thumbnails.style.setProperty("--repeat-mode",
e.target.checked ? "auto-fit" : "auto-fill"
);
});
単純にチェックボックスにイベントが発生したらその状態を調べて、チェックが入っていればカスタム・プロパティの値を auto-fit
に、外れていれば auto-fill
にと、三項演算子で出力してるだけですね。
という訳で、完成したものがこちらです。あっちなみに今回のサンプルも別タブで開くようにしております。
さわって理解する auto-fill
と auto-fit
の挙動の違い
それでは、サンプルを色々な端末で、チェックボックスにチェックを入れたり外したりしながら、スライダーを動かして遊んでみましょう。さて、どうなるでしょう?
アイテムが複数行に渡る場合 → 違いはない
まず画像が複数行に渡って並んでる場合ですが、この場合はチェックボックスにチェックを入れても、特に何も変化はないですよね。これは別に書いたコードがバグってる訳ではなくて😅 この段階ではそれが正常なんです。
アイテムが一行に収まる場合 → 違いが発生
では、この状態からそれぞれスライダーをめいっぱい左に寄せて、画像の幅を最小の 20px
に近づけていってみてください。あっスマホでやられる場合は縦向きだと最小にしても複数行のままなんで、端末を横向きにして試さないとたぶん「えっ何が違うん?」ってなります。涙
どうですか? チェックを外した状態 (auto-fill
) では画像はどんどん小さくなっていきますが、チェックを入れた状態 (auto-fit
) では、ある一定のところまでいくと画像がそれ以上小さくならないですよね? どうやらこれが auto-fill
と auto-fit
の違いのように思えます。
2 つの違いは余ったスペースの埋め方…ではない
つまり auto-fill
と auto-fit
の違いとは、指定のグリッド幅ですべてのアイテムを並べてもコンテナ幅を埋め尽くせない場合に、auto-fill
は余ったスペースに新しいグリッドを追加できるだけ追加して埋める、auto-fit
は余ったスペースを既存のアイテムを拡大することで埋める…といいたいところですが、これは正確ではありません。
実はどちらの場合も、空のグリッドを追加してるのは一緒なんです。試しに開発者ツールでグリッド・オーバーレイを表示してみると、auto-fill
であろうが auto-fit
であろうが、最後のグリッド線の番号は一緒であることが分かるかと思います。
ではどこに違いがあるかというと、auto-fill
で追加された空のグリッドは空でないグリッドと同じ幅を持ちますが、auto-fit
で追加された空のグリッドは折りたたまれる…つまり幅はゼロになり、間の溝 (gap
) もないものとして扱われます。違いは実はそれだけなのです。
えっじゃあ auto-fit
の時に幅が一定以上小さくならないのはなぜかって? それは単に minmax()
関数の最大値に 1fr
って入れてるからですね🤣 自分でそう指定したから、空のグリッドが折りたたまれてできたスペースを使ってるってだけの話なのです。信じられないなら開発者ツールなどで 1fr
の代わりに 30px
とかの固定値を入れてみるといいですよ、普通にスペースが空きますから。
そんな訳で
本日は、前回の記事で作成したスライダーで拡大縮小できる画像一覧に、本来の主目的であった auto-fill
と auto-fit
の挙動の違いを確認するための機能として、この 2 つをチェックボックスで切り替えられる機能を実装した作業のまとめと、完成したものを使って作成したスクリーンショットを交えて、2 つのキーワードの挙動の違いを解説してみました。
まぁ正直僕も最初は「違いは余ったスペースの埋め方なんだな」みたいな雑な認識をしてたんですよ。実際にスライダー動かしながらグリッド・オーバーレイの変化を眺めててあれっ? てなって、あらためて学び直してみたような感じですので、あんまり偉そうにはできんのでした。涙
という訳で、こんな解説でご理解いただけましたでしょうか? 上手く伝わったかどうかちょっと心配ですが、お役に立てましたら幸いです。