├── .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 | [](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 |
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.
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.
135 | 136 |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.
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.
164 | 165 |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.
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.
193 | 194 |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.
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.
222 | 223 |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.
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.