MooTools ScrollSpy, Mobile Devices, JavaScript Scroll Events, and CSS Positioning

By  on  

One question I've been asked often is why ScrollSpy and my Go To Top link functionality don't appear to work well on the iPhone, iPad, or any other mobile device.  The problem is simple to identify and easy to fix.  The issue comes down to the way mobile devices view fixed-positioned elements.  Let me explain to you the scenario, problem, and solution to making the "Go To Top" link follow the user as they scroll.

ScrollSpy's / "Go To Top" Basic Usage

The first step will be creating the CSS for the "Go To Top" link.  The link will be styled to work well within the traditional browser since that's our priority.

#totop { 
	color:#090; 
	font-weight:bold; 
	text-shadow:1px 1px 0 #ccc; 
	bottom:10px; 
	right:10px; 
	font-size:1.1em; 
	position:fixed; 
	display:block; 
	z-index:10; 
}

The link is set to display 10px from the bottom of the screen at any given time.  The ScrollSpy usage is fairly simple;  when the "enter" threshold is met, the element fades in:

// When the DOM is ready
window.addEvent("domready",function() {
	// Create the "top" link
	var top = new Element('a', { 
		id: 'totop', 
		text: 'Top', 
		styles: { opacity: 0 }, 
		href: '#top' 
	}).inject(document.body);
	// Create a ScrollSpy instance
	var spy = new ScrollSpy({
		min: 150,
		onEnter: function(pos) {
			top.fade(1);
		},
		onLeave: function(pos) {
			top.fade(0);
		}
	});
});

At this point, the "Go To Top" link functionality will work great within your typical web browser.  Your mobile browser?  Not so much.  Why?

The Mobile Issue

The reason you wont see the GTT link follow the browser as it scrolls is two fold:

  1. Your mobile device's browser sees the the page as one "view", and pages downward.  Thus, fixing a link to the bottom keeps it there, regardless of where the user is in the page.
  2. The scroll event only fires at the end of the user's scroll, not during, so the link will not follow the user as they scroll.  Once the scroll ends, the link will "jump" down to the bottom of the view.

With those two details in mind, let's fix this scrolling CSS problem.

The Solution:  Position Reassignment onScroll

The only way to fix the scrolling problem is to adjust a few of the CSS settings we provided for the traditional browser.  Instead of using fixed positioning, we're going to use absolute positioning and we'll also update the CSS top setting to place the element within the viewport.

// If this is an iOS mobile platform...
if(Browser.Platform.ios || Browser.Platform.android) {
	// Change styling of the TOP element's position
	top.setStyles({ 
		position: "absolute", 
		bottom: "auto" 
	});
	// Add a scroll event to...
	spy.addEvent("scroll",function(position) {
		// ...position the element
		 // 20px offset from bottom
		top.setStyle("top",(position.y + window.getSize().y - 20) + "px");
	});
}

One we establish that the client is a mobile browser, we swap out the positioning styles and add a scroll event to ScrollSpy to update the top position of the GTT link at the end of every scroll.  Probably easier than you thought, no? This solution was tested on iPad, iPhone, and Android.

There you have it!  The problem isn't with ScrollSpy;  it's with the way that mobile browsers handle fixed positioning.  No updates to ScrollSpy will be made on account of mobile, as ScrollSpy is simply used to get positioning information;  as long as the position information is provided, you can add positioning styles to desired elements.

Recent Features

  • By
    Being a Dev Dad

    I get asked loads of questions every day but I'm always surprised that they're rarely questions about code or even tech -- many of the questions I get are more about non-dev stuff like what my office is like, what software I use, and oftentimes...

  • By
    How I Stopped WordPress Comment Spam

    I love almost every part of being a tech blogger:  learning, preaching, bantering, researching.  The one part about blogging that I absolutely loathe:  dealing with SPAM comments.  For the past two years, my blog has registered 8,000+ SPAM comments per day.  PER DAY.  Bloating my database...

Incredible Demos

  • By
    Form Element AJAX Spinner Attachment Using MooTools

    Many times you'll see a form dynamically change available values based on the value of a form field. For example, a "State" field will change based on which Country a user selects. What annoys me about these forms is that they'll often do an...

  • By
    Editable Content Using MooTools 1.2, PHP, and MySQL

    Everybody and their aerobics instructor wants to be able to edit their own website these days. And why wouldn't they? I mean, they have a $500 budget, no HTML/CSS experience, and extraordinary expectations. Enough ranting though. Having a website that allows for...

Discussion

  1. Brandon

    Good article and explanation. Personally I don’t think ScrollSpy does a good job of imitating a fixed position element on mobile because as you stated it doesn’t fire until the scroll is complete. So the “fixed” element always jumps to it’s new location. It’s fine for a link as you’ve shown in your demo, but for something more substantial like a header/footer/navigation one should consider eliminating all native scrolling events and rolling your own. Google recently wrote a good article, although half complete, on how they do “fixed” positioning for their mobile Gmail sites. It’s a good read and I recommend checking it out if you haven’t already, maybe put some Mootools spin on it.

    http://code.google.com/mobile/articles/webapp_fixed_ui.html

  2. Thanks David. Works like a CSS dream.

  3. Hi, your demo no longer loads in chrome (ie for mobile viewing through the simulator) because mimetype is set to text for the scrollspy file and chrome is enforcing strict mimetype headers

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!