├── demo ├── css │ └── styles.css ├── img │ ├── cat-1.png │ └── cat-2.png ├── index.html └── video │ ├── index.html │ └── overscroll.mp4 ├── overscroll.js ├── overscroll.min.js └── readme.md /demo/css/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Overscroll.js 3 | * 4 | * MIT licensed 5 | * Copyright (C) 2013 Tim Holman, http://tholman.com 6 | */ 7 | 8 | html { 9 | height: 100%; 10 | } 11 | 12 | body { 13 | height: 200%; 14 | margin: 0px; 15 | } 16 | 17 | .easter-egg { 18 | margin-left: -481px; 19 | position: fixed; 20 | height: 500px; 21 | z-index: 2; 22 | left: 50%; 23 | } 24 | 25 | .top-cat { 26 | top: -500px; 27 | } 28 | 29 | .bottom-cat { 30 | bottom: -500px; 31 | } 32 | 33 | .notice { 34 | margin-left: -6px; 35 | position: fixed; 36 | width: 0px; 37 | left: 50%; 38 | } 39 | 40 | .notice.top { 41 | -webkit-animation: float-up 1s infinite alternate; 42 | -moz-animation: float-up 1s infinite alternate; 43 | -ms-animation: float-up 1s infinite alternate; 44 | animation: float-up 1s infinite alternate; 45 | border-right: 6px solid transparent; 46 | border-top: 10px solid transparent; 47 | border-left: 6px solid transparent; 48 | border-bottom: 10px solid #222; 49 | top: 5px; 50 | } 51 | 52 | .notice.bottom { 53 | -webkit-animation: float-down 1s infinite alternate; 54 | -moz-animation: float-down 1s infinite alternate; 55 | -ms-animation: float-down 1s infinite alternate; 56 | animation: float-down 1s infinite alternate; 57 | border-bottom: 10px solid transparent; 58 | border-right: 6px solid transparent; 59 | border-left: 6px solid transparent; 60 | border-top: 10px solid #222; 61 | bottom: 5px; 62 | } 63 | 64 | .overscroll { 65 | font-family: 'Montserrat', sans-serif; 66 | -webkit-transform: translateY(-50%); 67 | -moz-transform: translateY(-50%); 68 | -ms-transform: translateY(-50%); 69 | transform: translateY(-50%); 70 | padding-bottom: 30px; 71 | text-align: center; 72 | position: fixed; 73 | margin: 0px; 74 | width: 100%; 75 | color: #222; 76 | z-index: 1; 77 | top: 50%; 78 | } 79 | 80 | .overscroll h1 { 81 | font-size: 100px; 82 | margin: 0px; 83 | } 84 | 85 | .overscroll .description { 86 | font-family: monospace; 87 | line-height: 22px; 88 | font-size: 18px; 89 | width: 650px; 90 | margin: auto; 91 | margin-top: 10px; 92 | margin-bottom: 25px; 93 | } 94 | 95 | .overscroll .links { 96 | font-family: monospace; 97 | letter-spacing: 0.3px; 98 | font-style: italic; 99 | font-size: 16px; 100 | } 101 | 102 | .overscroll .links a { 103 | text-decoration: none; 104 | margin-left: 10px; 105 | margin-right: 10px; 106 | color: #777; 107 | } 108 | 109 | .overscroll .links a:hover { 110 | text-decoration: underline; 111 | } 112 | 113 | /********************************************* 114 | * Animations 115 | *********************************************/ 116 | 117 | @-webkit-keyframes float-up { 118 | 0% { 119 | -webkit-transform: translateY(0px); 120 | } 121 | 122 | 100% { 123 | -webkit-transform: translateY(10px); 124 | } 125 | } 126 | 127 | @-moz-keyframes float-up { 128 | 0% { 129 | -moz-transform: translateY(0px); 130 | } 131 | 132 | 100% { 133 | -moz-transform: translateY(10px); 134 | } 135 | } 136 | 137 | @-ms-keyframes float-up { 138 | 0% { 139 | -ms-transform: translateY(0px); 140 | } 141 | 142 | 100% { 143 | -ms-transform: translateY(10px); 144 | } 145 | } 146 | 147 | @keyframes float-up { 148 | 0% { 149 | transform: translateY(0px); 150 | } 151 | 152 | 100% { 153 | transform: translateY(10px); 154 | } 155 | } 156 | 157 | @-webkit-keyframes float-down { 158 | 0% { 159 | -webkit-transform: translateY(0px); 160 | } 161 | 162 | 100% { 163 | -webkit-transform: translateY(-10px); 164 | } 165 | } 166 | 167 | @-moz-keyframes float-down { 168 | 0% { 169 | -moz-transform: translateY(0px); 170 | } 171 | 172 | 100% { 173 | -moz-transform: translateY(-10px); 174 | } 175 | } 176 | 177 | @-ms-keyframes float-down { 178 | 0% { 179 | -ms-transform: translateY(0px); 180 | } 181 | 182 | 100% { 183 | -ms-transform: translateY(-10px); 184 | } 185 | } 186 | 187 | @keyframes float-down { 188 | 0% { 189 | transform: translateY(0px); 190 | } 191 | 192 | 100% { 193 | transform: translateY(-10px); 194 | } 195 | } 196 | 197 | /********************************************* 198 | * 3rd party 199 | *********************************************/ 200 | iframe { 201 | margin-bottom: -4px; 202 | margin-left: 15px; 203 | } 204 | 205 | .github-link { 206 | position: fixed; 207 | top: 0; 208 | right: 0; 209 | border: 0; 210 | } 211 | -------------------------------------------------------------------------------- /demo/img/cat-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/overscroll/6a2cf21ebf884b278b5abbefd34a799eeb9f4417/demo/img/cat-1.png -------------------------------------------------------------------------------- /demo/img/cat-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/overscroll/6a2cf21ebf884b278b5abbefd34a799eeb9f4417/demo/img/cat-2.png -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Overscroll.js 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | Fork me on GitHub 23 | 24 | 25 |
26 |

OVERSCROLL.JS

27 |
28 | Overscroll.js, is a small javascript library, giving you the ability to peek and show small easter eggs when the screen is scrolled beyond the height of the window.
(It's a touch based ios/osx thing) 29 |
30 | 36 |
37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /demo/video/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 27 | 28 | 29 | 32 | 33 | -------------------------------------------------------------------------------- /demo/video/overscroll.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/overscroll/6a2cf21ebf884b278b5abbefd34a799eeb9f4417/demo/video/overscroll.mp4 -------------------------------------------------------------------------------- /overscroll.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Overscroll. 3 | * 4 | * MIT licensed 5 | * Copyright (C) 2015 Tim Holman, http://tholman.com 6 | */ 7 | 8 | /********************************************* 9 | * Utils 10 | *********************************************/ 11 | 12 | function getSupportedTransform() { 13 | var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' '); 14 | for(var i = 0; i < prefixes.length; i++) { 15 | if(document.createElement('div').style[prefixes[i]] !== undefined) { 16 | return prefixes[i]; 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | /********************************************* 23 | * Overscroll 24 | *********************************************/ 25 | 26 | function Overscroll() { 27 | 28 | var scrollPosition = 0; 29 | var windowHeight = 0; 30 | var shakeYourBody = document.body; 31 | var windows95 = window; 32 | var transform = getSupportedTransform(); 33 | 34 | var elements = {top: [], bottom: []}; 35 | 36 | this.init = function() { 37 | this.window = window; 38 | this.onScroll(); 39 | this.onResize(); 40 | this.scrollEvent = this.window.addEventListener("scroll", this.onScroll); 41 | this.resizeEvent = this.window.addEventListener("resize", this.onResize); 42 | } 43 | 44 | this.bindElement = function(element, position, delta) { 45 | 46 | // Default data! 47 | delta = delta || 1; 48 | position = position || 'top'; 49 | 50 | // Only bind events once there is something to overscroll. 51 | if( elements.top.length === 0 && elements.bottom.length === 0 ) { 52 | this.init(); 53 | } 54 | 55 | var elementObject = {domElement: element, height: element.clientHeight, delta: delta}; 56 | elements[position].push(elementObject); 57 | } 58 | 59 | this.onScroll = function() { 60 | scrollPosition = windows95.pageYOffset || shakeYourBody.scrollTop; 61 | doTheThing(); 62 | } 63 | 64 | // @TODO, Should I check elements heights here, incase they change? 65 | this.onResize = function() { 66 | windowHeight = windows95.innerHeight; 67 | } 68 | 69 | // Zhu Li! 70 | var doTheThing = function() { 71 | 72 | var i; 73 | 74 | // @TODO: Could this be cleaner, somehow? 75 | // @TODO: Should this use RAF rather than not... its not very intensive 76 | if( scrollPosition <= 0 ) { 77 | for( i = 0; i < elements.top.length; i++ ) { 78 | 79 | var thisElement = elements.top[i]; 80 | var movement = ( -scrollPosition * thisElement.delta ); 81 | 82 | // Don't allow element to overreach its height. 83 | if( movement > thisElement.height ) { 84 | movement = thisElement.height; 85 | } 86 | 87 | thisElement.domElement.style[transform] = 'translateY(' + ( movement ) + 'px )'; 88 | } 89 | } else if ( scrollPosition >= windowHeight ) { 90 | 91 | for( i = 0; i < elements.bottom.length; i++ ) { 92 | 93 | var thisElement = elements.bottom[i]; 94 | var movement = ( ( scrollPosition - windowHeight ) * thisElement.delta ); 95 | 96 | // Don't allow element to overreach its height. 97 | if( movement > thisElement.height ) { 98 | movement = thisElement.height; 99 | } 100 | 101 | thisElement.domElement.style[transform] = 'translateY(' + (-movement ) + 'px )'; 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /overscroll.min.js: -------------------------------------------------------------------------------- 1 | function getSupportedTransform(){var e="transform WebkitTransform MozTransform OTransform msTransform".split(" ");for(var t=0;tr.height){o=r.height}r.domElement.style[i]="translateY("+o+"px )"}}else if(e>=t){for(n=0;nr.height){o=r.height}r.domElement.style[i]="translateY("+ -o+"px )"}}}} -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Overscroll.js 2 | 3 | A tiny javascript library, to capture the moments when you've scrolled more than the screen allows (osx/ios)... so we can sneak in some little easter eggs. [Here's a live demo](http://tholman.com/overscroll), [and here's a video ](http://tholman.com/overscroll/video)! 4 | 5 | ### Instructions 6 | 7 | `Overscroll.js` is a stand alone library (no jquery, or the likes) so usage is pretty straight forward. All styling of easter egg elements is up to the user, `Overscroll.js` only handles moving your elements onto/off the screen, when you are scrolling beyond the pages height. 8 | 9 | #### HTML 10 | 11 | There aren't any restrictions for the `html` overscroll can bind too, that said, you do need to position them (ideally off screen) yourself. Overscroll will handle their movement. 12 | 13 | ```html 14 | 15 | 16 | ``` 17 | 18 | #### CSS 19 | You'll need to position the element you want to slide in/out of the screen initially. Since `overscroll` edits the transform of your element, you should try to avoid using transforms on it too. 20 | 21 | That said, your positioning doesn't need to be anything too complex. For example: 22 | 23 | ```css 24 | .easter-egg { 25 | /* Dimensions */ 26 | width: 300px; 27 | height: 500px; 28 | 29 | /* Fixed position */ 30 | position: fixed; 31 | left: 50%; 32 | top: 0px; 33 | 34 | /* Centered horizontally, and hidden above screen */ 35 | margin-left: -150px; 36 | margin-top: -500px; 37 | } 38 | ``` 39 | 40 | Above, the `margin-top: -500px` hides the element above the top of the screen, since overscroll will handle showing it when the there is overscroll in that direction. 41 | 42 | #### JS 43 | 44 | `Overscroll.js` is fairly straight forward when it comes to kicking it off, you'll need to create a new instance of overscroll (and include the script in the page), and then bind elements to it once they have been rendered. You can do this with `document.querySelector`. 45 | 46 | ```html 47 | 48 | 49 | 55 | ``` 56 | 57 | There are options, for when the easter egg is at the top, or bottom. 58 | 59 | ```html 60 | 61 | 62 | 63 | 70 | ``` 71 | 72 | And finally, a delta, to show how sensitive the scroll should be, when in the overscroll area... this makes it easier for people to find, but isn't really necessary. 73 | 74 | ```html 75 | 76 | 77 | 83 | ``` 84 | 85 | #### Image/Example 86 | 87 | Here's a couple of screenshots of `Overscroll.js` in action. You should really look at the [demo](http://tholman.com/overscroll) though, to get a full feel for the interactions, or check out the [video](http://tholman.com/overscroll/video)! 88 | 89 | Overscroll on the bottom: 90 | ![Overscroll.js doing its thing](http://i.imgur.com/PSvRl9Z.png "Overscroll Bottom") 91 | 92 | Overscroll on the top: 93 | ![Overscroll.js doing its thing](http://i.imgur.com/sHmWDsR.png "Overscroll Top") 94 | 95 | ### Browser support 96 | 97 | Overscroll has been tested in the latest stable builds of Safari and Chrome. IE & Firefox don't really have the "overscroll" zones, so they won't work. Its just for fun... so not the end of the world ;) 98 | 99 | ### License 100 | 101 | The MIT License (MIT) 102 | 103 | Copyright (C) 2017 ~ [Tim Holman](http://tholman.com) ~ timothy.w.holman@gmail.com 104 | --------------------------------------------------------------------------------