WebDesign Dackel

jQueryとCSSのclipプロパティを活用して、ここまで白ここから黒、みたいな表現を作る

jQueryとCSSのclipプロパティを活用して、ここまで白ここから黒、みたいな表現

Hatena0
Google+0
Pocket0
Feedly0

はじめに

いきなりですが、タイトルが若干意味不明ですね。良いタイトルが思いつきませんでした。
やりたいことは単純で、下の画像みたいな感じなことです。

動作イメージ

実はこのブログの画面右上のメニューボタンにも試験的に実装しています。
ヘッダーよりも下にスクロールすると、アイコンが紺色に変わるようになっています。
アイコンがヘッダの部分と同じ白のままだと、コンテンツ部分に入った時に可視性が下がってしまうため取り入れてみました。

これはCSSclipプロパティと、jQueryを使えば簡単に実現できるので、似たような事がやりたかったんだー!という方の参考になればと思います。

デモ

実際に動かせるようにデモページを用意しましたので、ぜひパソコンから見てみてください。(スマホから見ると動きが微妙な感じです…)

デモページ

動作の仕組み

PhotoShopなどで使えるクリッピングマスクをイメージしてもらえると分かりやすいと思います。
色を変えたい要素、デモページで言うとBoxとなっている矩形を2つ用意して同じ座標で重ねておきます。
そしたら、ある境界線を元に上に被せた要素を切り抜くという仕組みです。

今回は「切り抜く」という部分にCSSで用意されているclipプロパティを使っています。

clipとは?

ボックスを切り抜くためのプロパティです。こんな感じで指定出来ます。

clip: rect(上, 右, 下, 左);

rectで指定した領域が切り抜かれた状態で表示されます。
ただ、ちょっとクセがあってposition:absoluteになっている要素にしか適用されないみたいです。

詳しくは下記のサイトが参考になりました。

サンプルコード

デモページで使っているコードは下記のような感じです。

HTML

<div class="box">
  <div class="box__item box__item--black" id="js-scroll-mask">Box</div>
  <div class="box__item box__item--white">Box</div>
</div>

<div class="container container--white">
  <h1>jQueryとCSS clipの活用サンプル</h1>
  <h2>白の領域</h2>
</div>

<div class="container container--black" id="js-scroll-divider">
  <h2>黒の領域</h2>
</div>

JS側でスクロールに応じてdiv#js-scroll-maskclipを操作していきます。
境界線にはdiv#js-scroll-dividerを使います。

CSS

.box {
  position:fixed;
  top:50%;
  right:100px;
  z-index:100;
  width:200px;
  height:200px;
  margin-top:-100px;
  line-height:200px;
  font-size:40px;
  font-weight:bold;
}

.box__item {
  position:absolute;
  width:100%;
  height:100%;
  text-align:center;
}

.box__item--black {
  z-index:2;
  clip:rect(0, 200px, 200px, 0);
  color:#fff;
  background:#111;
}

.box__item--white {
  z-index:1;
  color:#111;
  background:#fff;
}

.container {
  padding:20em 2em;
}

.container--white {
  background:#fff;
}

.container--black {
  background:#000;
  color:#fff;
}

黒と白の重なり順がポイントです。

JavaScript

$(function(){

  var $mask = $("#js-scroll-mask"),
      $divider = $("#js-scroll-divider"),
      maskSize = {
        width: $mask.outerWidth(),
        height: $mask.outerHeight()
      };

  // スクロールに応じて境界線を調整する
  $(window).on("scroll", function(){

    // 境界線と、マスク本体の座標を取得する
    var dividerOffset = $divider.offset(),
        maskOffset = $mask.offset();

    // clipプロパティに適用するサイズを求める
    var clip = {
      right: maskSize.width,
      bottom: maskSize.height - ( ( maskOffset.top + maskSize.height ) - dividerOffset.top )
    };

    // clipのrect:bottomをマスクのサイズ内に収める
    clip.bottom = clip.bottom <= 0 ? 0 : clip.bottom;
    clip.bottom = clip.bottom >= maskSize.height ? maskSize.height : clip.bottom;

    // clipプロパティへ適用する
    $mask.css("clip", "rect(0, " + clip.right + "px, " + clip.bottom + "px, 0)");

  }).trigger("scroll");

});

まとめ

以上、かなりざっくりと書いてしまったので不明なところやこうした方がいいよ!というところがあればお気軽にコメント頂ければと思います。

あと、デモでは単純に矩形を使っていますが、テキスト要素でやってみても面白いなぁと思いました。