├── img └── bg │ └── stationblue.jpg ├── README.md ├── css └── style.css ├── LICENSE ├── index.html └── js ├── ahrelax.min.js └── ahrelax.js /img/bg/stationblue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conorluddy/ahRelax/HEAD/img/bg/stationblue.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ahrelax 2 | ======= 3 | 4 | Experimental lightweight JS/jQuery script to facilitate quick scroll based animations. Way out of date - wouldn't recommend using for anything! 5 | 6 | Currently less than 1kb minified, but will probably need to grow to be useful. 7 | 8 | Tried to make use of some of the tips in here, without making it as complicated: 9 | https://medium.com/@dhg/parallax-done-right-82ced812e61c 10 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | 2 | html, body, div, span, applet, object, iframe, 3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 4 | a, abbr, acronym, address, big, cite, code, 5 | del, dfn, em, img, ins, kbd, q, s, samp, 6 | small, strike, strong, sub, sup, tt, var, 7 | b, u, i, center, 8 | dl, dt, dd, ol, ul, li, 9 | fieldset, form, label, legend, 10 | table, caption, tbody, tfoot, thead, tr, th, td, 11 | article, aside, canvas, details, embed, 12 | figure, figcaption, footer, header, hgroup, 13 | menu, nav, output, ruby, section, summary, 14 | time, mark, audio, video { 15 | margin: 0; 16 | padding: 0; 17 | border: 0; 18 | font: inherit; 19 | font-size: 100%; 20 | vertical-align: baseline; 21 | } 22 | 23 | html, body{ 24 | height: 100%; 25 | } 26 | 27 | .row { 28 | width: 100%; 29 | height: 66%; 30 | position: relative; 31 | display: block; 32 | } 33 | 34 | #move-me{ 35 | background: url("../img/bg/stationblue.jpg") no-repeat scroll 0 0 transparent; 36 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Conor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | AhRelax - Parallax facilitator 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 | -------------------------------------------------------------------------------- /js/ahrelax.min.js: -------------------------------------------------------------------------------- 1 | define(["jquery"],function(e){var b=0,g=0,i=0,c=0,h=((g-b)/2)+b,f=0,a=e(window),d=e("body"),k=[{wrap:"#piece-station",target:null,rate:-0.3,tweak:0,effect:"bgSlideVertical"}],j={bgSlideVertical:function(m,n){var l=(n*m.rate).toFixed(2); 2 | l-=m.rate<0?m.height-m.tweak:0;e(m.wrap).css("background-position","0 "+l+"px");},elementSlideVertical:function(m,n){var l=(n*m.rate).toFixed(2);l-=m.rate<0?m.height-m.tweak:0; 3 | e(m.wrap).css("transform","translate3d(0,"+l+"px,0");}};setup=function(){var m;i=a.height();c=a.width();b=a.scrollTop();g=a.scrollTop()+i;for(var l=k.length-1; 4 | l>=0;l--){m=e(k[l].wrap);k[l].starts=m.offset().top;k[l].ends=m.offset().top+m.height();k[l].height=m.height();k[l].lasts=m.height()/i;}};posUpdate=function(){window.requestAnimationFrame(function(){setVpTop(); 5 | animatePieces();});};setVpTop=function(){b=a.scrollTop();g=a.scrollTop()+i;};calcVisibilty=function(o){var n=e(o.wrap),s=o.starts,l=o.ends,p=sb;if(p){n.addClass("inView"); 6 | }else{n.removeClass("inView");return p;}var m=((g-b)/2)+b,q=((l-s)/2)+s,r=1-((m-q)/i*-1)<1?(1-((m-q)/i*-1)).toFixed(2):1;progressOut=1-((m-q)/i*-1)>1?(((m-q)/i*-1)*-1).toFixed(2):0; 7 | o.progressIn=r;o.progressOut=progressOut;o.midpoint=q;if(r>0.5){n.addClass("mostInView");n.addClass("beenInView");}else{n.removeClass("mostInView");}return p; 8 | };animatePieces=function(){for(var m=k.length-1;m>=0;m--){var n=e(k[m].wrap),p=false,q=k[m].starts,l=k[m].ends,o;p=calcVisibilty(k[m]);if(p){o=q-g;switch(k[m].effect){case"bgSlideVertical":j.bgSlideVertical(k[m],o); 9 | break;case"opacity":j.opacity(k[m]);break;}}}};init=function(){setup();a.resize(setup);f=setInterval(posUpdate,10);};}); -------------------------------------------------------------------------------- /js/ahrelax.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Each & Other website, 2015 [www.eachandother.com] 3 | * Author: Conor Luddy 4 | * 5 | * 6 | * --------- 7 | * 8 | * 9 | * Attach this to a front end module by giving its root 10 | * element the attribute: data-js-module="" 11 | */ 12 | 13 | (function(window, document, EachAnd, $, Modernizr, undefined) { 14 | 'use strict'; 15 | 16 | EachAnd.util.ahhrelax = function() { 17 | 18 | var 19 | //Viewport 20 | vpTop = 0, 21 | vpBottom = 0, 22 | vpHeight = 0, 23 | vpWidth = 0, 24 | vpMidpoint = ((vpBottom - vpTop) / 2) + vpTop, 25 | //Setup fills this with individual objects we can animate 26 | initialisedPieces = [], 27 | //Other 28 | scrollInterval = 0, 29 | $window = $(window), 30 | $body = $('body'); 31 | 32 | /* 33 | * These are the classes that get applied to each 'piece' 34 | */ 35 | var viewClass = { 36 | //Applies to all pieces 37 | pieceToBeUsed: 'js-ar-piece', 38 | //Has never been in the viewport 39 | notYetBeenInView: 'js-ar-unSeen', 40 | //Has been in the viewport but may or may not still be 41 | hasBeenInView: 'js-ar-beenInView', 42 | //Is somewhere in view 43 | currentlyInView: 'js-ar-inView', 44 | //Is more than 50% of the way into the centre (based on midpoints - may need more accurate implementation) 45 | mostlyInView: 'js-ar-mostInView', 46 | //Is more than 50% of the way past the centre (based on midpoints - may need more accurate implementation) 47 | mostlyPastView: 'js-ar-mostlyPastView' 48 | }; 49 | 50 | /* 51 | * Targeted pieces or elements 52 | * New effects can be defined for use here 53 | * 54 | * Pieces potentially get the following properties: 55 | * wrap 56 | * rate 57 | * tweak 58 | * effect 59 | * starts 60 | * ends 61 | * lasts 62 | * height 63 | * progressIn - 0-1, maxes out at 1 when the piece is actually taking up some vp space 64 | * progressOut 65 | * midpoint 66 | */ 67 | var piece = [{ 68 | wrap: '.m-statement', 69 | effect: 'fadeOutOnExit', 70 | rate: 2 71 | }]; 72 | 73 | // , { 74 | // //Just apply the classes used for visibility and don't do any parallaxy stuff 75 | // // wrap: '.row-about', 76 | // // effect: 'fadeOutOnExit', 77 | // // rate: 2 78 | // }, { 79 | // //Just apply the classes used for visibility and don't do any parallaxy stuff 80 | // // wrap: '.row-clients' 81 | // }], 82 | 83 | 84 | 85 | 86 | /* 87 | * Effects for assigning to our animatable pieces 88 | * 89 | * Define whatever you can think of. There's plenty of data to use. 90 | */ 91 | var effect = { 92 | 93 | bgSlideVertical: function(piece, relativeTop) { 94 | var newvalue = (relativeTop * piece.rate).toFixed(2); 95 | //If the rate is negative, background position should be 96 | //shifted up so that it can move down without leaving a gap. 97 | newvalue = piece.rate < 0 ? piece.height - piece.tweak : 0; 98 | $(piece.wrap).css('background-position', '0 ' + newvalue + 'px'); 99 | }, 100 | 101 | elementSlideVertical: function(piece, relativeTop) { 102 | // var newvalue = ( relativeTop * piece.rate ).toFixed( 2 ); 103 | // newvalue -= piece.rate < 0 ? piece.height - piece.tweak : 0; 104 | // $( piece.wrap ).css( 'transform', 'translate3d(0,' + newvalue + 'px,0' ); 105 | }, 106 | 107 | fadeOutOnExit: function(piece) { 108 | var rate = typeof(piece.rate) === 'undefined' ? 1 : piece.rate; 109 | piece.element.css('opacity', (1 - piece.progressOut * rate).toFixed(2)); 110 | }, 111 | 112 | // fadeInOnApproach: function(piece) { 113 | // var rate = typeof(piece.rate) === 'undefined' ? 1 : piece.rate; 114 | // piece.element.css('opacity', (0 + piece.progressIn * rate).toFixed(2)); 115 | // }, 116 | 117 | debuggy: function(piece) { 118 | console.log(piece); 119 | } 120 | 121 | }; 122 | 123 | 124 | 125 | 126 | 127 | 128 | /* 129 | * Calculate some dimensions 130 | */ 131 | function setup() { 132 | 133 | var 134 | $pw, 135 | thisPiece = {}; 136 | 137 | vpHeight = $window.height(); 138 | vpWidth = $window.width(); 139 | vpTop = $window.scrollTop(); 140 | vpBottom = $window.scrollTop() + vpHeight; 141 | 142 | //Calculate the start and end points 143 | for (var i = piece.length - 1; i >= 0; i--) { 144 | //Piece could be a jQuery collection of elemeents, not jst one... 145 | $pw = $(piece[i].wrap); 146 | 147 | for (var j = 0; j < $pw.length; j++) { 148 | 149 | thisPiece = {}; 150 | 151 | $.extend( thisPiece, piece[i] ); 152 | 153 | thisPiece.element = $pw.eq(j); 154 | //Start of active section 155 | thisPiece.starts = $pw.eq(j).offset().top; 156 | //End of active section 157 | thisPiece.ends = thisPiece.starts + $pw.eq(j).height(); 158 | //Save this so it doesn't need to calculate it every 10ms 159 | thisPiece.height = $pw.eq(j).height(); 160 | //Ratio of section height to viewport height... has to be useful for something... 161 | thisPiece.lasts = $pw.eq(j).height() / vpHeight; 162 | 163 | initialisedPieces.push(thisPiece); 164 | 165 | thisPiece.element.addClass(viewClass.notYetBeenInView); 166 | 167 | } 168 | } 169 | } 170 | 171 | 172 | 173 | 174 | 175 | /* 176 | * Animate 177 | */ 178 | function posUpdate() { 179 | window.requestAnimationFrame(function() { 180 | setVpTop(); 181 | animatePieces(); 182 | }); 183 | } 184 | 185 | 186 | 187 | function setVpTop() { 188 | // Viewport top 189 | vpTop = $window.scrollTop(); 190 | // Viewport bottom 191 | vpBottom = $window.scrollTop() + vpHeight; 192 | } 193 | 194 | 195 | 196 | function manageVisibilty(piece) { 197 | 198 | var 199 | $piece = piece.element, 200 | pieceTop = piece.starts, 201 | pieceBot = piece.ends, 202 | vpMidpoint, 203 | pieceMidpoint, 204 | progressIn, 205 | progressOut, 206 | inview = pieceTop < vpBottom && pieceBot > vpTop; 207 | 208 | if (inview) { 209 | $piece.addClass(viewClass.currentlyInView); 210 | $piece.addClass(viewClass.hasBeenInView); 211 | // 212 | $piece.removeClass(viewClass.notYetBeenInView); 213 | } else { 214 | $piece.removeClass(viewClass.currentlyInView); 215 | return inview; 216 | } 217 | 218 | //Midpoint of viewport in relation to page 219 | vpMidpoint = ((vpBottom - vpTop) / 2) + vpTop; 220 | 221 | //Midpoint of targeted piece in relation to page 222 | pieceMidpoint = piece.midpoint = ((pieceBot - pieceTop) / 2) + pieceTop; 223 | 224 | //0% when it just comes into vp, 100% when midpoints match 225 | progressIn = piece.progressIn = 1 - ((vpMidpoint - pieceMidpoint) / vpHeight * -1) < 1 ? (1 - ((vpMidpoint - pieceMidpoint) / vpHeight * -1)).toFixed(2) : 1; 226 | 227 | //0% when when midpoints match, 100% when it exits vp 228 | progressOut = piece.progressOut = 1 - ((vpMidpoint - pieceMidpoint) / vpHeight * -1) > 1 ? (((vpMidpoint - pieceMidpoint) / vpHeight * -1) * -1).toFixed(2) : 0; 229 | 230 | //Add, change and remove these as you see fit: 231 | 232 | //As piece is scrolled towards centre 233 | if (progressIn > 0.5) $piece.addClass(viewClass.mostlyInView); 234 | else $piece.removeClass(viewClass.mostlyInView); 235 | 236 | //As piece is scrolled beyond centre 237 | if (progressOut > 0.5) $piece.addClass(viewClass.mostlyPastView); 238 | else $piece.removeClass(viewClass.mostlyPastView); 239 | 240 | return inview; 241 | } 242 | 243 | 244 | 245 | 246 | 247 | /** 248 | * animatePieces 249 | */ 250 | function animatePieces() { 251 | 252 | for (var i = initialisedPieces.length - 1; i >= 0; i--) { 253 | 254 | var 255 | inview = false, 256 | pieceTop = initialisedPieces[i].starts, 257 | pieceBot = initialisedPieces[i].ends, 258 | relativeTop; 259 | 260 | inview = manageVisibilty( initialisedPieces[i] ); 261 | 262 | // element is in view if it's top is less than vp bottom, and its bottom is greater than vp top 263 | if ( inview ) { 264 | relativeTop = pieceTop - vpBottom; 265 | 266 | if( typeof( initialisedPieces[i].effect ) !== 'undefined' ) { 267 | switch ( initialisedPieces[i].effect ){ 268 | 269 | case 'bgSlideVertical': 270 | effect.bgSlideVertical( initialisedPieces[i], relativeTop ); 271 | break; 272 | 273 | case 'elementSlideVertical': 274 | effect.elementSlideVertical( initialisedPieces[i], relativeTop ); 275 | break; 276 | 277 | case 'fadeOutOnExit': 278 | effect.fadeOutOnExit( initialisedPieces[i] ); 279 | break; 280 | 281 | //Easy way to explore data we can play with. 282 | //You can set inverval to 30sec or something 283 | //down below if you want time to read the output. 284 | case 'debuggy': 285 | effect.debuggy( initialisedPieces[i] ); 286 | break; 287 | } 288 | 289 | } 290 | 291 | } 292 | 293 | } 294 | 295 | } 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | /* 306 | * Initialise page 307 | */ 308 | function init() { 309 | //Save necessary widths, heights, and other important factors 310 | setup(); 311 | 312 | //Update them on window resize 313 | $window.resize(setup); 314 | 315 | //Update the page every x 316 | scrollInterval = setInterval(posUpdate, 50); 317 | } 318 | 319 | 320 | return init(); 321 | }; 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | //Move elsewhere 330 | EachAnd.util.ahhrelax(); 331 | 332 | 333 | 334 | 335 | 336 | 337 | })(this.window, this.document, this.EachAnd, jQuery, Modernizr); 338 | --------------------------------------------------------------------------------