【CSS】Excelにおける「ウィンドウ枠の固定」をCSSのみ(主にflex)で実現したい

感情的プログラミング伝記(通称エモプロ)は、襲いかかるバグとの戦いの日々や新しい技術に対する感動。こんなに便利な関数作っちゃって誰かに自慢したいなどのような、プログラミングという論理的作業の中にある人間としての無垢な感情を徒然に書き記すものであります。

さて第1回は掲題の通り「ウィンドウ枠の固定」をCSSで実現してやりますよ!
flex大好き人間の私が今まで使ったことのなかったflex-shrinkの使い道を皆様にお伝えしたいと思います。

WEB上でガントチャート作りたいなと思った時以外の需要があるとは到底思えませんが何かに使えたらなと思っております!

「ウィンドウ枠の固定」とは?

エクセル(Numbers)で「ガントチャート的な」列を固定した表

上図のように「ガントチャート的な」と書かれた列が固定され、その右の日付が書かれた列がスクロールされていくようなやつのことです。
これをhtmlとcssでやってみようという試みです。

横幅を固定すれば難しいことはない

固定する側とスクロールする側の横幅を何ピクセル!って固定しちゃえばぶっちゃけめちゃくちゃ簡単です。

<style>
  .flex {
    display: flex; /* 横並び */
  }
  .left {
    width: 300px; /* 固定する側 */
    border: 1px solid #555;
  }
  .right {
    width: 600px; /* スクロール側 */
    overflow: scroll; /* 600pxからはみ出たらスクロール */
    white-space: nowrap; /* 改行しない */
    border: 1px solid #555;
  }
</style>
<div class="flex">
  <div class="left">
    宮沢賢治『ポラーノの広場』より
  </div>
  <div class="right">
    あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
  </div>
</div>

左と右の領域をそれぞれ300px、600pxにしました。
無事右側がスクロールされたのでめでたしめでたし・・・なわけありません!
実戦に投入する際に両領域のサイズを指定できることなんて滅多にないと思います。

次は固定したい方のみサイズ指定してみる

<style>
  .flex {
    display: flex; /* 横並び */
  }
  .left {
    width: 300px; /* 固定する側 */
    border: 1px solid #555;
  }
  .right {
    width: 600px; /* スクロール側 */
    overflow: scroll; /* 600pxからはみ出たらスクロール */
    white-space: nowrap; /* 改行しない */
    border: 1px solid #555;
  }
</style>
<div class="flex">
  <div class="left">
    宮沢賢治『ポラーノの広場』より
  </div>
  <div class="right">
    あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
  </div>
</div>

右側のwidth: 600pxを消して、flex-grow: 1;を入れました。
さっきよりは画面幅に対して柔軟になったかなと。
ただ左側が300px固定のはずなのにちょっと右側に潰されているのが気に食わない!

もし左側が完全に300px固定であればmin-width: 300px; max-width: 300px;を入れればクリアできます。
でも左側が完全に300px固定であるとは到底思えないのです。

では最後に私が行き着いたどんな場所にもフィットする素晴らしい「ウィンドウ枠の固定」をお見せします。

これがマジで使える「ウィンドウ枠の固定」CSSだ!

<style>
  .flex {
    display: flex; /* 横並び */
  }
  .flex > div {
    border: 1px solid #555;
    padding: 16px;
  }

  .left {
    /* width: 300px; */ /* 固定する側 */
    flex-shrink: 0;
  }
  .right {
    /* width: 600px; */ /* スクロール側 */
    flex-grow: 1; /* 右側は画面幅ギリまで使う */
    overflow: scroll; /* 600pxからはみ出たらスクロール */
    white-space: nowrap; /* 改行しない */
  }
</style>
<div class="flex">
  <div class="left">
    宮沢賢治『ポラーノの広場』より
  </div>
  <div class="right">
    あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
  </div>
</div>

左側のwidth:300px;による固定をやめてflex-shrink: 0;を追加しました。
flex-shrink

CSS の flex-shrink プロパティは、フレックスアイテムの縮小係数を設定します。フレックスアイテムの寸法がフレックスコンテナーよりも大きい場合、アイテムは flex-shrink の数値に従って縮小して収まります。

mozilla https://developer.mozilla.org/ja/docs/Web/CSS/flex-shrink

ということで、この値が大きいほど縮みやすいって感じです。
ちなみに初期値は1(これ重要)です。
左側ではそれを0にしました。つまり左側は縮まないということになります。
おかげで画面が小さくなっても右側だけが縮んでくれます。

そして何よりお伝えしたいのは、300pxとか600pxなどの固定値を使用せず、コピペで使いまわせるということですね!

左右の領域にそれぞれtableを入れてセルの高さだけを統一してあげると、まるでエクセルのような表も作れちゃいますよ!

ということで。今回はここまで!それじゃまた来週!