Appleの商品ページに使用されているスクロールに合わせて動画を再生するエフェクトを実装するスクリプト -Scrolleo
Post on:2019年11月15日
Appleの新商品は商品自体にワクワクするだけでなく、商品の見せ方・ページのデザインに注目する人も多いと思います。
11/13に発表された16インチ MacBook Proの商品ページに使用されているようなスクロールに合わせて動画を再生するスクリプトを紹介します。
「こういうページにしてよ!」という時用にチェックしておきたいですね。
LyftでモーショングラフィックスやWebサイトからUIアニメーションなどを手がけているMark Teater氏が開発中のスクリプトで、Appleで最近よく使用されているスクロールに合わせて動画を再生するエフェクトを再現するためのシンプルなプラグインです。実際の動作は、下記ページで楽しめます。
100pxのスクロールで、動画を6秒のみ再生します。
See the Pen
Scrolleo by Mark Teater (@markteater)
on CodePen.
HTML
動画コンテンツを配置します。
1 2 3 4 5 6 7 |
<div style="margin-top: 100vh"> <h3>Video 1 (Only plays 6 seconds of video with 100px delay</h3> <!-- Video 1 --> <video id="scrolleo-1" width="100%" height="100%" autobuffer="autobuffer" preload="preload"> <source src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.mp4"> </video> </div> |
JavaScript
requestAnimationFrameを使用し、複数のカスタムスクロールビデオを簡単に作成できます。
JavaScriptは、MITライセンスで利用できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
/* Scrolleo - make your video scroll with inertia * MIT License - by Mark Teater */ (function(window, document, undefined) { "use strict"; var _Scrolleo = function(opts) { // Defaults this.acceleration = 0.08; //1 is fastest, 0 is slowest, 0.08 is default this.secondsPerScreen = null; //Set this to the length of the video. "1" is 1 second. this.additionalOffset = 0; //Add or subtract pixels to when the video will start. "10" means that the video will start 10px earlier. this.wrapperEl = null; // Override defaults if (opts) { for (var opt in opts) { this[opt] = opts[opt]; } } }; var targetScrollPos; _Scrolleo.prototype = { init: function() { var self = this; this.wrapper = document.querySelectorAll(this.wrapperEl); // get the location of the top of the page targetScrollPos = window.pageYOffset; Array.prototype.forEach.call(this.wrapper, function(wr) { // Set the pixelsPerSecond to the full duration of the video if nothing was set in the options if (self.secondsPerScreen === null) { self.wrapper[0].addEventListener("loadedmetadata", function() { self.secondsPerScreen = self.wrapper[0].duration; //recalculate values on video with new pixelsPerSecond self.distanceToTop = getElemDistanceToTop(elem); self.offsetFromTop = getOffsetFromTop(self.distanceToTop); self.pixelsPerSecond = getPixelsPerSecond(); }); } self.pixelsPerSecond = null; self.scrollPos = null; self.currentTime = null; self.offsetFromTop = null; self.distanceToTop = null; // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel (function() { var lastTime = 0; var vendors = ["ms", "moz", "webkit", "o"]; for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"]; window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] || window[vendors[x] + "CancelRequestAnimationFrame"]; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; })(); // requestAnim shim layer by Paul Irish window.requestAnimFrame = (function() { return ( window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function */ callback, /* DOMElement */ element) { window.setTimeout(callback, 1000 / 60); } ); })(); // Define functions to be used by Scrolleo var getElemDistanceToTop = function(elem) { //http://gomakethings.com/get-distances-to-the-top-of-the-document-with-native-javascript/ var location = 0; if (elem.offsetParent) { do { location += elem.offsetTop; elem = elem.offsetParent; } while (elem); } return location >= 0 ? location : 0; }, getOffsetFromTop = function(distanceToTop) { var offset = distanceToTop - window.innerHeight + self.additionalOffset; return offset >= 0 ? offset : 0; }, getPixelsPerSecond = function() { var pixelsPerSecond = (window.innerHeight + self.wrapper[0].clientHeight) / self.secondsPerScreen; return pixelsPerSecond >= 0 ? pixelsPerSecond : 0; }, scrollHandler = function() { targetScrollPos = window.pageYOffset; }, resizeHandler = function() { //recalculate values on resize self.distanceToTop = getElemDistanceToTop(elem); self.offsetFromTop = getOffsetFromTop(self.distanceToTop); self.pixelsPerSecond = getPixelsPerSecond(); }, scrollControl = function() { //what to do when scrolling self.scrollPos += (targetScrollPos - self.offsetFromTop - self.scrollPos) * self.acceleration; self.currentTime = self.scrollPos / self.pixelsPerSecond; //convert scrollPos from pixels to seconds to set self.currentTime self.wrapper[0].currentTime = self.currentTime; self.wrapper[0].pause(); }; // Get an element's distance from the top of the page var elem = self.wrapper[0]; // Calulate the initial size, distance, and offset of each scrolleo video self.distanceToTop = getElemDistanceToTop(elem); self.offsetFromTop = getOffsetFromTop(self.distanceToTop); self.pixelsPerSecond = getPixelsPerSecond(); self.scrollPos = targetScrollPos - self.offsetFromTop; wr.pause(); // Use requestAnimationFrame to ensure the video is updating when the browser is ready window.requestAnimFrame(function render() { window.requestAnimFrame(render); // Only kickoff scrollControl if the scrollPos of element hasn't reached targetScrollPos if (Math.round(self.scrollPos + self.offsetFromTop) != targetScrollPos) { scrollControl(); } }); window.addEventListener("scroll", scrollHandler, false); window.addEventListener("resize", resizeHandler, false); }); } }; window.Scrolleo = _Scrolleo; })(window, document); // Setup video 1 var scrolleo1 = new Scrolleo({ acceleration: 0.08, // 1 = instant, 0 = never secondsPerScreen: 6, // Defaults to video duration additionalOffset: 100, // Positive starts the video later, negative starts earlier. default starts when top of video hits bottom of the screen wrapperEl: "#scrolleo-1" // id of the video you want to control }); scrolleo1.init(); // Setup Video 2 var scrolleo2 = new Scrolleo({ wrapperEl: "#scrolleo-2" }); scrolleo2.init(); |
下記をベースにした、とのことです。
sponsors