With position: sticky we can finally set a container/element in a certain sticky position.

A short Reminder:

Until now webdesigners could assign the following positions to container/elements:

  • position: static (default)
  • position: relative (relative position in document order)
  • position: absolute (absolute position in relative context)
  • position: fixed (fixed in viewport)

The idea to put a container/element from a specific location “sticky”, (but not before scrolling first, allowing the element to scroll along for a while, and then fix it to a certain position) has been there for quite a while in web design. I can still remember when @rem on jqueryfordesigners.com explained the inner workings for this in jQuery.

For some time now, there is a new CSS3 property that implements the same behavior natively in the browser. This is already enabled in Safari 6.1 and later (with -webkit-prefix), and also works in Safari Mobile. Chrome and Firefox (on Android) have the property currently behind a flag, Microsoft thinks about it.


enable position: sticky in Chrome/Firefox

in Chrome’s adressbar go to: chrome://flags/#enable-experimental-web-platform-features hit enter, and enable “experimental Web Platform features”.

in Firefox in the adressbar go to about:config hit enter, (promise to be careful) and search for layout.css.sticky.enabled : ‘double clicking’ the result will set the value to true.


Usage in CSS


.sticky {
  position: -webkit-sticky;
  position: sticky;
}

Modernizr Feature Detection

With Modernizr I can, with an additional integrated test, check whether the browser supports position: sticky or not. On the http://modernizr.com/download/ is the option under "Non-core Detects," from where you can check the box and generate a custom build.

When using grunt-modernizr there’s an extra option for a test with tests: ['css-positionsticky'] in the Grunt-Config (gruntfile.js):

// Build modernizr
modernizr: {
dist: {
devFile: 'path/to/source/modernizr.js',
outputFile: 'path/to/build/modernizr.min.js',
files: {
  src: [
    'js/{,*/}*.js',
    'css/{,*/}*.scss',
    '!js/vendor/*'
  ]
},
uglify: true,
parseFiles: true,
tests: ['css-positionsticky']
}
}

The property can then be queried using Javascript:

Modernizr.csspositionsticky; // true or false

Fallbacks and Polyfills

I always tend to only set a visual behavior for browsers with full native support. Especially with responsive webdesign a fallback for position: fixed becomes increasingly difficult to implement, because the dynamic positions of Javascript should always be recalculated, which may of course have a negative impact on performance.

Therefore the fallback should always be tested.

Currently, I recommend using the sticky properties only with additional feature detected classes. So set the position (top/bottom) only together with sticky.

Example

.sticky {
  position: static;
}
.csspositionsticky .sticky {
  position: sticky;
  top: 20em;
}

Polyfill:

The Filamentgroup has posted a Polyfill for position: sticky which implements the behavior for browsers that do not support the property.

When needed one can load the polyfill via Modernizr.load

Modernizr.load({
test: Modernizr.csspositionsticky,
nope: 'fixedsticky.js'
});

Note: in Modernizr 3.0 will Modernizr.load (which under the hood is “yepnope”) be dissolved again; use yepnope then.

I hope, Chrome and Firefox will release the property soon - leaving us with missing only IE …