overflow でスクロールバーを表示させると padding-right・padding-bottom が効かなくなる事象と対策

overflow: autooverflow: scroll でスクロールバーを表示させると、padding-rightpadding-bottom の指定が効かなくなり、ボックスの右端や下端にテキストがくっついて見える不具合があった。

手元の環境で試したところ、Chrome はこのような動きにはならず、Firefox や IE で発生するようだった。

当該事象が確認できるデモページを作成したので、以下で確認してほしい。

不具合が起こるコードは、以下のような感じ。

/* 
 * HTML 側は以下のような構成。
 *   <pre class="normal">長いテキスト…</pre>
 */
.normal {
  width: 100%;
  height: 5rem;
  overflow: scroll;  /* 幅・高さを適当に指定し、スクロールするようにしておく */
  border: 1px solid #ccc;
  padding: 1rem;  /* 四隅に余白を付けたいが… */
  background: #f0f0f0;
}

直感的にこういう作りにすると思うのだが、これだと padding-rightpadding-bottom0 扱いになってしまう。

そこで、スクロールさせたい要素にラッパー要素を作り、ラッパー要素の ::after 擬似要素で padding-bottom を、内部のスクロールさせたい要素の ::after 擬似要素で padding-right を実現するようにしてみる。

HTML は以下のようになる。

<div class="fixed">
  <pre>長いテキスト…</pre>
</div>

CSS は次のようにする。

/* 修正版 : 基本デザインはラッパー側で行う */
div.fixed {
  width: 100%;
  height: 5rem;
  overflow: scroll;
  border: 1px solid #ccc;
  padding: 1rem 0 0 1rem;  /* 余計なバッティングを避けるため、右と下は余白を付けないでおく */
  background: #f0f0f0;
}

/* padding-bottom 代わりの要素を作る */
div.fixed::after {
  content: "";
  display: block;
  width: 1px;
  height: 1rem;  /* padding-bottom にしたい値 */
}

/* 中の pre 要素は inline-block にしておき、末尾に自身の ::after 擬似要素が配置できるようにしておく */
div.fixed > pre {
  display: inline-block;
}

/* padding-right 代わりの要素を作る */
div.fixed > pre::after {
  content: "";
  display: inline-block;
  width: 1rem;  /* padding-right にしたい値 */
  height: 1px;
}

イメージ的には、2つの ::after 擬似要素が突っ張り棒になって、スクロール領域の右と下に余白を作り出してる、という感じ。

デモページでは、「擬似要素表示切替」ボタンを押すと ::after 擬似要素に背景色を付けられるので、擬似要素がどのように作用しているのか確認できるだろう。

たかだかスクロールさせたいだけの要素にラッパー要素が必要になるのは、いささか冗長な気はするが、どうしてもスクロールする領域の右端と下端に余白を作りたい場合は、こういった手段も使えるだろう。