├── .babelrc ├── .drone.yml ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jscsrc ├── README.md ├── bower.json ├── dist ├── sticky-state.css ├── sticky-state.js └── sticky-state.min.js ├── examples ├── headroom.html ├── horizontal.html ├── index.html ├── main.css └── simple.html ├── package.json ├── src ├── sticky-state.css └── sticky-state.js ├── test ├── index.html └── index.js ├── webpack.dev.js └── webpack.prod.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ], 5 | 6 | "plugins": [ 7 | "transform-class-properties", 8 | "transform-class-constructor-call", [ 9 | "transform-es2015-classes", { 10 | "loose": true 11 | } 12 | ], 13 | "add-module-exports" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | cache: 2 | mount: 3 | - node_modules 4 | - .git 5 | build: 6 | image: node:6.2.2 7 | commands: 8 | - npm install 9 | publish: 10 | sftp: 11 | host: soenkekluth.com 12 | username: soenkekluth 13 | destination_path: /dev.soenkekluth.com/sticky-state 14 | files: 15 | - dist/* 16 | - examples/* 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS or Editor folders 2 | .DS_Store 3 | *.sublime-workspace 4 | npm-debug.log 5 | 6 | # Project folders to ignore 7 | node_modules 8 | .tern-port 9 | *.map 10 | /material 11 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "google", 3 | "maximumLineLength" : 200, 4 | "disallowSpacesInAnonymousFunctionExpression": null, 5 | "excludeFiles": [ "node_modules/**" ], 6 | "disallowEmptyBlocks": true, 7 | "disallowKeywords": [ 8 | "with" 9 | ], 10 | "disallowMixedSpacesAndTabs": true, 11 | "disallowMultipleLineStrings": true, 12 | "disallowMultipleVarDecl": "exceptUndefined", 13 | "disallowSpaceAfterPrefixUnaryOperators": [ 14 | "!", 15 | "+", 16 | "++", 17 | "-", 18 | "--", 19 | "~" 20 | ], 21 | "disallowSpaceBeforeBinaryOperators": [ 22 | "," 23 | ], 24 | "disallowSpaceBeforePostfixUnaryOperators": true, 25 | "disallowSpacesInNamedFunctionExpression": { 26 | "beforeOpeningRoundBrace": true 27 | }, 28 | "disallowSpacesInsideArrayBrackets": true, 29 | "disallowSpacesInsideParentheses": true, 30 | "disallowTrailingComma": true, 31 | "disallowTrailingWhitespace": true, 32 | "requireCamelCaseOrUpperCaseIdentifiers": true, 33 | "requireCapitalizedConstructors": true, 34 | "requireCommaBeforeLineBreak": true, 35 | "requireCurlyBraces": true, 36 | "requireDotNotation": true, 37 | "requireLineFeedAtFileEnd": true, 38 | "requireParenthesesAroundIIFE": true, 39 | "requireSpaceAfterBinaryOperators": true, 40 | "requireSpaceAfterKeywords": [ 41 | "catch", 42 | "do", 43 | "else", 44 | "for", 45 | "if", 46 | "return", 47 | "switch", 48 | "try", 49 | "while" 50 | ], 51 | "requireSpaceAfterLineComment": true, 52 | "requireSpaceBeforeBinaryOperators": true, 53 | "requireSpaceBeforeBlockStatements": true, 54 | "requireSpacesInAnonymousFunctionExpression": { 55 | "beforeOpeningCurlyBrace": true 56 | }, 57 | "requireSpacesInConditionalExpression": true, 58 | "requireSpacesInFunctionDeclaration": { 59 | "beforeOpeningCurlyBrace": true 60 | }, 61 | "requireSpacesInFunctionExpression": { 62 | "beforeOpeningCurlyBrace": true 63 | }, 64 | "requireSpacesInNamedFunctionExpression": { 65 | "beforeOpeningCurlyBrace": true 66 | }, 67 | "validateIndentation": 2, 68 | "validateLineBreaks": "LF", 69 | "validateParameterSeparator": ", ", 70 | "validateQuoteMarks": "'" 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #StickyState 2 | 3 | StickyState adds state to position:sticky elements and also polyfills the missing native sticky feature. 4 | 5 | Dependency free, pure Javascript for IE9+. 6 | 7 | Today's browsers do not all support the position:sticky feature (which by the way is being used (polyfilled) on pretty much every site you visit) - moreover the native supported feature itself comes without a readable state. Something like `a:hover => div:sticky` to add different styles to the element in its sticky state - or to read the state if needed in JavaScript. 8 | 9 | Unlike almost all polyfills you can find in the wild, StickyState is highly performant. The calculations are reduced to a minimum by persisting several attributes. 10 | 11 | In some cases you also need to know in which direction the user scrolls - for example if you want to hide a sticky header when the user scrolls up. if you set the scrollClass property of the options StickyState will add your choosen classNames to the element when it is sticky and scrolling. 12 | 13 | As a standalone Library its 6.75kb gzipped. 14 | 15 | # Warning concerning Chromes implementation of native position:sticky 16 | it looks like chromes implementaton of position:sticky is different to all other implementations out there. don't know if thats a bug - but bottom is currently not recognized by chrome. there will be a fix for this soon in sticky-state 17 | 18 | ### Dependencies 19 | none! 20 | 21 | ### Browser support 22 | IE >= 9, * 23 | 24 |
25 | 26 | ### Install 27 | ``` 28 | npm install sticky-state 29 | ``` 30 | 31 |
32 | 33 | ### Demo 34 | #### all you can eat 35 | https://rawgit.com/soenkekluth/sticky-state/master/examples/index.html 36 | 37 | #### headroom style 38 | https://rawgit.com/soenkekluth/sticky-state/master/examples/headroom.html 39 | 40 | #### simple 41 | https://rawgit.com/soenkekluth/sticky-state/master/examples/simple.html 42 | 43 |
44 | 45 | ### css 46 | Your css should contain the following lines: 47 | (you can specify the classNames in js) 48 | https://github.com/soenkekluth/sticky-state/blob/master/dist/sticky-state.css 49 | ```css 50 | .sticky { 51 | position: -webkit-sticky; 52 | position: sticky; 53 | } 54 | 55 | .sticky.sticky-fixed.is-sticky { 56 | position: fixed; 57 | -webkit-backface-visibility: hidden; 58 | -moz-backface-visibility: hidden; 59 | backface-visibility: hidden; 60 | } 61 | 62 | .sticky.sticky-fixed.is-sticky:not([style*="margin-top"]) { 63 | margin-top: 0 !important; 64 | } 65 | .sticky.sticky-fixed.is-sticky:not([style*="margin-bottom"]) { 66 | margin-bottom: 0 !important; 67 | } 68 | 69 | .sticky.sticky-fixed.is-absolute{ 70 | position: absolute; 71 | } 72 | 73 | ``` 74 |
75 | 76 | ### js 77 | ```javascript 78 | var StickyState = require('sticky-state'); 79 | new StickyState(document.querySelectorAll('.sticky')); 80 | // all elements with class .sticky will have sticky state: 81 | ``` 82 | 83 | #### options 84 | ```javascript 85 | 86 | var StickyState = require('sticky-state'); 87 | 88 | // the props you can set (except scrollClass this shows the default options): 89 | 90 | 91 | 92 | var stickyOptions = { 93 | disabled: false, // disable or enable the sticky feature initially 94 | className: 'sticky', // the core class which should be equal to the css. see above. 95 | stateClassName: 'is-sticky', // the state class, when the element is actually sticky 96 | fixedClass: 'sticky-fixed', // the fallback class that uses position:fixed to make the element sticky 97 | wrapperClass: 'sticky-wrap', // the fallback (polyfilled) version needs a placeholder that uses the space of the actual sticky element when its position:fixed 98 | wrapFixedSticky: true, // by default the sticky element gets wrapped by the placeholder. if you set it to false it will be inserted right before it. 99 | absoluteClass: 'is-absolute', // the polyfilled sticky element needs to be position:absolut in some cases. 100 | 101 | // scrollclass will add a class to the sticky element that is depending on the scroll direction when the element is sticky. 102 | // when the scrolling stops the class will be the value of "none" unless you set "persist" to true. 103 | 104 | scrollClass: { 105 | down: null, 106 | up: null, 107 | none: null, 108 | persist: false 109 | } 110 | }; 111 | 112 | // instantiate with options 113 | var stickyElements = new StickyState(document.querySelectorAll('.sticky'), stickyOptions); 114 | 115 | ``` 116 | 117 | #### api / events 118 | ```javascript 119 | var StickyState = require('sticky-state'); 120 | new StickyState(document.querySelectorAll('.sticky')) 121 | .on('sticky:on', function(e){console.log('sticky:on', e.target);}) 122 | .on('sticky:off', function(e){console.log('sticky:off' ,e.target);}); 123 | 124 | ``` 125 |
126 | 127 | ### React Component 128 | https://github.com/soenkekluth/react-sticky-state 129 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sticky-state", 3 | "description": "StickyState is a high performant module making native position:sticky statefull and polyfill the missing sticky browser feature", 4 | "main": "dist/sticky-state.min.js", 5 | "authors": [ 6 | "Sönke Kluth (http://soenkekluth.com/)" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "position:sticky", 11 | "sticky", 12 | "polyfill", 13 | "state", 14 | "statefull", 15 | "performant", 16 | "position" 17 | ], 18 | "homepage": "https://github.com/soenkekluth/sticky-state", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /dist/sticky-state.css: -------------------------------------------------------------------------------- 1 | .sticky { 2 | position: -webkit-sticky; 3 | position: sticky; 4 | } 5 | 6 | .sticky.sticky-fixed.is-sticky { 7 | margin-top: 0; 8 | margin-bottom: 0; 9 | position: fixed; 10 | -webkit-backface-visibility: hidden; 11 | -moz-backface-visibility: hidden; 12 | backface-visibility: hidden; 13 | } 14 | 15 | .sticky.sticky-fixed.is-sticky:not([style*="margin-top"]) { 16 | margin-top: 0 !important; 17 | } 18 | .sticky.sticky-fixed.is-sticky:not([style*="margin-bottom"]) { 19 | margin-bottom: 0 !important; 20 | } 21 | 22 | 23 | .sticky.sticky-fixed.is-absolute{ 24 | position: absolute; 25 | } 26 | -------------------------------------------------------------------------------- /dist/sticky-state.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _objectAssign = require('object-assign'); 10 | 11 | var _objectAssign2 = _interopRequireDefault(_objectAssign); 12 | 13 | var _classstring = require('classstring'); 14 | 15 | var _classstring2 = _interopRequireDefault(_classstring); 16 | 17 | var _eventdispatcher = require('eventdispatcher'); 18 | 19 | var _eventdispatcher2 = _interopRequireDefault(_eventdispatcher); 20 | 21 | var _scrollfeatures = require('scrollfeatures'); 22 | 23 | var _scrollfeatures2 = _interopRequireDefault(_scrollfeatures); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 28 | 29 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 30 | 31 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 32 | 33 | var defaults = { 34 | disabled: false, 35 | className: 'sticky', 36 | stateClassName: 'is-sticky', 37 | fixedClass: 'sticky-fixed', 38 | wrapperClass: 'sticky-wrap', 39 | wrapFixedSticky: true, 40 | absoluteClass: 'is-absolute', 41 | 42 | scrollClass: { 43 | down: null, 44 | up: null, 45 | none: null, 46 | persist: false, 47 | active: false 48 | } 49 | }; 50 | 51 | var initialState = { 52 | sticky: false, 53 | absolute: false, 54 | fixedOffset: '', 55 | offsetHeight: 0, 56 | bounds: { 57 | top: null, 58 | left: null, 59 | right: null, 60 | bottom: null, 61 | height: null, 62 | width: null 63 | }, 64 | restrict: { 65 | top: null, 66 | left: null, 67 | right: null, 68 | bottom: null, 69 | height: null, 70 | width: null 71 | }, 72 | wrapperStyle: null, 73 | elementStyle: null, 74 | initialStyle: null, 75 | style: { 76 | top: null, 77 | bottom: null, 78 | left: null, 79 | right: null, 80 | 'margin-top': 0, 81 | 'margin-bottom': 0, 82 | 'margin-left': 0, 83 | 'margin-right': 0 84 | }, 85 | disabled: false 86 | }; 87 | 88 | var getAbsolutBoundingRect = function getAbsolutBoundingRect(el, fixedHeight) { 89 | var rect = el.getBoundingClientRect(); 90 | var top = rect.top + _scrollfeatures2.default.windowY; 91 | var height = fixedHeight || rect.height; 92 | return { 93 | top: top, 94 | bottom: top + height, 95 | height: height, 96 | width: rect.width, 97 | left: rect.left, 98 | right: rect.right 99 | }; 100 | }; 101 | 102 | var addBounds = function addBounds(rect1, rect2) { 103 | var rect = (0, _objectAssign2.default)({}, rect1); 104 | rect.top -= rect2.top; 105 | rect.left -= rect2.left; 106 | rect.right = rect.left + rect1.width; 107 | rect.bottom = rect.top + rect1.height; 108 | return rect; 109 | }; 110 | 111 | var getPositionStyle = function getPositionStyle(el) { 112 | 113 | var result = {}; 114 | var style = window.getComputedStyle(el, null); 115 | 116 | for (var key in initialState.style) { 117 | var value = parseInt(style.getPropertyValue(key)); 118 | value = isNaN(value) ? null : value; 119 | result[key] = value; 120 | } 121 | 122 | return result; 123 | }; 124 | 125 | var getPreviousElementSibling = function getPreviousElementSibling(el) { 126 | var prev = el.previousElementSibling; 127 | if (prev && prev.tagName.toLocaleLowerCase() === 'script') { 128 | prev = getPreviousElementSibling(prev); 129 | } 130 | return prev; 131 | }; 132 | 133 | var StickyState = function (_EventDispatcher) { 134 | _inherits(StickyState, _EventDispatcher); 135 | 136 | function StickyState(element, options) { 137 | _classCallCheck(this, StickyState); 138 | 139 | var elements; 140 | if (element instanceof window.NodeList) { 141 | elements = [].slice.call(element, 1); 142 | element = element[0]; 143 | } 144 | 145 | var _this = _possibleConstructorReturn(this, _EventDispatcher.call(this, { target: element })); 146 | 147 | _this.el = null; 148 | _this.firstRender = true; 149 | _this.scroll = null; 150 | _this.wrapper = null; 151 | _this.options = null; 152 | 153 | 154 | _this.el = element; 155 | 156 | if (options && options.scrollClass) { 157 | options.scrollClass = (0, _objectAssign2.default)({}, defaults.scrollClass, options.scrollClass, { active: true }); 158 | } 159 | _this.options = (0, _objectAssign2.default)({}, defaults, options); 160 | 161 | _this.setState((0, _objectAssign2.default)({}, initialState, { disabled: _this.options.disabled }), true); 162 | 163 | _this.scrollTarget = _scrollfeatures2.default.getScrollParent(_this.el); 164 | _this.hasOwnScrollTarget = _this.scrollTarget !== window; 165 | if (_this.hasOwnScrollTarget) { 166 | _this.updateFixedOffset = _this.updateFixedOffset.bind(_this); 167 | } 168 | 169 | _this.render = _this.render.bind(_this); 170 | _this.addSrollHandler(); 171 | _this.addResizeHandler(); 172 | _this.render(); 173 | 174 | if (elements && elements.length) { 175 | var _ret; 176 | 177 | var collection = StickyState.apply(elements, options); 178 | collection.push(_this); 179 | return _ret = collection, _possibleConstructorReturn(_this, _ret); 180 | } 181 | return _this; 182 | } 183 | 184 | StickyState.apply = function apply(elements, options) { 185 | 186 | if (elements && elements.length) { 187 | var arr = new StickyStateCollection(); 188 | for (var i = 0; i < elements.length; i++) { 189 | arr.push(new StickyState(elements[i], options)); 190 | } 191 | return arr; 192 | } 193 | 194 | return new StickyState(elements, options); 195 | }; 196 | 197 | StickyState.prototype.setState = function setState(newState, silent) { 198 | this.lastState = this.state || newState; 199 | this.state = (0, _objectAssign2.default)({}, this.state, newState); 200 | if (silent !== true) { 201 | this.render(); 202 | this.trigger(this.state.sticky ? 'sticky:on' : 'sticky:off'); 203 | } 204 | }; 205 | 206 | StickyState.prototype.disable = function disable(value) { 207 | this.setState({ disabled: value }, value); 208 | }; 209 | 210 | StickyState.prototype.getBoundingClientRect = function getBoundingClientRect() { 211 | return this.el.getBoundingClientRect(); 212 | }; 213 | 214 | StickyState.prototype.getBounds = function getBounds(noCache) { 215 | 216 | var clientRect = this.getBoundingClientRect(); 217 | var offsetHeight = _scrollfeatures2.default.documentHeight; 218 | noCache = noCache === true; 219 | 220 | if (noCache !== true && this.state.bounds.height !== null) { 221 | if (this.state.offsetHeight === offsetHeight && clientRect.height === this.state.bounds.height) { 222 | return { 223 | offsetHeight: offsetHeight, 224 | style: this.state.style, 225 | bounds: this.state.bounds, 226 | restrict: this.state.restrict 227 | }; 228 | } 229 | } 230 | 231 | // var style = noCache ? this.state.style : getPositionStyle(this.el); 232 | var initialStyle = this.state.initialStyle; 233 | if (!initialStyle) { 234 | initialStyle = getPositionStyle(this.el); 235 | } 236 | 237 | var style = initialStyle; 238 | var child = this.wrapper || this.el; 239 | var rect; 240 | var restrict; 241 | var offsetY = 0; 242 | var offsetX = 0; 243 | 244 | if (!Can.sticky) { 245 | rect = getAbsolutBoundingRect(child, clientRect.height); 246 | if (this.hasOwnScrollTarget) { 247 | var parentRect = getAbsolutBoundingRect(this.scrollTarget); 248 | offsetY = this.scroll.y; 249 | rect = addBounds(rect, parentRect); 250 | restrict = parentRect; 251 | restrict.top = 0; 252 | restrict.height = this.scroll.scrollHeight || restrict.height; 253 | restrict.bottom = restrict.height; 254 | } 255 | } else { 256 | var elem = getPreviousElementSibling(child); 257 | offsetY = 0; 258 | 259 | if (elem) { 260 | offsetY = parseInt(window.getComputedStyle(elem)['margin-bottom']); 261 | offsetY = offsetY || 0; 262 | rect = getAbsolutBoundingRect(elem); 263 | if (this.hasOwnScrollTarget) { 264 | rect = addBounds(rect, getAbsolutBoundingRect(this.scrollTarget)); 265 | offsetY += this.scroll.y; 266 | } 267 | rect.top = rect.bottom + offsetY; 268 | } else { 269 | elem = child.parentNode; 270 | offsetY = parseInt(window.getComputedStyle(elem)['padding-top']); 271 | offsetY = offsetY || 0; 272 | rect = getAbsolutBoundingRect(elem); 273 | if (this.hasOwnScrollTarget) { 274 | rect = addBounds(rect, getAbsolutBoundingRect(this.scrollTarget)); 275 | offsetY += this.scroll.y; 276 | } 277 | rect.top = rect.top + offsetY; 278 | } 279 | if (this.hasOwnScrollTarget) { 280 | restrict = getAbsolutBoundingRect(this.scrollTarget); 281 | restrict.top = 0; 282 | restrict.height = this.scroll.scrollHeight || restrict.height; 283 | restrict.bottom = restrict.height; 284 | } 285 | 286 | rect.height = child.clientHeight; 287 | rect.width = child.clientWidth; 288 | rect.bottom = rect.top + rect.height; 289 | } 290 | 291 | restrict = restrict || getAbsolutBoundingRect(child.parentNode); 292 | 293 | return { 294 | offsetHeight: offsetHeight, 295 | style: style, 296 | bounds: rect, 297 | initialStyle: initialStyle, 298 | restrict: restrict 299 | }; 300 | }; 301 | 302 | StickyState.prototype.updateBounds = function updateBounds(silent, noCache) { 303 | silent = silent === true; 304 | noCache = noCache === true; 305 | this.setState(this.getBounds(noCache), silent); 306 | }; 307 | 308 | StickyState.prototype.updateFixedOffset = function updateFixedOffset() { 309 | this.lastState.fixedOffset = this.state.fixedOffset; 310 | if (this.state.sticky) { 311 | this.state.fixedOffset = this.scrollTarget.getBoundingClientRect().top + 'px;'; 312 | } else { 313 | this.state.fixedOffset = ''; 314 | } 315 | if (this.lastState.fixedOffset !== this.state.fixedOffset) { 316 | this.render(); 317 | } 318 | }; 319 | 320 | StickyState.prototype.addSrollHandler = function addSrollHandler() { 321 | if (!this.scroll) { 322 | var hasScrollTarget = _scrollfeatures2.default.hasInstance(this.scrollTarget); 323 | this.scroll = _scrollfeatures2.default.getInstance(this.scrollTarget); 324 | this.onScroll = this.onScroll.bind(this); 325 | this.scroll.on('scroll:start', this.onScroll); 326 | this.scroll.on('scroll:progress', this.onScroll); 327 | this.scroll.on('scroll:stop', this.onScroll); 328 | 329 | if (this.options.scrollClass.active) { 330 | this.onScrollDirection = this.onScrollDirection.bind(this); 331 | this.scroll.on('scroll:up', this.onScrollDirection); 332 | this.scroll.on('scroll:down', this.onScrollDirection); 333 | if (!this.options.scrollClass.persist) { 334 | this.scroll.on('scroll:stop', this.onScrollDirection); 335 | } 336 | } 337 | if (hasScrollTarget && this.scroll.scrollY > 0) { 338 | this.scroll.trigger('scroll:progress'); 339 | } 340 | } 341 | }; 342 | 343 | StickyState.prototype.removeSrollHandler = function removeSrollHandler() { 344 | if (this.scroll) { 345 | this.scroll.off('scroll:start', this.onScroll); 346 | this.scroll.off('scroll:progress', this.onScroll); 347 | this.scroll.off('scroll:stop', this.onScroll); 348 | if (this.options.scrollClass.active) { 349 | this.scroll.off('scroll:up', this.onScrollDirection); 350 | this.scroll.off('scroll:down', this.onScrollDirection); 351 | this.scroll.off('scroll:stop', this.onScrollDirection); 352 | } 353 | if (!this.scroll.hasListeners()) { 354 | this.scroll.destroy(); 355 | } 356 | this.onScroll = null; 357 | this.onScrollDirection = null; 358 | this.scroll = null; 359 | } 360 | }; 361 | 362 | StickyState.prototype.addResizeHandler = function addResizeHandler() { 363 | if (!this.onResize) { 364 | this.onResize = this.update.bind(this); 365 | window.addEventListener('sticky:update', this.onResize, false); 366 | window.addEventListener('resize', this.onResize, false); 367 | window.addEventListener('orientationchange', this.onResize, false); 368 | } 369 | }; 370 | 371 | StickyState.prototype.removeResizeHandler = function removeResizeHandler() { 372 | if (this.onResize) { 373 | window.removeEventListener('sticky:update', this.onResize); 374 | window.removeEventListener('resize', this.onResize); 375 | window.removeEventListener('orientationchange', this.onResize); 376 | this.onResize = null; 377 | } 378 | }; 379 | 380 | StickyState.prototype.destroy = function destroy() { 381 | _EventDispatcher.prototype.destroy.call(this); 382 | this.removeSrollHandler(); 383 | this.removeResizeHandler(); 384 | this.render = null; 385 | this.el = null; 386 | this.state = null; 387 | this.wrapper = null; 388 | }; 389 | 390 | StickyState.prototype.getScrollClasses = function getScrollClasses(obj) { 391 | if (this.options.scrollClass.active) { 392 | obj = obj || {}; 393 | var direction = this.scroll.y <= 0 || this.scroll.y + this.scroll.clientHeight >= this.scroll.scrollHeight ? 0 : this.scroll.directionY; 394 | obj[this.options.scrollClass.up] = direction < 0; 395 | obj[this.options.scrollClass.down] = direction > 0; 396 | } 397 | return obj; 398 | }; 399 | 400 | StickyState.prototype.onScrollDirection = function onScrollDirection(e) { 401 | if (this.state.sticky || e.type === _scrollfeatures2.default.events.SCROLL_STOP) { 402 | this.el.className = (0, _classstring2.default)(this.el.className, this.getScrollClasses()); 403 | } 404 | }; 405 | 406 | StickyState.prototype.onScroll = function onScroll(e) { 407 | this.updateStickyState(false); 408 | if (this.hasOwnScrollTarget && !Can.sticky) { 409 | this.updateFixedOffset(); 410 | if (this.state.sticky && !this.hasWindowScrollListener) { 411 | this.hasWindowScrollListener = true; 412 | _scrollfeatures2.default.getInstance(window).on('scroll:progress', this.updateFixedOffset); 413 | } else if (!this.state.sticky && this.hasWindowScrollListener) { 414 | this.hasWindowScrollListener = false; 415 | _scrollfeatures2.default.getInstance(window).off('scroll:progress', this.updateFixedOffset); 416 | } 417 | } 418 | }; 419 | 420 | StickyState.prototype.update = function update() { 421 | this.scroll.updateScrollPosition(); 422 | this.updateBounds(true, true); 423 | this.updateStickyState(false); 424 | }; 425 | 426 | StickyState.prototype.getStickyState = function getStickyState() { 427 | 428 | if (this.state.disabled) { 429 | return { sticky: false, absolute: false }; 430 | } 431 | 432 | var scrollY = this.scroll.y; 433 | var scrollX = this.scroll.x; 434 | var top = this.state.style.top; 435 | var bottom = this.state.style.bottom; 436 | // var left = this.state.style.left; 437 | // var right = this.state.style.right; 438 | var sticky = this.state.sticky; 439 | var absolute = this.state.absolute; 440 | 441 | if (top !== null) { 442 | var offsetBottom = this.state.restrict.bottom - this.state.bounds.height - top; 443 | top = this.state.bounds.top - top; 444 | 445 | if (this.state.sticky === false && (scrollY >= top && scrollY <= offsetBottom || top <= 0 && scrollY < top)) { 446 | sticky = true; 447 | absolute = false; 448 | } else if (this.state.sticky && (top > 0 && scrollY < top || scrollY > offsetBottom)) { 449 | sticky = false; 450 | absolute = scrollY > offsetBottom; 451 | } 452 | } else if (bottom !== null) { 453 | 454 | scrollY += window.innerHeight; 455 | var offsetTop = this.state.restrict.top + this.state.bounds.height - bottom; 456 | bottom = this.state.bounds.bottom + bottom; 457 | 458 | if (this.state.sticky === false && scrollY <= bottom && scrollY >= offsetTop) { 459 | sticky = true; 460 | absolute = false; 461 | } else if (this.state.sticky && (scrollY > bottom || scrollY < offsetTop)) { 462 | sticky = false; 463 | absolute = scrollY <= offsetTop; 464 | } 465 | } 466 | return { sticky: sticky, absolute: absolute }; 467 | }; 468 | 469 | StickyState.prototype.updateStickyState = function updateStickyState(silent) { 470 | var values = this.getStickyState(); 471 | 472 | if (values.sticky !== this.state.sticky || values.absolute !== this.state.absolute) { 473 | silent = silent === true; 474 | values = (0, _objectAssign2.default)(values, this.getBounds()); 475 | this.setState(values, silent); 476 | } 477 | }; 478 | 479 | StickyState.prototype.render = function render() { 480 | 481 | if (this.state.disabled) { 482 | return; 483 | } 484 | 485 | var classNameObj = {}; 486 | 487 | if (this.firstRender) { 488 | this.firstRender = false; 489 | 490 | if (!Can.sticky) { 491 | this.wrapper = document.createElement('div'); 492 | this.wrapper.className = this.options.wrapperClass; 493 | var parent = this.el.parentNode; 494 | if (parent) { 495 | parent.insertBefore(this.wrapper, this.el); 496 | } 497 | if (this.options.wrapFixedSticky) { 498 | this.wrapper.appendChild(this.el); 499 | } 500 | classNameObj[this.options.fixedClass] = true; 501 | } 502 | 503 | this.updateBounds(true, true); 504 | this.updateStickyState(true); 505 | } 506 | 507 | if (!Can.sticky) { 508 | var elementStyle = ''; 509 | var height = this.state.disabled || this.state.bounds.height === null || !this.state.sticky && !this.state.absolute ? 'auto;' : this.state.bounds.height + 'px;'; 510 | var wrapperStyle = 'height:' + height; 511 | wrapperStyle += height === 'auto;' ? '' : (this.state.style['margin-top'] ? 'margin-top:' + this.state.style['margin-top'] + 'px;' : '0;') + (this.state.style['margin-bottom'] ? 'margin-bottom' + this.state.style['margin-bottom'] + 'px;' : '0;'); 512 | 513 | if (this.state.absolute !== this.lastState.absolute) { 514 | wrapperStyle += this.state.absolute ? 'position:relative;' : ''; 515 | classNameObj[this.options.absoluteClass] = this.state.absolute; 516 | elementStyle += this.state.absolute ? this.state.style.top !== null ? 'margin-top:' + (this.state.restrict.height - (this.state.bounds.height + this.state.style.top) + (this.state.restrict.top - this.state.bounds.top)) + 'px;' : 'margin-top:0;' + (this.state.style.bottom !== null ? 'margin-bottom:' + (this.state.restrict.height - (this.state.bounds.height + this.state.style.bottom) + (this.state.restrict.bottom - this.state.bounds.bottom)) + 'px;' : 'margin-bottom:0;') : 'margin-bottom:0;margin-top:0;'; 517 | } 518 | 519 | if ((this.state.style.top !== null || this.state.style.bottom !== null) && this.hasOwnScrollTarget && !this.state.absolute && this.lastState.fixedOffset !== this.state.fixedOffset) { 520 | elementStyle += 'margin-top:' + (this.state.fixedOffset ? this.state.fixedOffset : '0;'); 521 | } 522 | 523 | if (this.state.wrapperStyle !== wrapperStyle) { 524 | this.state.wrapperStyle = wrapperStyle; 525 | this.wrapper.style.cssText += wrapperStyle; 526 | } 527 | 528 | if (this.state.elementStyle !== elementStyle) { 529 | this.state.elementStyle = elementStyle; 530 | this.el.style.cssText += elementStyle; 531 | } 532 | } 533 | 534 | classNameObj[this.options.stateClassName] = this.state.sticky; 535 | classNameObj = this.getScrollClasses(classNameObj); 536 | var className = (0, _classstring2.default)(this.el.className, classNameObj); 537 | 538 | if (this.el.className !== className) { 539 | this.el.className = className; 540 | } 541 | 542 | return this.el; 543 | }; 544 | 545 | _createClass(StickyState, null, [{ 546 | key: 'native', 547 | get: function get() { 548 | return Can.sticky; 549 | } 550 | }]); 551 | 552 | return StickyState; 553 | }(_eventdispatcher2.default); 554 | 555 | var _canSticky = null; 556 | 557 | var Can = function () { 558 | function Can() { 559 | _classCallCheck(this, Can); 560 | } 561 | 562 | _createClass(Can, null, [{ 563 | key: 'sticky', 564 | get: function get() { 565 | if (_canSticky !== null) { 566 | return _canSticky; 567 | } 568 | if (typeof window !== 'undefined') { 569 | 570 | if (window.Modernizr && window.Modernizr.hasOwnProperty('csspositionsticky')) { 571 | return _canSticky = window.Modernizr.csspositionsticky; 572 | } 573 | 574 | var documentFragment = document.documentElement; 575 | var testEl = document.createElement('div'); 576 | documentFragment.appendChild(testEl); 577 | var prefixedSticky = ['sticky', '-webkit-sticky']; 578 | 579 | _canSticky = false; 580 | 581 | for (var i = 0; i < prefixedSticky.length; i++) { 582 | testEl.style.position = prefixedSticky[i]; 583 | _canSticky = !!window.getComputedStyle(testEl).position.match('sticky'); 584 | if (_canSticky) { 585 | break; 586 | } 587 | } 588 | documentFragment.removeChild(testEl); 589 | } 590 | return _canSticky; 591 | } 592 | }]); 593 | 594 | return Can; 595 | }(); 596 | 597 | var StickyStateCollection = function (_EventDispatcher2) { 598 | _inherits(StickyStateCollection, _EventDispatcher2); 599 | 600 | function StickyStateCollection() { 601 | _classCallCheck(this, StickyStateCollection); 602 | 603 | var _this2 = _possibleConstructorReturn(this, _EventDispatcher2.call(this)); 604 | 605 | _this2.items = []; 606 | return _this2; 607 | } 608 | 609 | StickyStateCollection.prototype.push = function push(item) { 610 | this.items.push(item); 611 | }; 612 | 613 | StickyStateCollection.prototype.update = function update() { 614 | var i = -1; 615 | while (++i < this.items.length) { 616 | this.items[i].update(); 617 | } 618 | }; 619 | 620 | StickyStateCollection.prototype.addListener = function addListener(event, listener) { 621 | 622 | var i = -1; 623 | while (++i < this.items.length) { 624 | this.items[i].addListener(event, listener); 625 | } 626 | return this; 627 | }; 628 | 629 | StickyStateCollection.prototype.removeListener = function removeListener(event, listener) { 630 | var i = -1; 631 | while (++i < this.items.length) { 632 | this.items[i].removeListener(event, listener); 633 | } 634 | return this; 635 | }; 636 | 637 | return StickyStateCollection; 638 | }(_eventdispatcher2.default); 639 | 640 | exports.default = StickyState; 641 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/sticky-state.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * sticky-state 2.4.1 - StickyState is a high performant module making native position:sticky statefull and polyfill the missing sticky browser feature 3 | * Copyright (c) 2016 Sönke Kluth (http://soenkekluth.com/) - https://github.com/soenkekluth/sticky-state#readme 4 | * License: MIT 5 | */ 6 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.StickyState=e():t.StickyState=e()}(this,function(){return function(t){function e(s){if(i[s])return i[s].exports;var n=i[s]={exports:{},id:s,loaded:!1};return t[s].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){t.exports=i(2)},function(t,e){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t){return!t||0===Object.keys(t).length}Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=e.target,n=e.currentTarget;i(this,t),this.target=s||this,this.currentTarget=n||this,this.eventMap={},this.destroyed=!1,this.on=this.bind=this.addEventListener=this.addListener,this.off=this.unbind=this.removeEventListener=this.removeListener,this.once=this.one=this.addListenerOnce,this.emit=this.trigger=this.dispatchEvent=this.dispatch}return t.prototype.addListener=function(t,e){var i=this.getListener(t);return i?i.indexOf(e)===-1&&i.push(e):this.eventMap[t]=[e],this},t.prototype.addListenerOnce=function(t,e){var i=this,s=function s(n){e(n),i.off(t,s)};return this.on(t,s)},t.prototype.removeListener=function(t,e){if(!e)return this.removeAllListener(t);var i=this.getListener(t);if(i){var s=i.indexOf(e);s>-1&&(i.splice(s,1),i.length||delete this.eventMap[t])}return this},t.prototype.removeAllListener=function(t){var e=this.getListener(t);return e&&(this.eventMap[t].length=0,delete this.eventMap[t]),this},t.prototype.hasListener=function(t){return null!==this.getListener(t)},t.prototype.hasListeners=function(){return null!==this.eventMap&&void 0!==this.eventMap&&!s(this.eventMap)},t.prototype.dispatch=function(t,e){var i=this.getListener(t);if(i){var s=e||{};s.type=t,s.target=s.target||this.target,s.currentTarget=s.currentTarget||this.currentTarget;for(var n=-1;++n0&&this.scroll.trigger("scroll:progress")}},e.prototype.removeSrollHandler=function(){this.scroll&&(this.scroll.off("scroll:start",this.onScroll),this.scroll.off("scroll:progress",this.onScroll),this.scroll.off("scroll:stop",this.onScroll),this.options.scrollClass.active&&(this.scroll.off("scroll:up",this.onScrollDirection),this.scroll.off("scroll:down",this.onScrollDirection),this.scroll.off("scroll:stop",this.onScrollDirection)),this.scroll.hasListeners()||this.scroll.destroy(),this.onScroll=null,this.onScrollDirection=null,this.scroll=null)},e.prototype.addResizeHandler=function(){this.onResize||(this.onResize=this.update.bind(this),window.addEventListener("sticky:update",this.onResize,!1),window.addEventListener("resize",this.onResize,!1),window.addEventListener("orientationchange",this.onResize,!1))},e.prototype.removeResizeHandler=function(){this.onResize&&(window.removeEventListener("sticky:update",this.onResize),window.removeEventListener("resize",this.onResize),window.removeEventListener("orientationchange",this.onResize),this.onResize=null)},e.prototype.destroy=function(){t.prototype.destroy.call(this),this.removeSrollHandler(),this.removeResizeHandler(),this.render=null,this.el=null,this.state=null,this.wrapper=null},e.prototype.getScrollClasses=function(t){if(this.options.scrollClass.active){t=t||{};var e=this.scroll.y<=0||this.scroll.y+this.scroll.clientHeight>=this.scroll.scrollHeight?0:this.scroll.directionY;t[this.options.scrollClass.up]=e<0,t[this.options.scrollClass.down]=e>0}return t},e.prototype.onScrollDirection=function(t){(this.state.sticky||t.type===g.default.events.SCROLL_STOP)&&(this.el.className=(0,u.default)(this.el.className,this.getScrollClasses()))},e.prototype.onScroll=function(t){this.updateStickyState(!1),this.hasOwnScrollTarget&&!x.sticky&&(this.updateFixedOffset(),this.state.sticky&&!this.hasWindowScrollListener?(this.hasWindowScrollListener=!0,g.default.getInstance(window).on("scroll:progress",this.updateFixedOffset)):!this.state.sticky&&this.hasWindowScrollListener&&(this.hasWindowScrollListener=!1,g.default.getInstance(window).off("scroll:progress",this.updateFixedOffset)))},e.prototype.update=function(){this.scroll.updateScrollPosition(),this.updateBounds(!0,!0),this.updateStickyState(!1)},e.prototype.getStickyState=function(){if(this.state.disabled)return{sticky:!1,absolute:!1};var t=this.scroll.y,e=(this.scroll.x,this.state.style.top),i=this.state.style.bottom,s=this.state.sticky,n=this.state.absolute;if(null!==e){var o=this.state.restrict.bottom-this.state.bounds.height-e;e=this.state.bounds.top-e,this.state.sticky===!1&&(t>=e&&t<=o||e<=0&&t0&&to)&&(s=!1,n=t>o)}else if(null!==i){t+=window.innerHeight;var r=this.state.restrict.top+this.state.bounds.height-i;i=this.state.bounds.bottom+i,this.state.sticky===!1&&t<=i&&t>=r?(s=!0,n=!1):this.state.sticky&&(t>i||t-1&&s.splice(h,1)}}return s}function s(){return i.apply(null,arguments).join(" ")}var n={}.hasOwnProperty;t.exports=s},function(t,e){"use strict";function i(t){if(null===t||void 0===t)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}function s(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de","5"===Object.getOwnPropertyNames(t)[0])return!1;for(var e={},i=0;i<10;i++)e["_"+String.fromCharCode(i)]=i;var s=Object.getOwnPropertyNames(e).map(function(t){return e[t]});if("0123456789"!==s.join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach(function(t){n[t]=t}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(t){return!1}}var n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable;t.exports=s()?Object.assign:function(t,e){for(var s,r,l=i(t),a=1;a0&&void 0!==arguments[0]?arguments[0]:window,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(n(this,e),e.hasInstance(i)){var r;return r=e.getInstance(i),o(l,r)}var l=o(this,t.call(this,{target:i}));return l._scrollTarget=null,l._y=0,l._x=0,l._speedY=0,l._speedX=0,l._lastSpeed=0,l._lastDirectionY=e.direction.none,l._lastDirectionX=e.direction.none,l._stopFrames=3,l._currentStopFrames=0,l._firstRender=!0,l._directionY=e.direction.none,l._directionX=e.direction.none,l._scrolling=!1,l._canScrollY=!1,l._canScrollX=!1,i.scrollFeatures=l,l._scrollTarget=i,l.options=s,g.animationFrame&&d(),l.init(),l}return r(e,t),e.getInstance=function(t,i){return t.scrollFeatures?t.scrollFeatures:new e(t,i)},e.hasInstance=function(t){return"undefined"!=typeof t.scrollFeatures},e.getScrollParent=function(t){return(0,u.default)(t)},l(e,null,[{key:"windowY",get:function(){return window.pageYOffset||window.scrollY||0}},{key:"windowX",get:function(){return window.pageXOffset||window.scrollX||0}},{key:"documentHeight",get:function(){return Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.scrollHeight,document.documentElement.offsetHeight)}},{key:"documentWidth",get:function(){return Math.max(document.body.scrollWidth,document.body.offsetWidth,document.documentElement.clientWidth,document.documentElement.scrollWidth,document.documentElement.offsetWidth)}}]),e.prototype.init=function(){var t=this;if(this.getScrollPosition=this._scrollTarget===window?function(){return{y:e.windowY,x:e.windowX}}.bind(this):function(){return{y:this._scrollTarget.scrollTop,x:this._scrollTarget.scrollLeft}}.bind(this),this.onResize=function(){t.trigger(e.events.SCROLL_RESIZE)},this.onScroll=this.onScroll.bind(this),this.onNextFrame=this.onNextFrame.bind(this),this.updateScrollPosition(),this._scrollTarget!==window){var i=/(auto|scroll)/,s=window.getComputedStyle(this._scrollTarget,null);this._canScrollY=i.test(s.getPropertyValue("overflow-y")),this._canScrollX=i.test(s.getPropertyValue("overflow-x"))}else this._canScrollY=this.clientHeight1||this.x>1)?(this.updateScrollPosition(),void this.trigger(e.events.SCROLL_PROGRESS)):void(this._scrolling||(this._scrolling=!0,this._lastDirectionY=e.direction.none,this._lastDirectionX=e.direction.none,this.trigger(e.events.SCROLL_START),g.animationFrame?this.nextFrameID=window.requestAnimationFrame(this.onNextFrame):this.onNextFrame()))},e.prototype.onNextFrame=function(){var t=this;this._speedY=this._y-this.y,this._speedX=this._x-this.x;var i=+this.speedY+ +this.speedX;return this._scrolling&&0===i&&this._currentStopFrames++>this._stopFrames?void this.onScrollStop():(this.updateScrollPosition(),this._lastDirectionY!==this.directionY&&this.trigger("scroll:"+(this.directionY===e.direction.down?"down":"up")),this._lastDirectionX!==this.directionX&&this.trigger("scroll:"+(this.directionX===e.direction.right?"right":"left")),this._lastDirectionY=this.directionY,this._lastDirectionX=this.directionX,this.trigger(e.events.SCROLL_PROGRESS),void(g.animationFrame?this.nextFrameID=window.requestAnimationFrame(this.onNextFrame):this._nextTimeout=setTimeout(function(){t.onNextFrame()},1e3/60)))},e.prototype.onScrollStop=function(){this._scrolling=!1,this.updateScrollPosition(),this.trigger(e.events.SCROLL_STOP),this._canScrollY&&(this.y<=0?this.trigger(e.events.SCROLL_MIN):this.y+this.clientHeight>=this.scrollHeight&&this.trigger(e.events.SCROLL_MAX)),this._canScrollX&&(this.x<=0?this.trigger(e.events.SCROLL_MIN):this.x+this.clientWidth>=this.scrollWidth&&this.trigger(e.events.SCROLL_MAX)),this._cancelNextFrame()},e.prototype._cancelNextFrame=function(){this._currentStopFrames=0,g.animationFrame?(window.cancelAnimationFrame(this.nextFrameID),this.nextFrameID=-1):clearTimeout(this._nextTimeout)},l(e,[{key:"scrollPosition",get:function(){return this.getScrollPosition()}},{key:"directionY",get:function(){return!this._canScrollY||0===this.speedY&&!this._scrolling?this._directionY=e.direction.none:this.speedY>0?this._directionY=e.direction.up:this.speedY<0&&(this._directionY=e.direction.down),this._directionY}},{key:"directionX",get:function(){return!this._canScrollX||0===this.speedX&&!this._scrolling?this._directionX=e.direction.none:this.speedX>0?this._directionX=e.direction.left:this.speedX<0&&(this._directionX=e.direction.right),this._directionX}},{key:"scrollTarget",get:function(){return this._scrollTarget}},{key:"scrolling",get:function(){return this._scrolling}},{key:"speedY",get:function(){return this._speedY}},{key:"speedX",get:function(){return this._speedX}},{key:"canScrollY",get:function(){return this._canScrollY}},{key:"canScrollX",get:function(){return this._canScrollX}},{key:"y",get:function(){return this.scrollPosition.y}},{key:"x",get:function(){return this.scrollPosition.x}},{key:"clientHeight",get:function(){return this._scrollTarget===window?window.innerHeight:this._scrollTarget.clientHeight}},{key:"clientWidth",get:function(){return this._scrollTarget===window?window.innerWidth:this._scrollTarget.clientWidth}},{key:"scrollHeight",get:function(){return this._scrollTarget===window?e.documentHeight:this._scrollTarget.scrollHeight}},{key:"scrollWidth",get:function(){return this._scrollTarget===window?e.documentWidth:this._scrollTarget.scrollWidth}}]),e}(c.default);p.direction={up:-1,down:1,none:0,right:2,left:-2},p.events={SCROLL_PROGRESS:"scroll:progress",SCROLL_START:"scroll:start",SCROLL_STOP:"scroll:stop",SCROLL_DOWN:"scroll:down",SCROLL_UP:"scroll:up",SCROLL_MIN:"scroll:min",SCROLL_MAX:"scroll:max",SCROLL_RESIZE:"scroll:resize"},e.default=p;var f=null,g=function(){function t(){n(this,t)}return l(t,null,[{key:"animationFrame",get:function(){return null===f&&(f=!!(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame)),f}}]),t}();t.exports=e.default}])}); -------------------------------------------------------------------------------- /examples/headroom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | stickystate headroom 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Hello World

17 |
18 |
19 | 20 |
21 | 22 |
23 | 24 |

Lorem

25 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

26 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

27 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

28 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

29 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

30 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

31 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

32 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

33 |
34 |
35 | 36 | 37 | 38 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /examples/horizontal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | stickystate headroom 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Hello World

17 |
18 |
19 | 20 |
21 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

22 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

23 |

scroll horizontal

24 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

25 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

26 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

27 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

28 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

29 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

30 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

31 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

32 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

33 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

34 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

35 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

36 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

37 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

38 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

39 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

40 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

41 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

42 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

43 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

44 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

45 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

46 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

47 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

48 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

49 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

50 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

51 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

52 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

53 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

54 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

55 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

56 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

57 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis cum dicta a, incidunt facilis eos asperiores, ducimus fuga rerum vitae architecto provident dolorem saepe atque nisi at quam harum debitis soluta eveniet inventore quo quasi ullam! Provident quas id, rem commodi tempore nostrum quis unde repellendus eius praesentium, omnis placeat? Dolor omnis, excepturi quidem sunt officia veniam doloremque accusantium laudantium.

58 |
59 | 60 | 61 | 62 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | StickyState 7 | 8 | 9 | 10 | 11 | 12 |
13 |

StickyState

14 | 15 |

A test page for the StickyState project

16 |

markup and styles of this document are mostly copied from filamentgroup

17 | 18 |
19 |
20 | Fixed to viewport top A. 21 |
state:
22 |
scrolling:
23 |
24 |
25 |
26 |
27 |
28 |
29 | spacer for resize testing 30 |
31 |
32 |
33 |
34 |
35 |
36 |

scroll horizontal

37 |
38 |
39 | 40 | 41 | 42 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga ut, maxime reiciendis ab pariatur eaque, suscipit esse tempora nesciunt atque assumenda a, consequatur ex et illo qui accusamus facere quis ipsam tenetur. Eaque molestias quo laudantium odio! Velit nobis, consequatur.

43 | 44 |
45 | Fixed to viewport top
with margin-top 46 |
state:
47 |
scrolling:
48 |
49 | 50 |

And now, some fake content to allow scrolling...

51 | 52 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

53 | 54 |

Header Level 2

55 | 56 |
    57 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 58 |
  3. Aliquam tincidunt mauris eu risus.
  4. 59 |
60 | 61 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

62 | 63 |

Header Level 3

64 | 65 |
    66 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 67 |
  • Aliquam tincidunt mauris eu risus.
  • 68 |
69 | 70 | 71 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

72 | 73 |

Header Level 2

74 | 75 |
    76 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 77 |
  3. Aliquam tincidunt mauris eu risus.
  4. 78 |
79 | 80 |
81 | Fixed to viewport bottom B (1em above). 82 |
state:
83 |
scroll:
84 |
85 |
86 |
87 |
88 | Fixed to viewport bottom A. 89 |
state:
90 |
scroll:
91 |
92 |
93 | 94 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

95 | 96 |

Header Level 3

97 | 98 |
    99 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 100 |
  • Aliquam tincidunt mauris eu risus.
  • 101 |
102 | 103 |

Sticky with overflow

104 |

fully supported. native and polyfilled

105 | 106 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

107 | 108 |
109 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

110 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

111 |
112 | Fixed to overflow div top. 113 |
state:
114 |
scrolling:
115 |
116 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

117 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

118 |
119 |
120 | 121 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

122 | 123 |

Header Level 2

124 | 125 |
    126 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 127 |
  3. Aliquam tincidunt mauris eu risus.
  4. 128 |
129 | 130 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

131 | 132 |

Header Level 3

133 | 134 |
    135 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 136 |
  • Aliquam tincidunt mauris eu risus.
  • 137 |
138 | 139 | 140 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

141 | 142 |

Header Level 2

143 | 144 |
    145 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 146 |
  3. Aliquam tincidunt mauris eu risus.
  4. 147 |
148 | 149 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

150 | 151 |

Header Level 3

152 | 153 |
    154 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 155 |
  • Aliquam tincidunt mauris eu risus.
  • 156 |
157 | 158 | 159 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

160 | 161 |

Header Level 2

162 | 163 |
    164 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 165 |
  3. Aliquam tincidunt mauris eu risus.
  4. 166 |
167 | 168 |
169 | 170 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /examples/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | *, 8 | *:before, 9 | *:after { 10 | -webkit-box-sizing: inherit; 11 | -moz-box-sizing: inherit; 12 | box-sizing: inherit; 13 | } 14 | 15 | html, 16 | body { 17 | padding: 0; 18 | margin: 0; 19 | } 20 | 21 | 22 | /* Logo */ 23 | 24 | .header { 25 | background: #247201; 26 | } 27 | 28 | #fg-logo { 29 | text-indent: -9999px; 30 | margin: 0 auto; 31 | width: 287px; 32 | height: 52px; 33 | } 34 | 35 | @media (-webkit-min-device-pixel-ratio: 1.5), 36 | (min-device-pixel-ratio: 1.5) { 37 | #fg-logo { 38 | -o-background-size: 287px 52px; 39 | background-size: 287px 52px; 40 | } 41 | } 42 | 43 | 44 | /* Demo CSS */ 45 | 46 | body { 47 | font-family: sans-serif; 48 | color: #444; 49 | } 50 | 51 | .center { 52 | width: 100%; 53 | max-width: 600px; 54 | margin: 0 auto; 55 | padding: 0 30px; 56 | } 57 | 58 | .top, 59 | .bottom { 60 | text-align: center; 61 | border: solid black; 62 | border-width: 1px 0; 63 | padding: 1em; 64 | width: 100%; 65 | max-width: 540px; 66 | } 67 | 68 | .bottom .state, 69 | .top .state { 70 | margin-top: 0.5em; 71 | } 72 | 73 | .bottom .state::after, 74 | .top .state::after { 75 | content: "static"; 76 | font-weight: bold; 77 | } 78 | 79 | .bottom .scroll::after, 80 | .top .scroll::after { 81 | content: "none"; 82 | font-weight: bold; 83 | } 84 | 85 | .bottom.is-sticky .state::after, 86 | .top.is-sticky .state::after { 87 | content: "is-sticky"; 88 | } 89 | 90 | .bottom.sticky-scroll-down.is-sticky .scroll::after, 91 | .top.sticky-scroll-down.is-sticky .scroll::after { 92 | content: "down"; 93 | } 94 | 95 | .bottom.sticky-scroll-up.is-sticky .scroll::after, 96 | .top.sticky-scroll-up.is-sticky .scroll::after { 97 | content: "up"; 98 | } 99 | 100 | .top { 101 | top: 0; 102 | } 103 | 104 | .bottom { 105 | bottom: 0; 106 | } 107 | 108 | #top-a { 109 | top: 32px; 110 | } 111 | 112 | #top-b { 113 | margin-top: 32px; 114 | } 115 | 116 | #bottom-b { 117 | bottom: 16px; 118 | } 119 | 120 | 121 | /* Demo Colors */ 122 | 123 | #top-a, 124 | #bottom-a { 125 | background-color: #f00; 126 | background-color: rgba(255, 0, 0, .6); 127 | } 128 | 129 | #top-b, 130 | #bottom-b { 131 | background-color: #0f0; 132 | background-color: rgba(0, 255, 0, .6); 133 | } 134 | 135 | .container { 136 | background-color: #999; 137 | } 138 | 139 | .headroom { 140 | top: 0; 141 | width: 100%; 142 | background-color: rgba(0, 0, 0, 0.8); 143 | padding-top: 20px; 144 | padding-bottom: 20px; 145 | -webkit-transition: -webkit-transform 240ms ease-in-out; 146 | transition: -webkit-transform 240ms ease-in-out; 147 | -o-transition: -o-transform 240ms ease-in-out; 148 | -moz-transition: transform 240ms ease-in-out, -moz-transform 240ms ease-in-out; 149 | transition: transform 240ms ease-in-out; 150 | transition: transform 240ms ease-in-out, -webkit-transform 240ms ease-in-out, -moz-transform 240ms ease-in-out, -o-transform 240ms ease-in-out; 151 | } 152 | 153 | .headroom h1 { 154 | margin: 0; 155 | color: white; 156 | } 157 | 158 | .headroom.is-sticky.headroom-scroll-down { 159 | -webkit-transition-delay: 400ms; 160 | -moz-transition-delay: 400ms; 161 | -o-transition-delay: 400ms; 162 | transition-delay: 400ms; 163 | -webkit-transform: translateY(-100%); 164 | -moz-transform: translateY(-100%); 165 | -ms-transform: translateY(-100%); 166 | -o-transform: translateY(-100%); 167 | transform: translateY(-100%); 168 | } 169 | 170 | 171 | 172 | 173 | 174 | .overflow-x, 175 | .overflow-y, 176 | .overflow { 177 | display: block; 178 | 179 | 180 | width: 100%; 181 | // max-width: 300px; 182 | overflow: hidden; 183 | 184 | height: 300px; 185 | } 186 | 187 | .overflow-y { 188 | overflow-y: scroll; 189 | } 190 | 191 | .overflow-x { 192 | overflow-x: scroll; 193 | } 194 | 195 | 196 | .overflow-y .overflow-content{ 197 | height: 800px; 198 | background: -webkit-repeating-linear-gradient( 199 | top, 200 | #606dbc, 201 | #606dbc 10px, 202 | #ffffff 10px, 203 | #ffffff 20px 204 | ); 205 | background: -moz-repeating-linear-gradient( 206 | top, 207 | #606dbc, 208 | #606dbc 10px, 209 | #ffffff 10px, 210 | #ffffff 20px 211 | ); 212 | background: -o-repeating-linear-gradient( 213 | top, 214 | #606dbc, 215 | #606dbc 10px, 216 | #ffffff 10px, 217 | #ffffff 20px 218 | ); 219 | background: repeating-linear-gradient( 220 | 180deg, 221 | #606dbc, 222 | #606dbc 10px, 223 | #ffffff 10px, 224 | #ffffff 20px 225 | ); 226 | } 227 | 228 | .overflow-x .overflow-content{ 229 | width: 800px; 230 | height: 100%; 231 | background: -webkit-repeating-linear-gradient( 232 | left, 233 | #606dbc, 234 | #606dbc 10px, 235 | #ffffff 10px, 236 | #ffffff 20px 237 | ); 238 | background: -moz-repeating-linear-gradient( 239 | left, 240 | #606dbc, 241 | #606dbc 10px, 242 | #ffffff 10px, 243 | #ffffff 20px 244 | ); 245 | background: -o-repeating-linear-gradient( 246 | left, 247 | #606dbc, 248 | #606dbc 10px, 249 | #ffffff 10px, 250 | #ffffff 20px 251 | ); 252 | background: repeating-linear-gradient( 253 | 90deg, 254 | #606dbc, 255 | #606dbc 10px, 256 | #ffffff 10px, 257 | #ffffff 20px 258 | ); 259 | } 260 | 261 | 262 | 263 | .left-headline { 264 | background-color: #f00; 265 | background-color: rgba(255, 0, 0, .6); 266 | padding: 1em; 267 | display:inline-block; 268 | left:0px; 269 | margin-left: 2em; 270 | } 271 | 272 | /* 273 | #top-b{ 274 | margin-top: 20px; 275 | } 276 | */ 277 | -------------------------------------------------------------------------------- /examples/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | stickystate headroom 8 | 9 | 10 | 11 | 12 | 38 | 39 | 40 | 41 |
42 |
43 |

Hello World

44 |
45 | 46 |
47 |

I am Sticky

48 |
49 |
50 | 51 |
52 | 53 |
54 | 55 |

Lorem

56 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

57 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

58 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

59 |
60 | sticky 61 |
62 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

63 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

64 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

65 |
66 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

67 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

68 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

69 | 70 |
71 | sticky 72 |
73 |
74 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

75 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error neque, repellendus enim impedit non dolorum repudiandae. Explicabo vitae deleniti, reiciendis fugiat expedita iste, dolore necessitatibus, accusamus, iusto placeat optio aspernatur voluptatem nostrum porro consequuntur vero obcaecati. Dignissimos quod placeat aperiam molestias rerum veniam distinctio, repellendus at natus officia dolorem deleniti dolor praesentium odit eveniet minus totam non, fugiat excepturi officiis error ducimus magnam consectetur provident. Fugiat at laudantium repudiandae reiciendis cum mollitia temporibus necessitatibus aliquid, iure fugit id, eos tempore vero sapiente consequuntur nulla culpa nobis sint. Inventore est reiciendis, placeat, voluptas tempore dolorem provident hic ex soluta nulla error delectus, rerum perspiciatis id ab nostrum incidunt beatae voluptate blanditiis. Dolorum, recusandae, quisquam placeat earum pariatur fugit, dolores minus magnam iure nesciunt cumque voluptas optio sit est. Aliquam dolorum ex facilis, aspernatur voluptatibus officiis tempora culpa, libero distinctio, amet est qui illum pariatur soluta. Soluta aut consectetur sapiente nemo, placeat doloremque voluptas ullam ea, eos ut voluptatibus adipisci molestiae est labore quidem recusandae voluptate dolorum et, quae quibusdam architecto. Ratione provident et quidem praesentium impedit aut sequi veritatis, consectetur distinctio, consequuntur molestiae neque doloremque vel ipsa omnis dolore itaque officiis, architecto nobis. Cumque expedita laboriosam fuga quae! Asperiores temporibus, ea.

76 |
77 |
78 | 79 | 80 | 81 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sticky-state", 3 | "version": "2.4.1", 4 | "description": "StickyState is a high performant module making native position:sticky statefull and polyfill the missing sticky browser feature", 5 | "main": "dist/sticky-state.js", 6 | "jsnext:main": "src/sticky-state.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "watch-js": "NODE_ENV=development webpack -wd --config ./webpack.dev.js", 10 | "build": "NODE_ENV=production webpack -p --config ./webpack.prod.js && cp src/sticky-state.css dist/", 11 | "build:debug": "NODE_ENV=production webpack --config ./webpack.prod.js && cp src/sticky-state.css dist/", 12 | "dist": "npm run build && npm run build-lib", 13 | "start": "npm run build && run-p watch-js devserver", 14 | "build-lib": "BABEL_ENV=production babel src -d dist", 15 | "devserver": "webpack-dev-server --config ./webpack.dev.js" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/soenkekluth/sticky-state.git" 20 | }, 21 | "keywords": [ 22 | "position:sticky", 23 | "sticky", 24 | "polyfill", 25 | "state", 26 | "statefull", 27 | "performant", 28 | "position" 29 | ], 30 | "author": "Sönke Kluth (http://soenkekluth.com/)", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/soenkekluth/sticky-state/issues" 34 | }, 35 | "homepage": "https://github.com/soenkekluth/sticky-state#readme", 36 | "dependencies": { 37 | "classstring": "1.0.0", 38 | "eventdispatcher": "2.1.2", 39 | "object-assign": "4.1.0", 40 | "scrollfeatures": "1.5.0" 41 | }, 42 | "devDependencies": { 43 | "babel-cli": "6.18.0", 44 | "babel-core": "6.18.2", 45 | "babel-loader": "6.2.8", 46 | "babel-plugin-add-module-exports": "0.2.1", 47 | "babel-plugin-transform-class-constructor-call": "6.18.0", 48 | "babel-plugin-transform-class-properties": "6.19.0", 49 | "babel-plugin-transform-es2015-classes": "6.18.0", 50 | "babel-preset-es2015": "6.18.0", 51 | "jsdom": "9.8.3", 52 | "npm-run-all": "3.1.1", 53 | "webpack": "1.13.3", 54 | "webpack-dev-server": "1.16.2" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/sticky-state.css: -------------------------------------------------------------------------------- 1 | .sticky { 2 | position: -webkit-sticky; 3 | position: sticky; 4 | } 5 | 6 | .sticky.sticky-fixed.is-sticky { 7 | margin-top: 0; 8 | margin-bottom: 0; 9 | position: fixed; 10 | -webkit-backface-visibility: hidden; 11 | -moz-backface-visibility: hidden; 12 | backface-visibility: hidden; 13 | } 14 | 15 | .sticky.sticky-fixed.is-sticky:not([style*="margin-top"]) { 16 | margin-top: 0 !important; 17 | } 18 | .sticky.sticky-fixed.is-sticky:not([style*="margin-bottom"]) { 19 | margin-bottom: 0 !important; 20 | } 21 | 22 | 23 | .sticky.sticky-fixed.is-absolute{ 24 | position: absolute; 25 | } 26 | -------------------------------------------------------------------------------- /src/sticky-state.js: -------------------------------------------------------------------------------- 1 | import assign from 'object-assign'; 2 | import classString from 'classstring'; 3 | import EventDispatcher from 'eventdispatcher'; 4 | import ScrollFeatures from 'scrollfeatures'; 5 | 6 | const defaults = { 7 | disabled: false, 8 | className: 'sticky', 9 | stateClassName: 'is-sticky', 10 | fixedClass: 'sticky-fixed', 11 | wrapperClass: 'sticky-wrap', 12 | wrapFixedSticky: true, 13 | absoluteClass: 'is-absolute', 14 | 15 | scrollClass: { 16 | down: null, 17 | up: null, 18 | none: null, 19 | persist: false, 20 | active: false 21 | } 22 | }; 23 | 24 | const initialState = { 25 | sticky: false, 26 | absolute: false, 27 | fixedOffset: '', 28 | offsetHeight: 0, 29 | bounds: { 30 | top: null, 31 | left: null, 32 | right: null, 33 | bottom: null, 34 | height: null, 35 | width: null 36 | }, 37 | restrict: { 38 | top: null, 39 | left: null, 40 | right: null, 41 | bottom: null, 42 | height: null, 43 | width: null 44 | }, 45 | wrapperStyle: null, 46 | elementStyle: null, 47 | initialStyle: null, 48 | style: { 49 | top: null, 50 | bottom: null, 51 | left: null, 52 | right: null, 53 | 'margin-top': 0, 54 | 'margin-bottom': 0, 55 | 'margin-left': 0, 56 | 'margin-right': 0 57 | }, 58 | disabled: false 59 | }; 60 | 61 | const getAbsolutBoundingRect = (el, fixedHeight) => { 62 | var rect = el.getBoundingClientRect(); 63 | var top = rect.top + ScrollFeatures.windowY; 64 | var height = fixedHeight || rect.height; 65 | return { 66 | top: top, 67 | bottom: top + height, 68 | height: height, 69 | width: rect.width, 70 | left: rect.left, 71 | right: rect.right 72 | }; 73 | }; 74 | 75 | const addBounds = (rect1, rect2) => { 76 | var rect = assign({}, rect1); 77 | rect.top -= rect2.top; 78 | rect.left -= rect2.left; 79 | rect.right = rect.left + rect1.width; 80 | rect.bottom = rect.top + rect1.height; 81 | return rect; 82 | }; 83 | 84 | const getPositionStyle = el => { 85 | 86 | var result = {}; 87 | var style = window.getComputedStyle(el, null); 88 | 89 | for (var key in initialState.style) { 90 | var value = parseInt(style.getPropertyValue(key)); 91 | value = isNaN(value) ? null : value; 92 | result[key] = value; 93 | } 94 | 95 | return result; 96 | }; 97 | 98 | const getPreviousElementSibling = el => { 99 | var prev = el.previousElementSibling; 100 | if (prev && prev.tagName.toLocaleLowerCase() === 'script') { 101 | prev = getPreviousElementSibling(prev); 102 | } 103 | return prev; 104 | }; 105 | 106 | class StickyState extends EventDispatcher { 107 | 108 | el = null; 109 | firstRender = true; 110 | scroll = null; 111 | wrapper = null; 112 | options = null; 113 | 114 | 115 | constructor(element, options) { 116 | 117 | var elements; 118 | if (element instanceof window.NodeList) { 119 | elements = [].slice.call(element, 1); 120 | element = element[0]; 121 | } 122 | 123 | super({target: element}); 124 | 125 | this.el = element; 126 | 127 | if (options && options.scrollClass) { 128 | options.scrollClass = assign({}, defaults.scrollClass, options.scrollClass, { active: true }); 129 | } 130 | this.options = assign({}, defaults, options); 131 | 132 | this.setState(assign({}, initialState, { disabled: this.options.disabled }), true); 133 | 134 | this.scrollTarget = ScrollFeatures.getScrollParent(this.el); 135 | this.hasOwnScrollTarget = this.scrollTarget !== window; 136 | if (this.hasOwnScrollTarget) { 137 | this.updateFixedOffset = this.updateFixedOffset.bind(this); 138 | } 139 | 140 | 141 | this.render = this.render.bind(this); 142 | this.addSrollHandler(); 143 | this.addResizeHandler(); 144 | this.render(); 145 | 146 | if (elements && elements.length) { 147 | var collection = StickyState.apply(elements, options); 148 | collection.push(this); 149 | return collection; 150 | } 151 | } 152 | 153 | static apply(elements, options) { 154 | 155 | if (elements && elements.length) { 156 | var arr = new StickyStateCollection(); 157 | for (var i = 0; i < elements.length; i++) { 158 | arr.push(new StickyState(elements[i], options)); 159 | } 160 | return arr; 161 | } 162 | 163 | return new StickyState(elements, options); 164 | } 165 | 166 | static get native() { 167 | return Can.sticky; 168 | } 169 | 170 | setState(newState, silent) { 171 | this.lastState = this.state || newState; 172 | this.state = assign({}, this.state, newState); 173 | if (silent !== true) { 174 | this.render(); 175 | this.trigger(this.state.sticky ? 'sticky:on' : 'sticky:off'); 176 | } 177 | } 178 | 179 | disable(value) { 180 | this.setState({disabled:value}, value); 181 | } 182 | 183 | getBoundingClientRect() { 184 | return this.el.getBoundingClientRect(); 185 | } 186 | 187 | getBounds(noCache) { 188 | 189 | var clientRect = this.getBoundingClientRect(); 190 | var offsetHeight = ScrollFeatures.documentHeight; 191 | noCache = noCache === true; 192 | 193 | if (noCache !== true && this.state.bounds.height !== null) { 194 | if (this.state.offsetHeight === offsetHeight && clientRect.height === this.state.bounds.height) { 195 | return { 196 | offsetHeight: offsetHeight, 197 | style: this.state.style, 198 | bounds: this.state.bounds, 199 | restrict: this.state.restrict 200 | }; 201 | } 202 | } 203 | 204 | // var style = noCache ? this.state.style : getPositionStyle(this.el); 205 | var initialStyle = this.state.initialStyle; 206 | if (!initialStyle) { 207 | initialStyle = getPositionStyle(this.el); 208 | } 209 | 210 | var style = initialStyle; 211 | var child = this.wrapper || this.el; 212 | var rect; 213 | var restrict; 214 | var offsetY = 0; 215 | var offsetX = 0; 216 | 217 | if (!Can.sticky) { 218 | rect = getAbsolutBoundingRect(child, clientRect.height); 219 | if (this.hasOwnScrollTarget) { 220 | var parentRect = getAbsolutBoundingRect(this.scrollTarget); 221 | offsetY = this.scroll.y; 222 | rect = addBounds(rect, parentRect); 223 | restrict = parentRect; 224 | restrict.top = 0; 225 | restrict.height = this.scroll.scrollHeight || restrict.height; 226 | restrict.bottom = restrict.height; 227 | } 228 | } else { 229 | var elem = getPreviousElementSibling(child); 230 | offsetY = 0; 231 | 232 | if (elem) { 233 | offsetY = parseInt(window.getComputedStyle(elem)['margin-bottom']); 234 | offsetY = offsetY || 0; 235 | rect = getAbsolutBoundingRect(elem); 236 | if (this.hasOwnScrollTarget) { 237 | rect = addBounds(rect, getAbsolutBoundingRect(this.scrollTarget)); 238 | offsetY += this.scroll.y; 239 | } 240 | rect.top = rect.bottom + offsetY; 241 | 242 | } else { 243 | elem = child.parentNode; 244 | offsetY = parseInt(window.getComputedStyle(elem)['padding-top']); 245 | offsetY = offsetY || 0; 246 | rect = getAbsolutBoundingRect(elem); 247 | if (this.hasOwnScrollTarget) { 248 | rect = addBounds(rect, getAbsolutBoundingRect(this.scrollTarget)); 249 | offsetY += this.scroll.y; 250 | } 251 | rect.top = rect.top + offsetY; 252 | } 253 | if (this.hasOwnScrollTarget) { 254 | restrict = getAbsolutBoundingRect(this.scrollTarget); 255 | restrict.top = 0; 256 | restrict.height = this.scroll.scrollHeight || restrict.height; 257 | restrict.bottom = restrict.height; 258 | } 259 | 260 | rect.height = child.clientHeight; 261 | rect.width = child.clientWidth; 262 | rect.bottom = rect.top + rect.height; 263 | } 264 | 265 | restrict = restrict || getAbsolutBoundingRect(child.parentNode); 266 | 267 | return { 268 | offsetHeight: offsetHeight, 269 | style: style, 270 | bounds: rect, 271 | initialStyle: initialStyle, 272 | restrict: restrict 273 | }; 274 | } 275 | 276 | updateBounds(silent, noCache) { 277 | silent = silent === true; 278 | noCache = noCache === true; 279 | this.setState(this.getBounds(noCache), silent); 280 | } 281 | 282 | updateFixedOffset() { 283 | this.lastState.fixedOffset = this.state.fixedOffset; 284 | if (this.state.sticky) { 285 | this.state.fixedOffset = (this.scrollTarget.getBoundingClientRect().top) + 'px;'; 286 | } else { 287 | this.state.fixedOffset = ''; 288 | } 289 | if (this.lastState.fixedOffset !== this.state.fixedOffset) { 290 | this.render(); 291 | } 292 | } 293 | 294 | addSrollHandler() { 295 | if (!this.scroll) { 296 | var hasScrollTarget = ScrollFeatures.hasInstance(this.scrollTarget); 297 | this.scroll = ScrollFeatures.getInstance(this.scrollTarget); 298 | this.onScroll = this.onScroll.bind(this); 299 | this.scroll.on('scroll:start', this.onScroll); 300 | this.scroll.on('scroll:progress', this.onScroll); 301 | this.scroll.on('scroll:stop', this.onScroll); 302 | 303 | if (this.options.scrollClass.active) { 304 | this.onScrollDirection = this.onScrollDirection.bind(this); 305 | this.scroll.on('scroll:up', this.onScrollDirection); 306 | this.scroll.on('scroll:down', this.onScrollDirection); 307 | if (!this.options.scrollClass.persist) { 308 | this.scroll.on('scroll:stop', this.onScrollDirection); 309 | } 310 | } 311 | if (hasScrollTarget && this.scroll.scrollY > 0) { 312 | this.scroll.trigger('scroll:progress'); 313 | } 314 | } 315 | } 316 | 317 | removeSrollHandler() { 318 | if (this.scroll) { 319 | this.scroll.off('scroll:start', this.onScroll); 320 | this.scroll.off('scroll:progress', this.onScroll); 321 | this.scroll.off('scroll:stop', this.onScroll); 322 | if (this.options.scrollClass.active) { 323 | this.scroll.off('scroll:up', this.onScrollDirection); 324 | this.scroll.off('scroll:down', this.onScrollDirection); 325 | this.scroll.off('scroll:stop', this.onScrollDirection); 326 | } 327 | if(!this.scroll.hasListeners()){ 328 | this.scroll.destroy(); 329 | } 330 | this.onScroll = null; 331 | this.onScrollDirection = null; 332 | this.scroll = null; 333 | } 334 | } 335 | 336 | addResizeHandler() { 337 | if (!this.onResize) { 338 | this.onResize = this.update.bind(this); 339 | window.addEventListener('sticky:update', this.onResize, false); 340 | window.addEventListener('resize', this.onResize, false); 341 | window.addEventListener('orientationchange', this.onResize, false); 342 | } 343 | } 344 | 345 | removeResizeHandler() { 346 | if (this.onResize) { 347 | window.removeEventListener('sticky:update', this.onResize); 348 | window.removeEventListener('resize', this.onResize); 349 | window.removeEventListener('orientationchange', this.onResize); 350 | this.onResize = null; 351 | } 352 | } 353 | 354 | 355 | destroy() { 356 | super.destroy(); 357 | this.removeSrollHandler(); 358 | this.removeResizeHandler(); 359 | this.render = null; 360 | this.el = null; 361 | this.state = null; 362 | this.wrapper = null; 363 | } 364 | 365 | getScrollClasses(obj) { 366 | if (this.options.scrollClass.active) { 367 | obj = obj || {}; 368 | var direction = (this.scroll.y <= 0 || this.scroll.y + this.scroll.clientHeight >= this.scroll.scrollHeight) ? 0 : this.scroll.directionY; 369 | obj[this.options.scrollClass.up] = direction < 0; 370 | obj[this.options.scrollClass.down] = direction > 0; 371 | } 372 | return obj; 373 | } 374 | 375 | onScrollDirection(e) { 376 | if (this.state.sticky || e.type === ScrollFeatures.events.SCROLL_STOP) { 377 | this.el.className = classString(this.el.className, this.getScrollClasses()); 378 | } 379 | } 380 | 381 | onScroll(e) { 382 | this.updateStickyState(false); 383 | if (this.hasOwnScrollTarget && !Can.sticky) { 384 | this.updateFixedOffset(); 385 | if (this.state.sticky && !this.hasWindowScrollListener) { 386 | this.hasWindowScrollListener = true; 387 | ScrollFeatures.getInstance(window).on('scroll:progress', this.updateFixedOffset); 388 | } else if (!this.state.sticky && this.hasWindowScrollListener) { 389 | this.hasWindowScrollListener = false; 390 | ScrollFeatures.getInstance(window).off('scroll:progress', this.updateFixedOffset); 391 | } 392 | } 393 | } 394 | 395 | update() { 396 | this.scroll.updateScrollPosition(); 397 | this.updateBounds(true, true); 398 | this.updateStickyState(false); 399 | } 400 | 401 | getStickyState() { 402 | 403 | if (this.state.disabled) { 404 | return { sticky: false, absolute: false }; 405 | } 406 | 407 | var scrollY = this.scroll.y; 408 | var scrollX = this.scroll.x; 409 | var top = this.state.style.top; 410 | var bottom = this.state.style.bottom; 411 | // var left = this.state.style.left; 412 | // var right = this.state.style.right; 413 | var sticky = this.state.sticky; 414 | var absolute = this.state.absolute; 415 | 416 | if (top !== null) { 417 | var offsetBottom = this.state.restrict.bottom - this.state.bounds.height - top; 418 | top = this.state.bounds.top - top; 419 | 420 | if (this.state.sticky === false && ((scrollY >= top && scrollY <= offsetBottom) || (top <= 0 && scrollY < top))) { 421 | sticky = true; 422 | absolute = false; 423 | } else if (this.state.sticky && (top > 0 && scrollY < top || scrollY > offsetBottom)) { 424 | sticky = false; 425 | absolute = scrollY > offsetBottom; 426 | } 427 | } else if (bottom !== null) { 428 | 429 | scrollY += window.innerHeight; 430 | var offsetTop = this.state.restrict.top + this.state.bounds.height - bottom; 431 | bottom = this.state.bounds.bottom + bottom; 432 | 433 | if (this.state.sticky === false && scrollY <= bottom && scrollY >= offsetTop) { 434 | sticky = true; 435 | absolute = false; 436 | } else if (this.state.sticky && (scrollY > bottom || scrollY < offsetTop)) { 437 | sticky = false; 438 | absolute = scrollY <= offsetTop; 439 | } 440 | } 441 | return { sticky, absolute }; 442 | } 443 | 444 | updateStickyState(silent) { 445 | var values = this.getStickyState(); 446 | 447 | if (values.sticky !== this.state.sticky || values.absolute !== this.state.absolute) { 448 | silent = silent === true; 449 | values = assign(values, this.getBounds()); 450 | this.setState(values, silent); 451 | } 452 | } 453 | 454 | render() { 455 | 456 | if (this.state.disabled) { 457 | return; 458 | } 459 | 460 | var classNameObj = {}; 461 | 462 | if (this.firstRender) { 463 | this.firstRender = false; 464 | 465 | if (!Can.sticky) { 466 | this.wrapper = document.createElement('div'); 467 | this.wrapper.className = this.options.wrapperClass; 468 | var parent = this.el.parentNode; 469 | if (parent) { 470 | parent.insertBefore(this.wrapper, this.el); 471 | } 472 | if(this.options.wrapFixedSticky){ 473 | this.wrapper.appendChild(this.el); 474 | } 475 | classNameObj[this.options.fixedClass] = true; 476 | } 477 | 478 | this.updateBounds(true, true); 479 | this.updateStickyState(true); 480 | } 481 | 482 | if (!Can.sticky) { 483 | var elementStyle = ''; 484 | var height = (this.state.disabled || this.state.bounds.height === null || (!this.state.sticky && !this.state.absolute)) ? 'auto;' : this.state.bounds.height + 'px;'; 485 | var wrapperStyle = 'height:' + height; 486 | wrapperStyle += (height === 'auto;') ? '' : (this.state.style['margin-top'] ? 'margin-top:' + this.state.style['margin-top'] + 'px;' : '0;') + (this.state.style['margin-bottom'] ? 'margin-bottom' + this.state.style['margin-bottom'] + 'px;' : '0;'); 487 | 488 | if (this.state.absolute !== this.lastState.absolute) { 489 | wrapperStyle += this.state.absolute ? 'position:relative;' : ''; 490 | classNameObj[this.options.absoluteClass] = this.state.absolute; 491 | elementStyle += this.state.absolute ? ((this.state.style.top !== null) ? ('margin-top:' + (this.state.restrict.height - (this.state.bounds.height + this.state.style.top) + (this.state.restrict.top - this.state.bounds.top)) + 'px;') : 'margin-top:0;' + ((this.state.style.bottom !== null) ? ('margin-bottom:' + (this.state.restrict.height - (this.state.bounds.height + this.state.style.bottom) + (this.state.restrict.bottom - this.state.bounds.bottom)) + 'px;') : 'margin-bottom:0;')) : 'margin-bottom:0;margin-top:0;'; 492 | 493 | } 494 | 495 | if ((this.state.style.top !== null || this.state.style.bottom !== null) && (this.hasOwnScrollTarget && !this.state.absolute && this.lastState.fixedOffset !== this.state.fixedOffset)) { 496 | elementStyle += 'margin-top:' + (this.state.fixedOffset ? this.state.fixedOffset : '0;'); 497 | } 498 | 499 | if (this.state.wrapperStyle !== wrapperStyle) { 500 | this.state.wrapperStyle = wrapperStyle; 501 | this.wrapper.style.cssText += wrapperStyle; 502 | } 503 | 504 | if (this.state.elementStyle !== elementStyle) { 505 | this.state.elementStyle = elementStyle; 506 | this.el.style.cssText += elementStyle; 507 | } 508 | } 509 | 510 | 511 | classNameObj[this.options.stateClassName] = this.state.sticky; 512 | classNameObj = this.getScrollClasses(classNameObj); 513 | var className = classString(this.el.className, classNameObj); 514 | 515 | if (this.el.className !== className) { 516 | this.el.className = className; 517 | } 518 | 519 | return this.el; 520 | } 521 | 522 | } 523 | 524 | var _canSticky = null; 525 | 526 | class Can { 527 | 528 | static get sticky() { 529 | if (_canSticky !== null) { 530 | return _canSticky; 531 | } 532 | if (typeof window !== 'undefined') { 533 | 534 | if (window.Modernizr && window.Modernizr.hasOwnProperty('csspositionsticky')) { 535 | return _canSticky = window.Modernizr.csspositionsticky; 536 | } 537 | 538 | var documentFragment = document.documentElement; 539 | var testEl = document.createElement('div'); 540 | documentFragment.appendChild(testEl); 541 | var prefixedSticky = ['sticky', '-webkit-sticky']; 542 | 543 | _canSticky = false; 544 | 545 | for (var i = 0; i < prefixedSticky.length; i++) { 546 | testEl.style.position = prefixedSticky[i]; 547 | _canSticky = !!window.getComputedStyle(testEl).position.match('sticky'); 548 | if (_canSticky) { 549 | break; 550 | } 551 | } 552 | documentFragment.removeChild(testEl); 553 | } 554 | return _canSticky; 555 | }; 556 | 557 | } 558 | 559 | class StickyStateCollection extends EventDispatcher { 560 | 561 | constructor() { 562 | super(); 563 | this.items = []; 564 | } 565 | 566 | push(item) { 567 | this.items.push(item); 568 | } 569 | 570 | update() { 571 | var i = -1; 572 | while (++i < this.items.length) { 573 | this.items[i].update(); 574 | } 575 | } 576 | 577 | addListener(event, listener) { 578 | 579 | var i = -1; 580 | while (++i < this.items.length) { 581 | this.items[i].addListener(event, listener); 582 | } 583 | return this; 584 | } 585 | 586 | removeListener(event, listener) { 587 | var i = -1; 588 | while (++i < this.items.length) { 589 | this.items[i].removeListener(event, listener); 590 | } 591 | return this; 592 | } 593 | 594 | } 595 | 596 | 597 | export default StickyState; 598 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | StickyState 7 | 8 | 9 | 144 | 145 | 146 |
147 |

StickyState

148 | 149 |

A test page for the StickyState project

150 |

markup and styles of this document are mostly copied from filamentgroup

151 | 152 | 153 | 154 |
155 |
156 | Fixed to viewport top A. 157 |
state:
158 |
scrolling:
159 |
160 |
161 |
162 |
163 |
164 |
165 | spacer for resize testing 166 |
167 |
168 |
169 |
170 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga ut, maxime reiciendis ab pariatur eaque, suscipit esse tempora nesciunt atque assumenda a, consequatur ex et illo qui accusamus facere quis ipsam tenetur. Eaque molestias quo laudantium odio! Velit nobis, consequatur.

171 | 172 |
173 | Fixed to viewport top B. 174 |
state:
175 |
scrolling:
176 |
177 | 178 |

And now, some fake content to allow scrolling...

179 | 180 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

181 | 182 |

Header Level 2

183 | 184 |
    185 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 186 |
  3. Aliquam tincidunt mauris eu risus.
  4. 187 |
188 | 189 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

190 | 191 |

Header Level 3

192 | 193 |
    194 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 195 |
  • Aliquam tincidunt mauris eu risus.
  • 196 |
197 | 198 | 199 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

200 | 201 |

Header Level 2

202 | 203 |
    204 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 205 |
  3. Aliquam tincidunt mauris eu risus.
  4. 206 |
207 | 208 |
209 | Fixed to viewport bottom B (1em above). 210 |
state:
211 |
scroll:
212 |
213 |
214 |
215 |
216 | Fixed to viewport bottom A. 217 |
state:
218 |
scroll:
219 |
220 |
221 | 222 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

223 | 224 |

Header Level 3

225 | 226 |
    227 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 228 |
  • Aliquam tincidunt mauris eu risus.
  • 229 |
230 | 231 |

Sticky with overflow

232 |

fully supported. native and polyfilled

233 | 234 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

235 | 236 |
237 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

238 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

239 |
240 | Fixed to overflow div top. 241 |
state:
242 |
scrolling:
243 |
244 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

245 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sint quaerat excepturi, amet. Corporis pariatur illum ab, ea placeat delectus impedit.

246 |
247 |
248 | 249 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

250 | 251 |

Header Level 2

252 | 253 |
    254 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 255 |
  3. Aliquam tincidunt mauris eu risus.
  4. 256 |
257 | 258 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

259 | 260 |

Header Level 3

261 | 262 |
    263 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 264 |
  • Aliquam tincidunt mauris eu risus.
  • 265 |
266 | 267 | 268 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

269 | 270 |

Header Level 2

271 | 272 |
    273 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 274 |
  3. Aliquam tincidunt mauris eu risus.
  4. 275 |
276 | 277 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

278 | 279 |

Header Level 3

280 | 281 |
    282 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 283 |
  • Aliquam tincidunt mauris eu risus.
  • 284 |
285 | 286 | 287 |

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

288 | 289 |

Header Level 2

290 | 291 |
    292 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 293 |
  3. Aliquam tincidunt mauris eu risus.
  4. 294 |
295 | 296 |
297 | 298 | 299 | 300 | 301 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | var jsdom = require('jsdom'); 2 | var path = require('path'); 3 | var StickyState = require('../dist/stickystate'); 4 | 5 | 6 | var p = path.resolve(__dirname, 'index.html'); 7 | 8 | 9 | jsdom.env({ 10 | file: p, 11 | done: function(err, window) { 12 | 13 | global.window = window; 14 | global.document = window.document; 15 | 16 | var stickies = new StickyState(window.document.querySelectorAll('.sticky'), { 17 | scrollClass: { 18 | down: 'sticky-scroll-down', 19 | up: 'sticky-scroll-up' 20 | } 21 | }) 22 | .on('sticky:on', function(e) { console.log('sticky:on', e.target.id); }) 23 | .on('sticky:off', function(e) { console.log('sticky:off', e.target.id); }); 24 | 25 | console.log(StickyState.native); 26 | 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const package = require('./package'); 3 | 4 | module.exports = { 5 | 'context': __dirname + '/src', 6 | 'entry': [ 7 | // 'webpack/hot/dev-server', 8 | 'webpack-dev-server/client?http://localhost:3000/', 9 | './sticky-state.js' 10 | ], 11 | 'output': { 12 | 'path': __dirname + '/dist', 13 | 'filename': `${package.name}.min.js`, 14 | 'library': `StickyState`, 15 | 'libraryTarget': 'umd' 16 | }, 17 | 'module': { 18 | 'loaders': [{ 19 | 'test': /\.js$/, 20 | 'exclude': /node_modules/, 21 | 'loader': 'babel' 22 | }] 23 | }, 24 | 'plugins': [ 25 | //new webpack.HotModuleReplacementPlugin() 26 | ], 27 | devServer: { 28 | // contentBase: './', 29 | port: 3000, 30 | // hot: true, 31 | open: true, 32 | inline: true 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const package = require('./package'); 3 | 4 | const banner = `${package.name} ${package.version} - ${package.description}\nCopyright (c) ${ new Date().getFullYear() } ${package.author} - ${package.homepage}\nLicense: ${package.license}`; 5 | 6 | module.exports = { 7 | 'context': __dirname + '/src', 8 | 'entry': ['./sticky-state.js'], 9 | 'output': { 10 | 'path': __dirname + '/dist', 11 | 'filename': `${package.name}.min.js`, 12 | 'library': `StickyState`, 13 | 'libraryTarget': 'umd' 14 | }, 15 | debug: false, 16 | 'module': { 17 | 'loaders': [{ 18 | 'test': /\.js$/, 19 | 'exclude': /node_modules/, 20 | 'loader': 'babel' 21 | }] 22 | }, 23 | 'plugins': [ 24 | new webpack.BannerPlugin(banner), 25 | ] 26 | }; 27 | --------------------------------------------------------------------------------