Fixing Fixed Headers Presentation by Nick Dreckshage and Marcus Labrecque

Download Source Code View on Github

Introduction
To run locally, download source and run over local server. Like...
$ python -m SimpleHTTPServer 8000
Marcus Labrecque

Marcus Labrecque

  • Product Manager for Wayfair and Joss & Main
Nick Dreckshage

Nick Dreckshage

What it looks like... Not what it looks like...
// if you want to check out jossandmain without signing up, copy and paste this to console...

$('.yui3-overlay-mask, .yui3-modal').remove();
$('.footer_links').removeClass('logged_out');
Overview

Theme -- Fixed header as a toolbar

  • Sticky menus study
  • Fitt's Law
  • Meta toolbar!
Examples

The good. The bad.

  • Consistency
  • Context
  • Execution (check out Facebook)

Fab — Consistent?

Fab 1 Fab 2 Fab 3 Fab 4

One Kings Lane — Breadcrumbs great; almost there.

OKL 1 OKL 2

Pinterest — Great nav; execution?

Pin

AirBNB — UX ideal; execution?

Air BNB
Determine Purpose

What does the user need?

  • It has what you want, when you want
  • Everything is in same location
  • The tools you have do what you want them to

Risks...

  • Risk of distraction/annoyance
  • Restrictions on placement
  • Not ideal for mobile unless done perfectly
Wireframes 1 Wireframes 1
Code (Basic)

Dangerously easy...

  • The minimum code
  • Bootstrap/Boilerplate
  • Fluid grids vs. fixed width
  • Fixed + responsive header on fixed width?
  • Challenges with a fixed header

Minimum code

/* all it takes is css */

header{
position:fixed;
top:0;
z-index:5;
width:100%;
height:50px;
background:#e0e0e0;
}
section{
margin-top:50px;
height:1000px;
background:#eee;
}

Bootstrap + Fluid Grids (If it works for you, go for it. Bootstrap's great.)

Bootstrap

Fixed + responsive on fixed width? No.

Joss
Code (Intermediate)

Improving on basic implementation...

  • Scroll listeners
  • Media Queries
  • Modernizr
  • Zoom detection
  • Touch Devices
  • Hover Intent
  • Fallback for Non-JavaScript (Not this site!)

Scroll listeners

// if we want an offset, either for side nav (like in demo), or nav that becomes fixed on scroll (like pinterest/etc)

function checkOffset(){
return $(window).scrollTop() > 40 ? true : false;
}

Media Queries (assets/css/ffh.css)

/**
this gets rid of unnecessary fixed elements, and disables fixed for the others. if you have a fixed width site, it is probably worse ui to have the header fluid.
*/

@media only screen and (max-width:940px){
.ffh.ffh_fixed{
position:relative;
}
.ffh_spacer{
display:none;
}
.jq_ffh_scrollspy{
display:none;
}
.ffh_right{
padding:0;
width:100%;
}
}
@media only screen and (max-height:450px){
.jq_ffh_scrollspy{
display:none;
}
}

Modernizr (assets/js/ffh/fixedCheck.js)

Modernizr
// if media queries not supported, replicate via js

var mediaQueries = Modernizr.mq('only all'),
ieWidth = null,
ieHeight = null,
$w = $(window);

// CHECK SOURCE FOR ACTUAL IMPLEMENTATION. this would need to be in a function call...

if (!mediaQueries) {
ieWidth = $w.width();
ieHeight = $w.height();
}

// will do the checks in a minute...

Zoom detection (assets/js/ffh/fixedCheck.js)

// determine zoom level on  (again, check source for actual implementation)

function checkZoom(){
return detectZoom.zoom();
}

// ...

// then something like this...

if (zoom > 1 || (!mediaQueries && ieViewport < 940)){
$element.removeClass('fixed');
}

Touch -- again with Modernizr (assets/js/ffh/dropDown.js)

var touchEnabled = Modernizr.touch;

// then you can run checks against touch devices, and decide whether to hover, or have click dropdowns, for example

if (touchEnabled){ // ...

Hover Intent and Amazon's hover (assets/js/ffh/dropDown.js)

// you can also pass in options to change the sensitivity/timing settings

$('header').hoverIntent(initDropDown, 'li');

Fallback if JS Disabled

/* target with Modernizr. if you have a dropdown menu with important header information, for example. */

.no_js header ul:hover div{
display:block;
}
Code (Intermediate +)

Make it modular...

  • Grid format
  • Page specific
  • API

Simple Grid (assets/css/ffh.css)

.ffh_hd_grid_1  { width:188px;        }
.ffh_hd_grid_2 { width:376px; }
.ffh_hd_grid_3 { width:564px; }
.ffh_hd_grid_4 { width:752px; }
.ffh_hd_grid_5 { width:940px; }
.ffh_hd_off_1 { margin-left:188px; }
.ffh_hd_off_2 { margin-left:376px; }
.ffh_hd_off_3 { margin-left:564px; }
.ffh_hd_off_4 { margin-left:752px; }

Serving what is relevant to the page

<?php

// language doesnt matter. important to think of the header as more than just a 'page block.' it could be part of a header specific function library where you can easily populate with relevant data.

private static function switch_content($page){
switch($page) {
case self::HOME_PAGE :
self::fill_hd($widget_1 = true, $widget_2 = false);
break;
case self::ABOUT_US :
self::fill_hd(false, true);
break;
default :
self::fill_hd(true, true);
break;
}
}
?>

Using an API (assets/js/ffh/api.js and api/ffh.json)

// this site is using a fake json api (not real content from server). but this could theoretically work with ember.js/backbone/etc. could come in handy if using infinite scroll.

var api;

$.getJSON('/api/ffh.json', function(data){
$('#ss').on('activate', '.jq_ffh_api', function(){
api = $(this).data('api');
$('.jq_ffh_nav').html(data[api]);
// init non-delegated js (config dropdown) in header
initToggles('.ffh_toggle', 'ffh_toggle_off');
});
});
Before/After

Worth all the trouble? Hopefully...

  • Side by Side
  • Google Analytics
Side by Side
Conclusion/Questions
Flat UI

If you liked the UI, download it.

Front End Developers