8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NEAdvent Calendar 2023

Day 5

スクロール要素の端を徐々に透過させて続きがある感を演出する

Last updated at Posted at 2023-12-04

概要

スクロール要素の端を徐々に透過させるように見せることで、スクロールできる=続きがある感を演出してみました。
CSSにて線形グラデーションでの透過は困難なので、白色グラデーション要素をマスクして上下に霧がかかったように効果をつけることで、透過されているように見せています。
スクロールし切った状態ではこの効果は不要のため、スクロール状態に応じて動的にこの効果を切り替えるようにしました。

実演

See the Pen 上下の霧かけ by itanium (@itanium-R) on CodePen.

つくった経緯

MacにてChromeでWebページを閲覧すると、デフォルトでスクロールバーが非表示であり、スクロールしようとしない限り表示されません。
ブラウザのデフォルト挙動を尊重しつつ続きがある感じを演出するため、よく[続きを見る]を押下させるページにて採用されている白色グラデーションの帯を擬似要素で被せる方式を採用しました。

実装

HTML

<div class="wrap">
  <div class="fog-added">
    ここに要素の中身を詰め込む。
  </div>
</div>

CSS

div.wrap {
  display: block;
  position: relative;
}

div.fog-added {
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

div.fog-added::before {
  content: "";
  width: 100%;
  height: 0px;
  display: block;
  background: linear-gradient(#fff, rgba(255, 255, 255, 0));
  position: absolute;
  top: 0;
  left: 0;
}

div.fog-added::after {
  content: "";
  width: 100%;
  height: 0px;
  display: block;
  background: linear-gradient(rgba(255, 255, 255, 0), #fff);
  position: absolute;
  bottom: 0;
  left: 0;
}

JavaScript

const fogHeight = 50;

/**
 * @param {string} querySelector
 * @returns {CSSStyleRule?}
 */
function getCSSRule(querySelector) {
  for (const sht of document.styleSheets) {
    for (const c of sht.cssRules) {
      if (c.selectorText === querySelector) return c;
    }
  }
}

/**
 * @param {Element} target
 */
function addFog(target) {
  const remainingScrollHeight =
    target.scrollHeight - target.offsetHeight - target.scrollTop;
  const topFogHeight = Math.min(
    target.scrollTop,
    target.offsetHeight / 2,
    fogHeight
  );
  const buttomFogHeight = Math.min(
    remainingScrollHeight,
    target.offsetHeight / 2,
    fogHeight
  );
  getCSSRule("div.fog-added::before").style.height = `${topFogHeight}px`;
  getCSSRule("div.fog-added::after").style.height = `${buttomFogHeight}px`;
}

const fogAddedElm = document.querySelector("div.fog-added");
fogAddedElm.addEventListener("scroll", (e) => addFog(e.target));
addFog(fogAddedElm);

ポイント

  • 擬似要素 (before, after) の style は JS で Element から直接操作できません。
    • document.styleSheets から CSSStyleRule を取得し操作することで回避できました。
  • 霧がかかったような効果をつける範囲は、以下の条件を満たすように決定されるようにしています。
    • スクロールし切る端に近づけば近づくほど短くし、端では0pxとする
    • 当該要素の外にはみ出さない
    • 標準の大きさを超えない
  • CSSの background#fff は配置場所の背景色にあわせることで背景と透過するように演出できます。

考慮事項

  • div.fog-added::before, div.fog-added::after が2回定義されるとうまく動きません。 JSの getCSSRule() を書き換えれば動くようにできますが、簡単のためこの仕様にしています。
  • 今回 add-fog を class 指定していますが、このコードでは当該 class が1要素のときのみしか考慮していません。複数使いたい時は追加で手を加える必要があります。

おわりに

続きがある感じをどうやって表現すればいいかをデザイナーの方と考えた結果、この表現方法ができました。
デザイナーさんには日々感謝感謝です。
チームのメンバーで知恵を絞りあって、より伝わりやすい表現・UI・UXを考えていきたいですね。

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?