このページの本文へ

バラバラの画像がぴったり揃う美しいパララックス

2014年12月18日 11時00分更新

大工原実里 / Stronghold

  • この記事をはてなブックマークに追加
本文印刷

今回の注目サイト:
Benoit Challand

http://www.benoitchalland.com/

 デジタルアーティスト「Benoit Challand」のポートフォリオサイト。

パララックスを利用したサムネイル一覧表示

 シンプルなポートフォリオサイトに、ページ遷移やメニュー表示などのスムーズなエフェクトによって新鮮さを加えているBenoit Challand

 トップページの作品一覧では、長さの異なる3カラムのリストを配置。それぞれのカラムのスクロールスピードを変え、ありがちなサムネイル一覧を奥行きのあるユニークなページに演出している。しかも、スクロールが止まるタイミングはどのカラムも同じ。ページの最下部で表示がぴったりそろう、美しいパララックス効果だ。

 今回はこのサイトを参考に、jQueryとCSS3を使って長さの異なるカラムを整えるパララックススクロールを作成する。

STEP 1:パララックスの構造を考える

 カラムによってスクロール速度を変えるため、ブラウザーのスクロール機能は使わず、ダミーのスクロール値をもとにしてjQueryで要素を移動させる、疑似的なスクロールを作成する。

 3つのカラムを包む要素(wrapper)をposition: fixed; で固定して、その中にある各カラムをtranslateで移動させる。このままだと、wrapperを固定しているのでマウススクロールができず、スクロール量も取得できないので、wrapperを包む要素(cols)を作る。colsには基準となる高さを指定することでマウススクロールを有効にし、scrollTopを取得する。

STEP 2:HTMLとCSSの準備

 STEP 1で考えた構造に沿って、HTMLとCSSを用意しよう。デモでは縦にサムネイルを10個ほど並べたカラムを3つ用意する。動きを再現する前に、高さを指定した空のボックスを並べてみる。中央のカラムだけ高さが短くなるよう、boxのサイズを小さくしておく。

■ソースコード(HTML)

<div class="cols">
  <div class="wrapper">
    <ul class="col left">
      <li class="box"><span>1</span></li>
...
      <li class="box"><span>10</span></li>
    </ul>
    <ul class="col center">
      <li class="box"><span>1</span></li>
...
      <li class="box"><span>10</span></li>
    </ul>
    <ul class="col right">
      <li class="box"><span>1</span></li>
... 
      <li class="box"><span>10</span></li>
    </ul>
  </div>
</div>

■ソースコード(CSS)

.cols {white-space: nowrapposition: relative;}
.cols .wrapper {padding: 0 20pxbox-sizing: border-boxposition: fixedtop: 0left: 50%transform: translate(-50%, 0)width: 100%max-width: 900px}
.cols .col {position: relativedisplay: inline-blockvertical-align: topwidth: 34%;}
.cols .col .left {margin: 0 3% 0 0;}
.cols .col .right {margin: 0 0 0 3%;}
.cols .col .center {margin: 0 3% 0 3%width: 20%;}
.cols .col li {margin: 80px 0;}
.box {height: 280pxwidth: 100%background: #E84A59font-size: 50pxcolor: #eeetext-align: centerdisplay: table;}
.box span {display: table-cellvertical-align: middle;}
.center .box {height: 200pxfont-size: 40px;}

DEMO > http://zxcvbnmnbvcxz.com/demonstration/as/010/1.html
(普通に並べた状態)

DEMO > http://zxcvbnmnbvcxz.com/demonstration/as/010/2.html
(position: fixed; を指定して準備完了)

STEP 3:スクロールエリアを用意して基準となる値を取得する

 全体を包む.colsにダミーの高さを設定し、スクロール可能にすることで、疑似スクロールで動かすためのスクロール量を取得する。

 今回は左カラムを基準にして中央カラムのスクロールスピードを変化させたいので、左カラムの高さをjQueryで取得して.colsに設定する。

 以下のデモでは取得したscrollTopの値をページ左下に表示している。コンテンツはまだ動かないが、スクロール量に応じて数値が変化するのを確認できるはずだ。

■ソースコード(HTML)

<!-- 確認用に追記 -- >
<div id="data">
  <div class="y">scrollTop:<span>0</span></div>
</div>

■ソースコード(JavaScript)

$(function(){
  cols = $('.cols');
  colLeft = $('.col.left');
  colLeft_y = 0;

  // コンテンツの高さを取得、セット
  colLeft_h = colLeft.height();
  cols.height(colLeft_h);
  
  // スクロール量を取得
  y = 0;
  $(document).on('scroll'function(){
    y = $(window).scrollTop();
    $('.y span').text(y); // scrollTop() を表示(確認用)

  });
});

STEP 4:カラムを移動させる

 setIntervalを設定し、5ミリ秒ごとにスクロール量に応じてカラムの位置をtranslateで移動させる。まずはすべてのカラムをスクロール値と同量だけ移動させてみよう。

 これで見かけ上、通常のスクロールと同じように動くようになった。

■ソースコード(HTML)

<!-- 確認用に追記 -- >
<div id="data">
  <div class="y">scrollTop:<span>0</span></div>
  <div class="l">カラムの位置 transform:translateY(-<span>0</span>px)</div>
</div>

■ソースコード(JavaScript)

$(function(){
  cols = $('.cols');
  colLeft = $('.col.left');
  colLeft_y = 0;
  colRight = $('.col.right'); // 右カラム
  colCenter = $('.col.center'); // 中央カラム

  wh = $(window).height();

  // コンテンツの高さを取得、セット
  colLeft_h = colLeft.height();
  cols.height(colLeft_h);

  // スクロール量を取得
  y = 0;
  $(document).on('scroll'function(){
    y = $(window).scrollTop();
    $('.y span').text(y);
  });

  setInterval(function(){
    // カラムの位置を更新
    colLeft_y += (y - colLeft_y); // 移動後の位置 = スクロール量 - 移動前の位置
    colLeft.css({'transform':'translateY(-' + colLeft_y + 'px)'});
    colRight.css({'transform':'translateY(-' + colLeft_y + 'px)'});
    colCenter.css({'transform':'translateY(-' + colLeft_y + 'px)'});

    // translateYの値を表示(確認用)
    $('.l span').text(colLeft_y);

  },5); // 5msごとにカラムのtranslateYを更新
});

中央カラムのスクロール量を調整

 次に、中央カラムのスクロール量を調整して、左右のカラムと同時にスクロールが終わるようにする。

 中央カラムの移動可能範囲と左カラムの移動可能範囲の比率(ratio)を求め、スクロール量にratioを乗算した量を指定することで実現できる。

■ソースコード(HTML)

<!-- 確認用に追記 -- >
<div id="data">
  <div class="y">scrollTop:<span>0</span></div>
  <div class="l">カラムの位置 transform:translateY(-<span>0</span>px)</div>
  <div class="c">中央カラム transform:translateY(-<span>0</span>px)</div>
</div>

■ソースコード(JavaScript)

$(function(){

  cols = $('.cols');
  colLeft = $('.col.left');
  colLeft_y = 0;
  colCenter = $('.col.center');
  colCenter_y = 0; // 中央カラムの移動量
  colRight = $('.col.right');

  wh = $(window).height();

  // コンテンツの高さを取得、セット
  colLeft_h = colLeft.height();
  colCenter_h = colCenter.height(); // 中央カラムの高さを取得
  cols.height(colLeft_h);

  //左カラムと中央カラムの比率を取得
  colLeft_scrollH = colLeft_h;
  ratio = (colCenter_h) / colLeft_scrollH;

  // スクロール量を取得
  y = 0;
  $(document).on('scroll'function(){
    y = $(window).scrollTop();
    $('.y span').text(y);
  });

  setInterval(function(){
    // 左カラムと中央カラムの移動範囲(高さから画面の高さを引いた範囲)の比率を求める
    var colLeft_scrollH = colLeft_h - wh;
    var ratio = (colCenter_h - wh) / colLeft_scrollH;

    // 中央カラム:移動量 = スクロール量 * 左列との比率
    colCenter_y += (y * ratio - colCenter_y);
    if (colCenter_y < 0.1) { //(colLeft_yが0.1より小さくになったら0にしておく)
      colCenter_y = 0;
    }
    colCenter.css({'transform':'translateY(-' + colCenter_y + 'px)'});

    // 左右カラム:移動量 = スクロール量
    colLeft_y += (y - colLeft_y);
    if (colLeft_y < 0.1) { //(colLeft_yが0.1より小さくになったら0にしておく)
      colLeft_y = 0;
    }
    colLeft.css({'transform':'translateY(-' + colLeft_y + 'px)'});
    colRight.css({'transform':'translateY(-' + colLeft_y + 'px)'});

    // translateYの値を表示(確認用)
    $('.l span').text(colLeft_y);
    $('.c span').text(colCenter_y);

  },5);
});

STEP 5:滑らかなスクロールを再現する

 STEP 4で基本的なしくみはできたが、スクロールの動きがまだぎこちない。参考サイトのように滑らかに動くように改善しよう。デモではsetIntervalで5ミリ秒ごとに描写しているため、移動させる値を細かく指定することで滑らかに動くようになる。デモではcolCenter_yとcolLeft_yの値に0.2を掛けた値を指定している。

■ソースコード(JavaScript)

ease = .2;

colCenter_y += (y * ratio - colCenter_y) * ease;
colLeft_y += (y - colLeft_y) * ease;

STEP 6:画像を入れる(imageloaded)

 STEP 5で作成したデモは、カラムの高さに応じて移動量を調整するため、画像サイズがまちまちの場合、画像の読み込みが完了していないと正しく動作しない。

 どんなサイズの画像が並んでも柔軟に対応できるよう、 imagesLoaded プラグインを使って画像の読み込みの完了を待ってから実行するようにする。

■ソースコード(HTML)

<div class="cols">
    <div class="wrapper">
        <ul class="col left">
            <li class="box"><img src="img/img1.jpg" alt=""></li>
...
            <li class="box"><img src="img/img5.jpg" alt=""></li>
        </ul>
        <ul class="col center">
            <li class="box"><img src="img/img1.jpg" alt=""></li>
...
            <li class="box"><img src="img/img5.jpg" alt=""></li>
        </ul>
        <ul class="col right">
            <li class="box"><img src="img/img1.jpg" alt=""></li>
...
            <li class="box"><img src="img/img5.jpg" alt=""></li>
        </ul>
    </div>
</div>

■ソースコード(CSS)

.box {height: auto;}
.center .box {height: auto;}
.box img {width: 100%height: autovertical-align: bottom;}

■ソースコード(JavaScript)

imagesLoaded('.cols'function(){
    // この中にコードを入れる
});

 以上でデモは完成だ。

パララックスを特定のエリアだけで実行する

 実際にサイトに組み込む際には、パララックスの上下にヘッダーやフッターなどの何かしらコンテンツを配置することもあるだろう。少し手を加えて、パララックスの起点と終点を設定して使いやすくしてみよう。

■ソースコード(JavaScript)

$(function(){

  cols = $('.cols');
  colLeft = $('.col.left');
  colLeft_y = 0;
  colCenter = $('.col.center');
  colCenter_y = 0;
  colRight = $('.col.right');

  wh = $(window).height();

  // パララックスするコンテンツは画面の下にスタンバイさせておく
  $('.cols .wrapper').css({'top': wh});

  // 画像の読み込みが完了したら実行
  imagesLoaded('.cols'function(){

    // 画像ロード完了
    $('.loading').fadeOut(600);

    // コンテンツの高さを取得、セット
    colLeft_h = colLeft.height();
    colCenter_h = colCenter.height();
    cols.height(colLeft_h);

    // 左カラムと中央カラムの比率を取得
    // この場合は 移動範囲 = カラムの高さ となるので -wh を削除
    colLeft_scrollH = colLeft_h;
    ratio = (colCenter_h) / colLeft_scrollH;

    // スクロール量を取得
    y = 0;
    $(document).on('scroll'function(){
    y = $(window).scrollTop();
    });

    ease = .2;

    setInterval(function(){

      // パララックス開始位置
      start = cols.offset().top;
      // スクロール量からパララックス開始位置を引いた値を基準とする
      new_y = y - start + wh;

      if( y > start - wh ){ 
        // パララックス開始位置が画面に入ったら実行
        if( colLeft_y < colLeft_h ){
          colCenter_y += (new_y * ratio - colCenter_y) * ease;
          colLeft_y += (new_y - colLeft_y) * ease;
        }else{
          // パララックスエリアが終わったらスクロールスピードを変更
          colCenter_y += (new_y - colLeft_y) * ease;
          colLeft_y += (new_y - colLeft_y) * ease;
        }
      }else{
        colCenter_y = 0;
        colLeft_y = 0;
      }

      colCenter.css({'transform':'translateY(-' + colCenter_y + 'px)'});
      colLeft.css({'transform':'translateY(-' + colLeft_y + 'px)'});
      colRight.css({'transform':'translateY(-' + colLeft_y + 'px)'});

    },5);
  });
});

DEMO > http://zxcvbnmnbvcxz.com/demonstration/as/010/8.html

著者:大工原実里(だいくはら・みさと)

著者写真

1989年生まれ。株式会社レターズのデザイナー。2014年からWebデザイナーとして働き始める。Webに関する活動拠点「Stronghold」というサイトでブログを書いたり、デザインの実験をしている。

Web Professionalトップへ

この連載の記事

一覧へ
Web Professionalトップページバナー

この記事の編集者は以下の記事をオススメしています

ASCII.jp会員サービス 週刊Web Professional登録

Webディレクター江口明日香が行く