├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── dist ├── fixedfixed.build.js └── fixedfixed.min.js ├── docs.css ├── index.html ├── package.json ├── src └── fixedfixed.js └── test └── unit ├── fixed-fixed-tests.js └── fixed-fixed.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | bower_components 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "browser": true, 14 | "predef": ["jQuery"], 15 | "devel": true 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | /*global require:true*/ 3 | module.exports = function(grunt) { 4 | 'use strict'; 5 | 6 | // Project configuration. 7 | grunt.initConfig({ 8 | 9 | // Constants 10 | pkg: grunt.file.readJSON('package.json'), 11 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + 12 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 13 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + 14 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + 15 | ' Licensed <%= pkg.license %> */\n', 16 | name: 'fixedfixed', 17 | 18 | // Task Configuration 19 | jshint: { 20 | src: { 21 | options: { 22 | jshintrc: '.jshintrc' 23 | }, 24 | src: 'src/<%= name %>.js' 25 | } 26 | }, 27 | uglify: { 28 | options: { 29 | banner: '<%= banner %>' 30 | }, 31 | pretty: { 32 | src: 'src/<%= name %>.js', 33 | dest: 'dist/<%= name %>.build.js', 34 | options: { 35 | mangle: false, 36 | compress: false, 37 | beautify: true, 38 | preserveComments: 'all' 39 | } 40 | }, 41 | min: { 42 | src: 'src/<%= name %>.js', 43 | dest: 'dist/<%= name %>.min.js' 44 | } 45 | }, 46 | qunit: { 47 | all: ['test/**/*.html'] 48 | } 49 | }); 50 | 51 | require( 'matchdep' ).filterDev( 'grunt-*' ).forEach( grunt.loadNpmTasks ); 52 | 53 | // Default task. 54 | grunt.registerTask( 'test', [ 'jshint', 'qunit' ] ); 55 | grunt.registerTask( 'lint', [ 'jshint' ] ); 56 | grunt.registerTask( 'default', [ 'jshint', 'qunit', 'uglify' ] ); 57 | }; 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Filament Group 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | :warning: This project is archived and the repository is no longer maintained. 2 | 3 | # Fixed-fixed: a CSS `position:fixed` qualifier 4 | 5 | - (c)2012 @scottjehl, Filament Group 6 | - Dual license: MIT and/or GPLv2 7 | 8 | [![Build Status](https://travis-ci.org/filamentgroup/fixed-fixed.svg)](https://travis-ci.org/filamentgroup/fixed-fixed) 9 | 10 | ## Explanation 11 | 12 | CSS fixed-positioning varies widely in browser support, and it's difficult to test. This repo includes a test that attempts to qualify the application of CSS position:fixed. Rather than testing immediately, it waits for the user to scroll, at which point it checks to see if fixed positioning is working properly. Prior to scroll, the script assumes fixed-positioning works, adding a class of `fixed-supported` that can be used to qualify any `position:fixed` CSS rules. When fixed positioning is tested and deemed unsupported, the class is removed, allowing any fixed-positioned elements to safely degrade to some other layout. 13 | 14 | One caveat in details of the approach: there are a few known browsers that report false results when running the included feature test. These browsers are no longer in development, but since they are popular, this script looks for them name and deems their `position:fixed` support as false immediately, never needing to run the test. Of course, this sort of blacklisting is quite untenable to maintain, so it is only used in the event that a feature test can not be reliably used. These browsers are Android 2.1, Opera Mobile (less than 11.0, 11.5 works but dynamically re-positions instead of true fixed), Opera Mini (latest), and Firefox Mobile (latest). 15 | 16 | Hat tip: the idea behind the testing portion of this approach was inspired by @Kangax's [Position Fixed Test](http://kangax.github.com/cft/#IS_POSITION_FIXED_SUPPORTED) 17 | 18 | ## Usage 19 | 20 | Just qualify any `position:fixed` usage in your stylesheet with a `.fixed-supported` parent class selector, like so: 21 | 22 | .fixed-supported header { position: fixed; } 23 | 24 | That class will be present on the HTML element in CSS fixed-supporting browsers. You can apply an initial/degraded layout in browsers that don't support fixed positioning properly by writing selectors that do not use the `.fixed-supported` selector. 25 | 26 | See [`index.html`](http://filamentgroup.github.com/fixed-fixed/) for an example. 27 | 28 | ## Available in [Bower](http://bower.io/) 29 | 30 | bower install filament-fixed 31 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filament-fixed", 3 | "version": "0.1.2", 4 | "main": ["dist/fixedfixed.build.js", "dist/fixedfixed.min.js"], 5 | "ignore": [ 6 | "**/.*" 7 | ], 8 | "dependencies": { 9 | "qunit": ">=1.12.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dist/fixedfixed.build.js: -------------------------------------------------------------------------------- 1 | /*! fixed-fixed - v0.1.0 - 2014-05-23 2 | * Copyright (c) 2014 ; Licensed MIT */ 3 | /*! Fixedfixed: a CSS position:fixed qualifier. (c)2012 @scottjehl, Filament Group, Inc. Dual license: MIT and/or GPLv2 */ 4 | (function(w, undefined) { 5 | var htmlclass = "fixed-supported", el = w.document.createElement("div"), ua = w.navigator.userAgent, docEl = w.document.documentElement; 6 | // fix the test element 7 | el.style.position = "fixed"; 8 | el.style.top = 0; 9 | // support test 10 | function checkFixed() { 11 | var scroll = "scrollTop" in w.document.body ? w.document.body.scrollTop : docEl.scrollTop; 12 | // only run test if there's a scroll we can compare 13 | if (scroll !== undefined && scroll > 0 && w.document.body) { 14 | w.document.body.insertBefore(el, w.document.body.firstChild); 15 | if (!el.getBoundingClientRect || el.getBoundingClientRect().top !== 0) { 16 | // Fixed is not working or can't be tested 17 | docEl.className = docEl.className.replace(htmlclass, ""); 18 | } 19 | // remove the test element 20 | w.document.body.removeChild(el); 21 | // unbind the handlers 22 | if (w.removeEventListener) { 23 | w.removeEventListener("scroll", checkFixed, false); 24 | } else { 25 | w.detachEvent("onscroll", checkFixed); 26 | } 27 | } 28 | } 29 | // if a particular UA is known to return false results with this feature test, try and avoid that UA here. 30 | if (// Android 2.1, 2.2, 2.5, and 2.6 Webkit 31 | !(ua.match(/Android 2\.[1256]/) && ua.indexOf("AppleWebKit") > -1) || // Opera Mobile less than version 11.0 (7458) 32 | !(ua.match(/Opera Mobi\/([0-9]+)/) && RegExp.$1 < 7458) || // Opera Mini 33 | !(w.operamini && {}.toString.call(w.operamini) === "[object OperaMini]") || // Firefox Mobile less than version 6 34 | !(ua.match(/Fennec\/([0-9]+)/) && RegExp.$1 < 6)) { 35 | //add the HTML class for now. 36 | docEl.className += " " + htmlclass; 37 | // bind to scroll event so we can test and potentially degrade 38 | if (w.addEventListener) { 39 | w.addEventListener("scroll", checkFixed, false); 40 | } else { 41 | w.attachEvent("onscroll", checkFixed); 42 | } 43 | } 44 | w.FixedFixed = checkFixed; 45 | })(this); -------------------------------------------------------------------------------- /dist/fixedfixed.min.js: -------------------------------------------------------------------------------- 1 | /*! fixed-fixed - v0.1.0 - 2014-05-23 2 | * Copyright (c) 2014 ; Licensed MIT */ 3 | (function(e,t){function o(){var c="scrollTop"in e.document.body?e.document.body.scrollTop:d.scrollTop;c!==t&&c>0&&e.document.body&&(e.document.body.insertBefore(i,e.document.body.firstChild),i.getBoundingClientRect&&0===i.getBoundingClientRect().top||(d.className=d.className.replace(n,"")),e.document.body.removeChild(i),e.removeEventListener?e.removeEventListener("scroll",o,!1):e.detachEvent("onscroll",o))}var n="fixed-supported",i=e.document.createElement("div"),c=e.navigator.userAgent,d=e.document.documentElement;i.style.position="fixed",i.style.top=0,c.match(/Android 2\.[1256]/)&&c.indexOf("AppleWebKit")>-1&&c.match(/Opera Mobi\/([0-9]+)/)&&7458>RegExp.$1&&e.operamini&&"[object OperaMini]"==={}.toString.call(e.operamini)&&c.match(/Fennec\/([0-9]+)/)&&6>RegExp.$1||(d.className+=" "+n,e.addEventListener?e.addEventListener("scroll",o,!1):e.attachEvent("onscroll",o)),e.FixedFixed=o})(this); -------------------------------------------------------------------------------- /docs.css: -------------------------------------------------------------------------------- 1 | /* Logo */ 2 | .header { 3 | background: #247201 url(http://filamentgroup.com/images/headerbg-new.jpg) no-repeat bottom left; 4 | } 5 | #fg-logo { 6 | text-indent: -9999px; 7 | margin: 0 auto; 8 | width: 287px; 9 | height: 52px; 10 | background-image: url(http://filamentgroup.com/images/fg-logo-icon.png); 11 | } 12 | @media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5){ 13 | #fg-logo { 14 | background-size: 287px 52px; 15 | background-image: url(http://filamentgroup.com/images/fg-logo-icon-lrg.png); 16 | } 17 | } 18 | /* Demo styles */ 19 | body { 20 | font-family: sans-serif; 21 | font-size: 100%; 22 | } 23 | .docs-main { 24 | margin: 1em auto; 25 | max-width: 46em; 26 | } 27 | label { 28 | display: block; 29 | margin: 1em 0; 30 | } 31 | input, 32 | textarea { 33 | display: block; 34 | width: 100%; 35 | -webkit-box-sizing: border-box; 36 | -moz-box-sizing: border-box; 37 | box-sizing: border-box; 38 | 39 | margin-top: .4em; 40 | padding: .6em; 41 | font-size: 100%; 42 | } 43 | 44 | .menu { 45 | background-color: white; 46 | box-sizing: border-box; 47 | border: 1px solid black; 48 | width: 10em; 49 | } 50 | 51 | .menu ul, .menu ol { 52 | list-style: none; 53 | padding: 5px; 54 | margin: 0; 55 | } 56 | 57 | .menu-selected { 58 | color: white; 59 | background-color: #aaa; 60 | } 61 | 62 | input { 63 | box-sizing: border-box; 64 | width: 10em; 65 | } 66 | 67 | h1.docs, 68 | h2.docs, 69 | h3.docs, 70 | h4.docs, 71 | h5.docs { 72 | font-weight: 500; 73 | margin: 1em 0; 74 | text-transform: none; 75 | color: #000; 76 | clear: both; 77 | } 78 | 79 | h1.docs { font-size: 2.8em; margin-top: .1em; text-transform: uppercase; } 80 | h2.docs { font-size: 2.2em; margin-top: 1.5em; border-top:1px solid #ddd; padding-top: .6em; float:none; } 81 | h3.docs { font-size: 1.6em; margin-top: 1.5em; margin-bottom: .5em; } 82 | h4.docs { font-size: 1.4em; margin-top: 1.5em; } 83 | 84 | p.docs, 85 | p.docs-intro, 86 | ol.docs, 87 | ul.docs, 88 | p.docs-note, 89 | dl.docs { 90 | margin: 1em 0; 91 | font-size: 1em; 92 | } 93 | 94 | ul.docs, 95 | ol.docs { 96 | padding-bottom: .5em; 97 | } 98 | ol.docs li, 99 | ul.docs li { 100 | margin-bottom: 8px; 101 | } 102 | ul.docs ul, 103 | ol.docs ul { 104 | padding-top: 8px; 105 | } 106 | .docs code { 107 | font-size: 1.1em; 108 | } 109 | 110 | p.docs strong { 111 | font-weight: bold; 112 | } 113 | 114 | .docs-note { 115 | background-color: #FFFAA4; 116 | } 117 | .docs-note p, 118 | .docs-note pre, 119 | p.docs-note { 120 | padding: .5em; 121 | margin: 0; 122 | } 123 | 124 | 125 | /** 126 | * prism.js default theme for JavaScript, CSS and HTML 127 | * Based on dabblet (http://dabblet.com) 128 | * @author Lea Verou 129 | */ 130 | 131 | code[class*="language-"], 132 | pre[class*="language-"] { 133 | color: black; 134 | text-shadow: 0 1px white; 135 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 136 | direction: ltr; 137 | text-align: left; 138 | white-space: pre; 139 | word-spacing: normal; 140 | font-size: 0.8em; 141 | 142 | -moz-tab-size: 4; 143 | -o-tab-size: 4; 144 | tab-size: 4; 145 | 146 | -webkit-hyphens: none; 147 | -moz-hyphens: none; 148 | -ms-hyphens: none; 149 | hyphens: none; 150 | } 151 | 152 | @media print { 153 | code[class*="language-"], 154 | pre[class*="language-"] { 155 | text-shadow: none; 156 | } 157 | } 158 | 159 | /* Code blocks */ 160 | pre[class*="language-"] { 161 | padding: 1em; 162 | margin: .5em 0; 163 | overflow: auto; 164 | } 165 | 166 | :not(pre) > code[class*="language-"], 167 | pre[class*="language-"] { 168 | background: #f5f2f0; 169 | } 170 | 171 | /* Inline code */ 172 | :not(pre) > code[class*="language-"] { 173 | padding: .1em; 174 | border-radius: .3em; 175 | } 176 | 177 | pre[class*="language-"] { 178 | padding: 1em; 179 | margin: 0; 180 | margin-bottom: 1em; 181 | } 182 | 183 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Fixed Fixed 7 | 8 | 9 | 16 | 17 | 18 | 19 | 89 |
90 |
91 | 92 |
93 |
94 |

Demo of Fixed-Fixed 95 | CSS position:fixed qualifier. 96 |

97 | 101 |
102 |
103 |
104 | 105 | 106 |
107 | Fixed to viewport top, when supported. 108 |
109 | 110 |

Fixed-fixed

111 | 112 |

A test page for the Fixed-fixed project

113 | 114 |

This test page includes a test to qualify the application of CSS position:fixed, which enjoys very spotty support across devices. It assumes fixed-positioning works initially, adding a class of fixed-supported that can be used to qualify any position:fixed rules. When the page is scrolled, it runs a test to determine if fixed-positioning is working properly, if not, the class is removed, allowing any fixed-positioned elements to safely degrade to some other layout.

115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 |

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

124 | 125 |

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.

126 | 127 |

Header Level 2

128 | 129 |
    130 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 131 |
  3. Aliquam tincidunt mauris eu risus.
  4. 132 |
133 | 134 |

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.

135 | 136 |

Header Level 3

137 | 138 | 142 | 143 |

144 | 			#header h1 a {
145 | 				display: block;
146 | 				width: 300px;
147 | 				height: 80px;
148 | 			}
149 | 			
150 | 151 | 152 | 153 | 154 |

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.

155 | 156 |

Header Level 2

157 | 158 |
    159 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 160 |
  3. Aliquam tincidunt mauris eu risus.
  4. 161 |
162 | 163 |

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.

164 | 165 |

Header Level 3

166 | 167 | 171 | 172 |

173 | 			#header h1 a {
174 | 				display: block;
175 | 				width: 300px;
176 | 				height: 80px;
177 | 			}
178 | 			
179 | 180 | 181 | 182 | 183 |

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.

184 | 185 |

Header Level 2

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

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.

193 | 194 |

Header Level 3

195 | 196 | 200 | 201 |

202 | 			#header h1 a {
203 | 				display: block;
204 | 				width: 300px;
205 | 				height: 80px;
206 | 			}
207 | 			
208 | 209 | 210 | 211 | 212 |

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.

213 | 214 |

Header Level 2

215 | 216 |
    217 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 218 |
  3. Aliquam tincidunt mauris eu risus.
  4. 219 |
220 | 221 |

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.

222 | 223 |

Header Level 3

224 | 225 | 229 | 230 |

231 | 			#header h1 a {
232 | 				display: block;
233 | 				width: 300px;
234 | 				height: 80px;
235 | 			}
236 | 			
237 | 238 | 239 | 240 | 241 |

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.

242 | 243 |

Header Level 2

244 | 245 |
    246 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 247 |
  3. Aliquam tincidunt mauris eu risus.
  4. 248 |
249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 |
259 | Fixed to viewport bottom, when supported. 260 |
261 | 262 | 263 |
264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fixed-fixed", 3 | "version": "0.1.0", 4 | "description": "CSS position:fixed qualifier.", 5 | "main": "src/fixedfixed.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/grunt test", 8 | "postinstall": "./node_modules/.bin/bower install" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/filamentgroup/fixed-fixed.git" 13 | }, 14 | "keywords": [ 15 | "fixed" 16 | ], 17 | "author": "Scott Jehl, Filament Group", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/filamentgroup/fixed-fixed/issues" 21 | }, 22 | "devDependencies": { 23 | "grunt-cli": "~0.1.13", 24 | "grunt": "~0.4.1", 25 | "matchdep": "~0.3.0", 26 | "grunt-contrib-jshint": "~0.1.1", 27 | "grunt-contrib-qunit": "~0.3.0", 28 | "grunt-contrib-uglify": "~0.1.1", 29 | "bower": "1.3.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/fixedfixed.js: -------------------------------------------------------------------------------- 1 | /*! Fixedfixed: a CSS position:fixed qualifier. (c)2012 @scottjehl, Filament Group, Inc. Dual license: MIT and/or GPLv2 */ 2 | (function( w, undefined ){ 3 | 4 | var htmlclass = "fixed-supported", 5 | el = w.document.createElement( "div" ), 6 | ua = w.navigator.userAgent, 7 | docEl = w.document.documentElement; 8 | 9 | // fix the test element 10 | el.style.position = "fixed"; 11 | el.style.top = 0; 12 | 13 | // support test 14 | function checkFixed(){ 15 | 16 | var scroll = "scrollTop" in w.document.body ? w.document.body.scrollTop : docEl.scrollTop; 17 | 18 | // only run test if there's a scroll we can compare 19 | if( scroll !== undefined && scroll > 0 && w.document.body ){ 20 | 21 | w.document.body.insertBefore( el, w.document.body.firstChild ); 22 | 23 | if( !el.getBoundingClientRect || el.getBoundingClientRect().top !== 0 ){ 24 | // Fixed is not working or can't be tested 25 | docEl.className = docEl.className.replace( htmlclass, "" ); 26 | } 27 | 28 | // remove the test element 29 | w.document.body.removeChild( el ); 30 | 31 | // unbind the handlers 32 | if( w.removeEventListener ){ 33 | w.removeEventListener( "scroll", checkFixed, false ); 34 | } 35 | else{ 36 | w.detachEvent( "onscroll", checkFixed ); 37 | } 38 | } 39 | } 40 | 41 | // if a particular UA is known to return false results with this feature test, try and avoid that UA here. 42 | if( 43 | // Android 2.1, 2.2, 2.5, and 2.6 Webkit 44 | !( ua.match( /Android 2\.[1256]/ ) && ua.indexOf( "AppleWebKit") > -1 ) || 45 | // Opera Mobile less than version 11.0 (7458) 46 | !( ua.match( /Opera Mobi\/([0-9]+)/ ) && RegExp.$1 < 7458 ) || 47 | // Opera Mini 48 | !( w.operamini && ({}).toString.call( w.operamini ) === "[object OperaMini]" ) || 49 | // Firefox Mobile less than version 6 50 | !( ua.match( /Fennec\/([0-9]+)/ ) && RegExp.$1 < 6 ) 51 | // If necessary, add the other untestable browsers here... 52 | ){ 53 | //add the HTML class for now. 54 | docEl.className += " " + htmlclass; 55 | 56 | // bind to scroll event so we can test and potentially degrade 57 | if( w.addEventListener ){ 58 | w.addEventListener( "scroll", checkFixed, false ); 59 | } 60 | else{ 61 | w.attachEvent( "onscroll", checkFixed ); 62 | } 63 | } 64 | 65 | w.FixedFixed = checkFixed; 66 | }( this )); 67 | -------------------------------------------------------------------------------- /test/unit/fixed-fixed-tests.js: -------------------------------------------------------------------------------- 1 | /* global QUnit:false, module:false, test:false, asyncTest:false, expect:false, start:false, stop:false, ok:false, equal:false, notEqual:false, deepEqual:false, notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false, SocialCount:true */ 2 | (function() { 3 | 4 | /* 5 | ======== A Handy Little QUnit Reference ======== 6 | http://docs.jquery.com/QUnit 7 | 8 | Test methods: 9 | expect(numAssertions) 10 | stop(increment) 11 | start(decrement) 12 | Test assertions: 13 | ok(value, [message]) 14 | equal(actual, expected, [message]) 15 | notEqual(actual, expected, [message]) 16 | deepEqual(actual, expected, [message]) 17 | notDeepEqual(actual, expected, [message]) 18 | strictEqual(actual, expected, [message]) 19 | notStrictEqual(actual, expected, [message]) 20 | raises(block, [expected], [message]) 21 | */ 22 | 23 | module('Exists', { 24 | setup: function() { 25 | } 26 | }); 27 | 28 | test( 'FixedFixed is exported', function() { 29 | ok( typeof FixedFixed === "function" ); 30 | }); 31 | 32 | 33 | }()); 34 | -------------------------------------------------------------------------------- /test/unit/fixed-fixed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fixed-fixed Test Suite 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 |

fixed-fixed Test Suite

21 |

22 |
23 |

24 |
    25 |
    26 | 27 | 28 | --------------------------------------------------------------------------------