├── .babelrc ├── .bowerrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .yo-rc.json ├── README.md ├── app ├── .eslintrc ├── apple-touch-icon.png ├── favicon.ico ├── fonts │ ├── redacted-regular.eot │ ├── redacted-regular.svg │ ├── redacted-regular.ttf │ ├── redacted-regular.woff │ └── redacted-regular.woff2 ├── index.html ├── robots.txt ├── scripts │ └── main.js └── styles │ ├── _header.scss │ └── main.scss ├── bower.json ├── dist ├── apple-touch-icon.png ├── favicon.ico ├── fonts │ ├── redacted-regular.eot │ ├── redacted-regular.svg │ ├── redacted-regular.ttf │ ├── redacted-regular.woff │ └── redacted-regular.woff2 ├── index.html ├── robots.txt ├── scripts │ └── main.js └── styles │ └── main.css ├── gulpfile.js ├── package.json └── test ├── index.html └── spec └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [{package,bower}.json] 24 | indent_style = space 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .tmp 3 | bower_components 4 | test/bower_components 5 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-mocha": { 3 | "ui": "tdd", 4 | "rjs": false 5 | } 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Envato Tuts+ Tutorial: [How to Create a “Sticky” Floating Video on Page Scroll](http://webdesign.tutsplus.com/tutorials/how-to-create-a-sticky-floating-video-on-page-scroll--cms-28342) 2 | #### Instructor: [Louie Rootfield](https://tutsplus.com/authors/lourfield) 3 | 4 | If you have found yourself browsing media websites recently–video streaming services, news websites, Facebook and so on–you might have noticed a trend regarding their video players. If we scroll down a page where a video is present, it will float and shrink the player, sticking it to the side of the viewport instead of losing it from view. This allows the users to keep an eye on the video, whilst looking through the other content at the same time. In this tutorial I’m going to show you how to recreate the same experience–so without further ado, let’s get started! 5 | 6 | [View the demo](http://tutsplus.github.io/how-to-create-a-sticky-floating-video-on-page-scroll) 7 | 8 | -------------------------------------------------------------------------------- /app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "jquery", 3 | "globals": { 4 | "jQuery": true, 5 | "YT": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/app/apple-touch-icon.png -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/app/favicon.ico -------------------------------------------------------------------------------- /app/fonts/redacted-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/app/fonts/redacted-regular.eot -------------------------------------------------------------------------------- /app/fonts/redacted-regular.svg: -------------------------------------------------------------------------------- 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 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /app/fonts/redacted-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/app/fonts/redacted-regular.ttf -------------------------------------------------------------------------------- /app/fonts/redacted-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/app/fonts/redacted-regular.woff -------------------------------------------------------------------------------- /app/fonts/redacted-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/app/fonts/redacted-regular.woff2 -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Floating Video — Tuts+ 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 |
29 |

Intruction: play the Youtube video and scrolldown to the bottom.

30 |
31 |
32 |
33 |
34 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto, excepturi. Rerum pariatur.

35 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit officiis, minus architecto alias voluptatibus ex, earum quis autem corporis sunt?

36 | 39 |
40 |
41 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

42 | 43 |
44 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium aliquid aliquam impedit voluptatibus nobis facere consequuntur sapiente ab eveniet ducimus necessitatibus autem aut rem veniam tempore eius deserunt, numquam itaque. 45 |
46 | 47 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

48 | 49 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

50 | 51 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur, sequi.

52 | 53 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

54 | 55 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

56 | 57 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur, sequi.

58 | 59 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

60 | 61 |
62 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium aliquid aliquam impedit voluptatibus nobis facere consequuntur sapiente ab eveniet ducimus necessitatibus autem aut rem veniam tempore eius deserunt, numquam itaque. 63 |
64 | 65 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur, sequi.

66 | 67 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

68 |
69 |
70 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /app/scripts/main.js: -------------------------------------------------------------------------------- 1 | /* eslint 2 | no-unused-vars: ["error", { "vars": "local", "varsIgnorePattern": "player" }] 3 | */ 4 | jQuery( function( $ ) { 5 | 6 | var player; 7 | 8 | var $window = $( window ); 9 | var $featuredMedia = $( "#featured-media" ); // Container. 10 | var $featuredVideo = $( "#featured-video" ); // Actual Video. 11 | var top = $featuredMedia.offset().top; 12 | var offset = Math.floor( top + ( $featuredMedia.outerHeight() / 2 ) ); 13 | 14 | window.onYouTubeIframeAPIReady = function() { 15 | player = new YT.Player( "featured-video", { 16 | events: { 17 | "onStateChange": onPlayerStateChange 18 | } 19 | } ); 20 | }; 21 | 22 | /** 23 | * Run when the Youtube video state (play, pause, etc.) is changed. 24 | * 25 | * @param {Object} event The Youtube Object Event. 26 | * @return {Void} 27 | */ 28 | function onPlayerStateChange( event ) { 29 | 30 | var isPlay = 1 === event.data; 31 | var isPause = 2 === event.data; 32 | var isEnd = 0 === event.data; 33 | 34 | if ( isPlay ) { 35 | $featuredVideo.removeClass( "is-paused" ); 36 | $featuredVideo.toggleClass( "is-playing" ); 37 | } 38 | 39 | if ( isPause ) { 40 | $featuredVideo.removeClass( "is-playing" ); 41 | $featuredVideo.toggleClass( "is-paused" ); 42 | } 43 | 44 | if ( isEnd ) { 45 | $featuredVideo.removeClass( "is-playing", "is-paused" ); 46 | } 47 | } 48 | 49 | /** 50 | * _.Underscore.js throttle. 51 | * 52 | * Delay executing a function. It will reduce the notifications of an event that fires multiple times. 53 | * 54 | * @see http://stackoverflow.com/questions/27078285/simple-throttle-in-js 55 | * 56 | * @param {Function} func The function to execute. 57 | * @param {Number} wait The delay time. 58 | * @param {Object} options Some options. 59 | * @return {Function} The function to execute. 60 | */ 61 | // function throttle( func, wait, options ) { 62 | // 63 | // var context, args, result; 64 | // var timeout = null; 65 | // var previous = 0; 66 | // if ( !options ) { 67 | // options = {}; 68 | // } 69 | // 70 | // var later = function() { 71 | // previous = options.leading === false ? 0 : Date.now(); 72 | // timeout = null; 73 | // result = func.apply( context, args ); 74 | // if ( !timeout ) { 75 | // context = args = null; 76 | // } 77 | // }; 78 | // 79 | // return function() { 80 | // var now = Date.now(); 81 | // if ( !previous && options.leading === false ) { 82 | // previous = now; 83 | // } 84 | // var remaining = wait - ( now - previous ); 85 | // context = this; 86 | // args = arguments; 87 | // if ( remaining <= 0 || remaining > wait ) { 88 | // if ( timeout ) { 89 | // clearTimeout( timeout ); 90 | // timeout = null; 91 | // } 92 | // previous = now; 93 | // result = func.apply( context, args ); 94 | // if ( !timeout ) { 95 | // context = args = null; 96 | // } 97 | // } else if ( !timeout && options.trailing !== false ) { 98 | // timeout = setTimeout( later, remaining ); 99 | // } 100 | // return result; 101 | // }; 102 | // }; 103 | 104 | // $window 105 | // 106 | // .on( "resize", throttle( function() { 107 | // top = $featuredMedia.offset().top; 108 | // offset = Math.floor( top + ( $featuredMedia.outerHeight() / 2 ) ); 109 | // }, 150 ) ) 110 | // 111 | // .on( "scroll", throttle( function() { 112 | // $featuredVideo.toggleClass( "is-sticky", 113 | // $window.scrollTop() > offset && $featuredVideo.hasClass( "is-playing" ) 114 | // ); 115 | // }, 150 ) ); 116 | // 117 | 118 | $window 119 | 120 | .on( "resize", function() { 121 | top = $featuredMedia.offset().top; 122 | offset = Math.floor( top + ( $featuredMedia.outerHeight() / 2 ) ); 123 | } ) 124 | 125 | .on( "scroll", function() { 126 | $featuredVideo.toggleClass( "is-sticky", 127 | $window.scrollTop() > offset && $featuredVideo.hasClass( "is-playing" ) 128 | ); 129 | } ); 130 | } ); 131 | -------------------------------------------------------------------------------- /app/styles/_header.scss: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-family: Arial, sans-serif; 4 | } 5 | *, 6 | *:before, 7 | *:after { 8 | box-sizing: inherit; 9 | } 10 | .cf:before, 11 | .cf:after { 12 | display: table; 13 | content: ' '; 14 | } 15 | .cf:after { 16 | clear: both; 17 | } 18 | .cf { 19 | *zoom: 1; 20 | } 21 | body { 22 | margin: 0; 23 | } 24 | img { 25 | max-width: 100%; 26 | height: auto; 27 | } 28 | figure { 29 | margin: 0; 30 | padding: 10px; 31 | } 32 | figure a { 33 | display: block; 34 | } 35 | mark { 36 | padding: 0 5px; 37 | background-color: #dddddd; 38 | } 39 | .site-header { 40 | background-color: #212a34; 41 | text-align: center; 42 | } 43 | .site-header h1, 44 | .site-header a { 45 | padding: 15px; 46 | text-transform: uppercase; 47 | color: #fff; 48 | } 49 | .site-header h1 { 50 | font-size: 18px; 51 | margin: 0; 52 | } 53 | .site-header a { 54 | font-size: 14px; 55 | font-weight: 300; 56 | display: block; 57 | text-decoration: none; 58 | background-color: #49b293; 59 | font-weight: 600; 60 | } 61 | @media screen and (min-width: 630px) { 62 | .site-header { 63 | text-align: none; 64 | } 65 | .site-header h1, 66 | .site-header a { 67 | font-size: 12px; 68 | } 69 | .site-header h1 { 70 | float: left; 71 | } 72 | .site-header a { 73 | float: right; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/styles/main.scss: -------------------------------------------------------------------------------- 1 | // bower:scss 2 | // endbower 3 | 4 | @import "../../bower_components/normalize.sass/_normalize"; 5 | @import "header"; 6 | 7 | body { 8 | background: #fafafa; 9 | text-rendering: optimizeLegibility; 10 | line-height: 1.68; 11 | } 12 | @font-face { 13 | font-family: 'redactedregular'; 14 | src: url('../fonts/redacted-regular.eot'); 15 | src: url('../fonts/redacted-regular.eot?#iefix') format('embedded-opentype'), 16 | url('../fonts/redacted-regular.woff2') format('woff2'), 17 | url('../fonts/redacted-regular.woff') format('woff'), 18 | url('../fonts/redacted-regular.ttf') format('truetype'), 19 | url('../fonts/redacted-regular.svg#redactedregular') format('svg'); 20 | font-weight: normal; 21 | font-style: normal; 22 | } 23 | .container { 24 | max-width: 720px; 25 | margin: 80px auto; 26 | padding: 0 30px; 27 | font-family: 'redactedregular'; 28 | position: relative; 29 | } 30 | .notice { 31 | background-color: #ffcc33; 32 | color: #000; 33 | font-weight: 700; 34 | padding: 15px; 35 | text-align: center; 36 | font-size: 0.9em; 37 | p { 38 | margin: 0; 39 | } 40 | } 41 | .content-media--video { 42 | background-color: #ddd; 43 | display: block; 44 | position: relative; 45 | padding: 0 0 ( ( 158px / 280px ) * 100% ) 0; 46 | } 47 | .content-media--video iframe { 48 | position: absolute; 49 | bottom: 0; 50 | left: 0; 51 | width: 100%; 52 | height: 100%; 53 | } 54 | .site-content { 55 | color: #ddd; 56 | p { 57 | line-height: 2.16; 58 | } 59 | h2 { 60 | margin-top: 60px; 61 | margin-bottom: 30px; 62 | } 63 | blockquote { 64 | margin-top: 50px; 65 | margin-bottom: 50px; 66 | padding: 20px 0; 67 | line-height: 1.8; 68 | border-top: 4px solid #eee; 69 | border-bottom: 4px solid #eee; 70 | } 71 | } 72 | .site-content header { 73 | margin-bottom: 3em; 74 | h1 { 75 | margin-top: 0; 76 | margin-bottom: 0.6em; 77 | } 78 | h2 { 79 | font-size: 1.1em; 80 | color: #ccc; 81 | } 82 | figure { 83 | margin: 2em 0; 84 | } 85 | } 86 | #featured-video { 87 | transition: width .2s ease-in-out, height .2s ease-in-out, transform .38s ease-in-out; 88 | } 89 | #featured-video.is-sticky { 90 | position: fixed; 91 | top: 15px; 92 | left: auto; 93 | max-width: 280px; 94 | max-height: 158px; 95 | width: 280px; 96 | height: 158px; 97 | @media screen and (min-width: 1120px) { 98 | transform: translateX(-80%); 99 | } 100 | @media screen and (min-width: 1300px) { 101 | transform: translateX(-115%); 102 | } 103 | 104 | /** 105 | * Optional, position should adjust following user behaviour; 106 | * whether the left-handed or right-handed. 107 | * 108 | * So it is often better to keep the video on top. 109 | */ 110 | @media screen and (max-width: 480px) { 111 | top: auto; 112 | bottom: 15px; 113 | 114 | // Compensating smaller screen. 115 | max-width: 200px; 116 | max-height: 113px; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "floating-video", 3 | "private": true, 4 | "dependencies": { 5 | "normalize.sass": "^3.0.0" 6 | }, 7 | "devDependencies": { 8 | "chai": "^3.5.0", 9 | "mocha": "^3.2.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dist/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/dist/apple-touch-icon.png -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/dist/favicon.ico -------------------------------------------------------------------------------- /dist/fonts/redacted-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/dist/fonts/redacted-regular.eot -------------------------------------------------------------------------------- /dist/fonts/redacted-regular.svg: -------------------------------------------------------------------------------- 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 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /dist/fonts/redacted-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/dist/fonts/redacted-regular.ttf -------------------------------------------------------------------------------- /dist/fonts/redacted-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/dist/fonts/redacted-regular.woff -------------------------------------------------------------------------------- /dist/fonts/redacted-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/how-to-create-a-sticky-floating-video-on-page-scroll/5d9cb915ab8a1aae74659272426be9ecb899bf40/dist/fonts/redacted-regular.woff2 -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | Floating Video — Tuts+

Intruction: play the Youtube video and scrolldown to the bottom.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto, excepturi. Rerum pariatur.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit officiis, minus architecto alias voluptatibus ex, earum quis autem corporis sunt?

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium aliquid aliquam impedit voluptatibus nobis facere consequuntur sapiente ab eveniet ducimus necessitatibus autem aut rem veniam tempore eius deserunt, numquam itaque.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur, sequi.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur, sequi.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium aliquid aliquam impedit voluptatibus nobis facere consequuntur sapiente ab eveniet ducimus necessitatibus autem aut rem veniam tempore eius deserunt, numquam itaque.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur, sequi.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

-------------------------------------------------------------------------------- /dist/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /dist/scripts/main.js: -------------------------------------------------------------------------------- 1 | "use strict";jQuery(function(e){function s(e){var s=1===e.data,a=2===e.data,o=0===e.data;s&&(i.removeClass("is-paused"),i.toggleClass("is-playing")),a&&(i.removeClass("is-playing"),i.toggleClass("is-paused")),o&&i.removeClass("is-playing","is-paused")}var a,o=e(window),t=e("#featured-media"),i=e("#featured-video"),n=t.offset().top,l=Math.floor(n+t.outerHeight()/2);window.onYouTubeIframeAPIReady=function(){a=new YT.Player("featured-video",{events:{onStateChange:s}})},o.on("resize",function(){n=t.offset().top,l=Math.floor(n+t.outerHeight()/2)}).on("scroll",function(){i.toggleClass("is-sticky",o.scrollTop()>l&&i.hasClass("is-playing"))})}); -------------------------------------------------------------------------------- /dist/styles/main.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit}button{overflow:visible;text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}html{box-sizing:border-box;font-family:Arial,sans-serif}*,:after,:before{box-sizing:inherit}.cf:after,.cf:before{display:table;content:" "}.cf:after{clear:both}.cf{*zoom:1}body{margin:0}img{max-width:100%;height:auto}figure{margin:0;padding:10px}figure a{display:block}mark{padding:0 5px;background-color:#ddd}.site-header{background-color:#212a34;text-align:center}.site-header a,.site-header h1{padding:15px;text-transform:uppercase;color:#fff}.site-header h1{font-size:18px;margin:0}.site-header a{font-size:14px;font-weight:300;display:block;text-decoration:none;background-color:#49b293;font-weight:600}@media screen and (min-width:630px){.site-header{text-align:none}.site-header a,.site-header h1{font-size:12px}.site-header h1{float:left}.site-header a{float:right}}body{background:#fafafa;text-rendering:optimizeLegibility;line-height:1.68}@font-face{font-family:redactedregular;src:url(../fonts/redacted-regular.eot);src:url(../fonts/redacted-regular.eot?#iefix) format("embedded-opentype"),url(../fonts/redacted-regular.woff2) format("woff2"),url(../fonts/redacted-regular.woff) format("woff"),url(../fonts/redacted-regular.ttf) format("truetype"),url(../fonts/redacted-regular.svg#redactedregular) format("svg");font-weight:400;font-style:normal}.container{max-width:720px;margin:80px auto;padding:0 30px;font-family:redactedregular;position:relative}.notice{background-color:#fc3;color:#000;font-weight:700;padding:15px;text-align:center;font-size:.9em}.notice p{margin:0}.content-media--video{background-color:#ddd;display:block;position:relative;padding:0 0 56.4285714286%}.content-media--video iframe{position:absolute;bottom:0;left:0;width:100%;height:100%}.site-content{color:#ddd}.site-content p{line-height:2.16}.site-content h2{margin-top:60px;margin-bottom:30px}.site-content blockquote{margin-top:50px;margin-bottom:50px;padding:20px 0;line-height:1.8;border-top:4px solid #eee;border-bottom:4px solid #eee}.site-content header{margin-bottom:3em}.site-content header h1{margin-top:0;margin-bottom:.6em}.site-content header h2{font-size:1.1em;color:#ccc}.site-content header figure{margin:2em 0}#featured-video{-webkit-transition:width .2s ease-in-out,height .2s ease-in-out,-webkit-transform .38s ease-in-out;transition:width .2s ease-in-out,height .2s ease-in-out,-webkit-transform .38s ease-in-out;transition:width .2s ease-in-out,height .2s ease-in-out,transform .38s ease-in-out;transition:width .2s ease-in-out,height .2s ease-in-out,transform .38s ease-in-out,-webkit-transform .38s ease-in-out}#featured-video.is-sticky{position:fixed;top:15px;left:auto;max-width:280px;max-height:158px;width:280px;height:158px}@media screen and (min-width:1120px){#featured-video.is-sticky{-webkit-transform:translateX(-80%);transform:translateX(-80%)}}@media screen and (min-width:1300px){#featured-video.is-sticky{-webkit-transform:translateX(-115%);transform:translateX(-115%)}}@media screen and (max-width:480px){#featured-video.is-sticky{top:auto;bottom:15px;max-width:200px;max-height:113px}} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // generated on 2017-02-11 using generator-webapp 2.3.2 2 | const gulp = require('gulp'); 3 | const gulpLoadPlugins = require('gulp-load-plugins'); 4 | const browserSync = require('browser-sync').create(); 5 | const del = require('del'); 6 | const wiredep = require('wiredep').stream; 7 | const runSequence = require('run-sequence'); 8 | 9 | const $ = gulpLoadPlugins(); 10 | const reload = browserSync.reload; 11 | 12 | var dev = true; 13 | 14 | gulp.task('styles', () => { 15 | return gulp.src('app/styles/*.scss') 16 | .pipe($.plumber()) 17 | .pipe($.sourcemaps.init()) 18 | .pipe($.sass.sync({ 19 | outputStyle: 'expanded', 20 | precision: 10, 21 | includePaths: ['.'] 22 | }).on('error', $.sass.logError)) 23 | .pipe($.autoprefixer({browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']})) 24 | .pipe($.sourcemaps.write()) 25 | .pipe(gulp.dest('.tmp/styles')) 26 | .pipe(reload({stream: true})); 27 | }); 28 | 29 | gulp.task('scripts', () => { 30 | return gulp.src('app/scripts/**/*.js') 31 | .pipe($.plumber()) 32 | .pipe($.sourcemaps.init()) 33 | .pipe($.babel()) 34 | .pipe($.sourcemaps.write('.')) 35 | .pipe(gulp.dest('.tmp/scripts')) 36 | .pipe(reload({stream: true})); 37 | }); 38 | 39 | function lint(files, options) { 40 | return gulp.src(files) 41 | .pipe($.eslint({ fix: true })) 42 | .pipe(reload({stream: true, once: true})) 43 | .pipe($.eslint.format()) 44 | .pipe($.if(!browserSync.active, $.eslint.failAfterError())); 45 | } 46 | 47 | gulp.task('lint', () => { 48 | return lint('app/scripts/**/*.js') 49 | .pipe(gulp.dest('app/scripts')); 50 | }); 51 | gulp.task('lint:test', () => { 52 | return lint('test/spec/**/*.js') 53 | .pipe(gulp.dest('test/spec')); 54 | }); 55 | 56 | gulp.task('html', ['styles', 'scripts'], () => { 57 | return gulp.src('app/*.html') 58 | .pipe($.useref({searchPath: ['.tmp', 'app', '.']})) 59 | .pipe($.if('*.js', $.uglify())) 60 | .pipe($.if('*.css', $.cssnano({safe: true, autoprefixer: false}))) 61 | .pipe($.if('*.html', $.htmlmin({collapseWhitespace: true}))) 62 | .pipe(gulp.dest('dist')); 63 | }); 64 | 65 | gulp.task('images', () => { 66 | return gulp.src('app/images/**/*') 67 | .pipe($.cache($.imagemin())) 68 | .pipe(gulp.dest('dist/images')); 69 | }); 70 | 71 | gulp.task('fonts', () => { 72 | return gulp.src(require('main-bower-files')('**/*.{eot,svg,ttf,woff,woff2}', function (err) {}) 73 | .concat('app/fonts/**/*')) 74 | .pipe($.if(dev, gulp.dest('.tmp/fonts'), gulp.dest('dist/fonts'))); 75 | }); 76 | 77 | gulp.task('extras', () => { 78 | return gulp.src([ 79 | 'app/*', 80 | '!app/*.html' 81 | ], { 82 | dot: false 83 | }).pipe(gulp.dest('dist')); 84 | }); 85 | 86 | gulp.task('clean', del.bind(null, ['.tmp', 'dist'])); 87 | 88 | gulp.task('serve', () => { 89 | runSequence(['clean', 'wiredep'], ['styles', 'scripts', 'fonts'], () => { 90 | browserSync.init({ 91 | notify: false, 92 | port: 9000, 93 | server: { 94 | baseDir: ['.tmp', 'app'], 95 | routes: { 96 | '/bower_components': 'bower_components' 97 | } 98 | } 99 | }); 100 | 101 | gulp.watch([ 102 | 'app/*.html', 103 | 'app/images/**/*', 104 | '.tmp/fonts/**/*' 105 | ]).on('change', reload); 106 | 107 | gulp.watch('app/styles/**/*.scss', ['styles']); 108 | gulp.watch('app/scripts/**/*.js', ['scripts']); 109 | gulp.watch('app/fonts/**/*', ['fonts']); 110 | gulp.watch('bower.json', ['wiredep', 'fonts']); 111 | }); 112 | }); 113 | 114 | gulp.task('serve:dist', ['default'], () => { 115 | browserSync.init({ 116 | notify: false, 117 | port: 9000, 118 | server: { 119 | baseDir: ['dist'] 120 | } 121 | }); 122 | }); 123 | 124 | gulp.task('serve:test', ['scripts'], () => { 125 | browserSync.init({ 126 | notify: false, 127 | port: 9000, 128 | ui: false, 129 | server: { 130 | baseDir: 'test', 131 | routes: { 132 | '/scripts': '.tmp/scripts', 133 | '/bower_components': 'bower_components' 134 | } 135 | } 136 | }); 137 | 138 | gulp.watch('app/scripts/**/*.js', ['scripts']); 139 | gulp.watch(['test/spec/**/*.js', 'test/index.html']).on('change', reload); 140 | gulp.watch('test/spec/**/*.js', ['lint:test']); 141 | }); 142 | 143 | // inject bower components 144 | gulp.task('wiredep', () => { 145 | gulp.src('app/styles/*.scss') 146 | .pipe($.filter(file => file.stat && file.stat.size)) 147 | .pipe(wiredep({ 148 | ignorePath: /^(\.\.\/)+/ 149 | })) 150 | .pipe(gulp.dest('app/styles')); 151 | 152 | gulp.src('app/*.html') 153 | .pipe(wiredep({ 154 | ignorePath: /^(\.\.\/)*\.\./ 155 | })) 156 | .pipe(gulp.dest('app')); 157 | }); 158 | 159 | gulp.task('build', ['lint', 'html', 'images', 'fonts', 'extras'], () => { 160 | return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true})); 161 | }); 162 | 163 | gulp.task('default', () => { 164 | return new Promise(resolve => { 165 | dev = false; 166 | runSequence(['clean', 'wiredep'], 'build', resolve); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "engines": { 4 | "node": ">=4" 5 | }, 6 | "devDependencies": { 7 | "babel-core": "^6.4.0", 8 | "babel-preset-es2015": "^6.3.13", 9 | "babel-register": "^6.5.2", 10 | "browser-sync": "^2.2.1", 11 | "del": "^2.2.0", 12 | "eslint-config-jquery": "^1.0.0", 13 | "gulp": "^3.9.0", 14 | "gulp-autoprefixer": "^3.0.1", 15 | "gulp-babel": "^6.1.1", 16 | "gulp-cache": "^0.4.2", 17 | "gulp-cssnano": "^2.0.0", 18 | "gulp-eslint": "^3.0.0", 19 | "gulp-filter": "^4.0.0", 20 | "gulp-htmlmin": "^3.0.0", 21 | "gulp-if": "^2.0.2", 22 | "gulp-imagemin": "^3.0.1", 23 | "gulp-load-plugins": "^1.2.4", 24 | "gulp-plumber": "^1.0.1", 25 | "gulp-sass": "^2.0.0", 26 | "gulp-size": "^2.1.0", 27 | "gulp-sourcemaps": "^2.2.0", 28 | "gulp-uglify": "^2.0.0", 29 | "gulp-useref": "^3.0.0", 30 | "main-bower-files": "^2.5.0", 31 | "run-sequence": "^1.2.2", 32 | "wiredep": "^4.0.0" 33 | }, 34 | "eslintConfig": { 35 | "env": { 36 | "es6": true, 37 | "node": true, 38 | "browser": true 39 | }, 40 | "rules": { 41 | "quotes": [ 42 | 2, 43 | "single" 44 | ] 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Spec Runner 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/spec/test.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | describe('Give it some context', function () { 5 | describe('maybe a bit more context here', function () { 6 | it('should run here few assertions', function () { 7 | 8 | }); 9 | }); 10 | }); 11 | })(); 12 | --------------------------------------------------------------------------------