I discovered an odd feature of the mobile Safari browser on IOS 5 on my iPad. I suspect that this is the same for the iPhone and iPod as well. If a page is set up so that it takes 100% of the screen and then the page scrolling is disabled by capturing and preventing the default action of the touchmove events, the page doesn’t have that rubber band feel that most pages have. The page will simply not scroll at all.

Now add in a textarea form field, with or without an actual form, and the page can scroll if the user has reached the edge of the textarea content. In other words, scroll the text area until the end of the data is reached. Scrolling stops. Then try to scroll more and the page scrolls!

This is terrible design on the part of the developers. The touchmove event that is generated indicates that it is for the textarea but it affects the page. It is just a bug or a bad design decision. I suspect that it was an accident that the developers didn’t have time to think about let alone fix.

The fixes I read about all day today included hidden divs and spans and other strange things but no one comment or post said that it had worked. No one seemed to have a fix although some seemed to get close.

I solved this. My fix is to determine if the textarea has reached the beginning or end of the data and after that, touchmove events are rejected. The hard part is in figuring out if the edge of the data is reached. I had to detect the direction of the scroll and then figure out if the textarea was at the beginning of the data or end. Here is the JavaScript code to do this:

document.addEventListener( 'touchmove', function (e) 
{ 
	var target = e.target;
	while ( target.nodeType != 1 )
		target = target.parentNode;
					
	if( target.tagName == 'TEXTAREA' )
	{
		var screenY = e.touches[0].screenY;
		if( screenY > lastScreenY )
		{
			if( target.scrollTop == 0 )
				e.preventDefault();
		}
		else if( screenY < lastScreenY )
		{
			if( target.scrollTop + target.offsetHeight == target.scrollHeight )
				e.preventDefault();
		}
		else
				e.preventDefault();
		
		lastScreenY = e.touches[0].screenY;
	}
	
	if ( target.tagName != 'BUTTON' && target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA' )
	{
		e.preventDefault();
	}
				
}, false );

document.addEventListener( 'touchstart', function (e) 
{ 
	var target = e.target;
	while ( target.nodeType != 1 )
		target = target.parentNode;
	if( target.tagName == 'TEXTAREA' )
	{
		lastScreenY = e.touches[0].screenY;
	}
}, false );

I am running an iPad 2 with IOS 5. My pages use iScroll but there is no scrolling element on the page in question. I did change iScroll to not do any interception of the scrolling events related to the textarea by changing the iScroll onBeforeScrollStart() function. My textarea should be exactly like a text area on any other page.

My page has only the textarea and it has zero orders, zero padding, and zero margins. Styling of it is done by sticking it inside of other elements that are styled.

I hope that this is workable for others. I’ve been posting my fix on a few forums where I saw solutions that didn’t work (not really solutions at all).