Scrolling a overflow:auto; element on a touch screen device

Monday, May 03, 2010

In mobile Safari on the iPhone, iPod Touch, and iPad (as well as the webkit based browser on Android phones) it's not immediately obvious how to scroll a div that has overflow:auto; set on it. If this were a desktop browser you would see scrollbars and be able to manipulate those or even use your mouse wheel. No such concepts exist on a touch screen device!

To scroll the entire page you just touch it and move your finger. But when you touch the element that would normally scroll, the entire page scrolls instead. This is a little bit broken in my opinion since there's no visual indicator that you aren't seeing all the content. However, if you are on a site and you know there's a scrollable div there is a simple (but not obvious) workaround. Simple use two fingers at the same time and scroll them in the same direction.

This works OK but like I said it's not obvious, there's still no indicator that the content is scrollable, and when you use more than one finger you might accidentally trigger some other gesture like scaling the page. I recently ran into this exact issue at work and came up with a pretty solid solution in javascript. I broke this down into two simple functions, but the last one is where the magic happens.

This first function simply attempts to create a new touch event. Only touch screen browsers like mobile Safari have these events, so if it doesn't throw an error then we are using a touch screen device. Otherwise it's probably a desktop browser.

function isTouchDevice(){
	try{
		document.createEvent("TouchEvent");
		return true;
	}catch(e){
		return false;
	}
}

Next, this function calls the isTouchDevice() function, and if it succeeds we attach some special touch events to the page. First when a touch event begins (the touchstart event) we get the current scroll position and prevent the default browser behavior, which in this case would be to scroll the page. Next when you move your finger the touchmove event is called. Here we just subtract the position of your finger from the scroll position we saved earlier and again prevent the page from scrolling.

function touchScroll(id){
	if(isTouchDevice){ //if touch events exist...
		var el=document.getElementById(id);
		var scrollStartPos=0;

		document.getElementById(id).addEventListener("touchstart", function(event) {
			scrollStartPos=this.scrollTop+event.touches[0].pageY;
			event.preventDefault();
		},false);

		document.getElementById(id).addEventListener("touchmove", function(event) {
			this.scrollTop=scrollStartPos-event.touches[0].pageY;
			event.preventDefault();
		},false);
	}
}

So that's it, just include these functions on your page and just call it by passing in the ID of the element you want to scroll. Like so: touchScroll("MyElement");. You can see a working demo here: http://chris-barr.com/files/touchScroll.htm. I feel like this is a better way of doing things because it's more intuitive since you're just using one finger, and it's potentially more obvious. Even if you don't immediately know there's hidden content, you might accidentally touch this while scrolling the page and realize there's more to see in this div.

Posted by Chris Barr on 05/03 at 11:48 PM
Filed under Web, Code, Javascript, CSS5 Comments

Typographical Javasctipt Clock

I was bored, so I made one.  Check it out here: http://chris-barr.com/files/text%20clock/

Posted by Chris Barr on 05/03 at 11:41 PM
Filed under Projects, Web, Code, Javascript0 Comments

Detect browser support for CSS properties

Tuesday, September 22, 2009

Adding shadows or rounded corners to any element is way more trouble than it should be, especially if you're tried out some of the newer CSS3 properties. A simple two lines of CSS can get you these amazingly gorgeous effects, but as expected they aren't supported in every browser (I'm looking at you Internet Explorer!)

Some older versions of browsers that do support these features don't use the official W3C method and you have you use a vendor specific CSS property,like so:

#coolElement{
    box-shadow:#000 3px 3px 8px;
    -moz-box-shadow:#000 3px 3px 8px;
    -webkit-box-shadow:#000 3px 3px 8px;
    border-radius:5px;
    -moz-border-radius:5px;
    -webkit-border-radius:5px;
}

So, that of course won't work in IE, and if you want to have rounded corners or shadows on IE you have to make some custom PNG images and align everything properly. It's a lot of work, but it must be done if you want it to look consistent across all browsers. I realized today that ideally I want to do both, meaning that I want to use the pure CSS method when it's available in the browser, and the old clunky way otherwise.

Sure I could just see what works in each browser and only allow certain versions of browsers, but I'd always have to come back and update that list as future browsers add support for these things. Instead, why not test and see if the browser supports these features first, and then decide what to do.

function supportsBoxShadow(){
  var s=document.body.style;
  return s.WebkitBoxShadow!== undefined||s.MozBoxShadow!==undefined||s.BoxShadow!==undefined;
}
function supportsBoderRadius(){
  var s=document.body.style;
  return s.WebkitBorderRadius!== undefined||s.MozBorderRadius!==undefined||s.BorderRadius!==undefined;
}

Those functions will return true if the CSS property is supported in the browser, and not just the W3C property, but the vendor specific property as well. If there's some other property you want to test, follow the same pattern and just use CamelCase and remove the hyphens.

So putting this into practice is pretty simple, assuming we use the CSS property defined above.

if(supportsBoxShadow()){
    //Woo! We don't have to do anything! CSS does all the work!
}else{
    //Write your complex code here to position your PNG shadows.... :(
}
Posted by Chris Barr on 09/22 at 09:43 AM
Filed under Web, Code, Javascript, CSS1 Comments

Comparing jQuery objects

Tuesday, July 21, 2009

Just wanted to post a quick blog update with a cool jQuery trick I’ve been using recently. Every now and then I need to compare one jQuery object to another but a simple $(this) == someObject doesn’t do anything. As it turns out jQuery objects are actually stored internally as an array and you can’t just directly compare arrays.

So with that in mind, the easiest and quickest solution is to just access the items in the array and compare those instead. Luckily the very first item in the jQuery array is all we need here, so to access it you simply need to put in square brackets the array item number you want like so: $(this)[0]. So check out the code example below.

<div id="nav">
    <a href="#">link 1</a>
    <a href="#">link 2</a>
    <a href="#">link 3</a>
    <a href="#">link 4</a>
</div>

<script type="text'javascript">
$(
    allItems = $("#nav a");  
    secondItem = $("#nav a:nth-child(2)");

    //loop through each item in this jQuery collection
    allItems.each(function(){
        //Compare the current jQuery object with the saved jQuery object
        //by accessing the first item in the array of each object.
        if($(this)[0] == secondItem[0]){
            //we are on the second item! Give it a red background
            $(this).css("background-color","red");
        }
    });
});
</script>

   

Posted by Chris Barr on 07/21 at 09:21 PM
Filed under General, Web, Code, Javascript3 Comments

Guessr - A Flickr Game!

Tuesday, April 14, 2009

So, I wrote a game! It's something I've been wanting to do and had the idea for a while now. The premise of the game is that a random word is selected, a search of Flickr.com is performed with that word and you see the images from that search. Now you have 30 seconds to guess what that word is!

The game is entirely written in javascript/jQuery and is completely themable with jQuery UI. I wrote the majority of it in one afternoon, and made some updates the following week based on some great feedback from friends on Twitter and just some better usability ideas I had.

Take a shot at it and let me know what you think. I hope to find the time soon to make even more improvements to the game.

Play Guessr!

Posted by Chris Barr on 04/14 at 09:41 PM
Filed under Photography, Design, Projects, Web, Code, Javascript, Gaming6 Comments

Mix ’09 Session Videos

Sunday, March 29, 2009

I just got back from the Mix '09 conference in Las Vegas, and it was so much better than I expected! For being a Microsoft sponsored conference mostly focusing on .NET and other MS technologies, there was about 50% Mac users there and most of these people were designers. It was a really nice mix (haha?) of designers and developers. I've got some photos from my trip up here on Flickr.

I think one of the best things they do is put up ALL the session videos online for free! There's some really valuable information in these! http://videos.visitmix.com/MIX09 (also you can view past years MIX sessions at http://videos.visitmix.com )

Here's some highlights I'm going to recommend:

  • Web Form Design - absolutely one of the best sessions I attended. Watch this video! He talks about why forms suck and what we as designers can do to help the process along. Very very well done and extremely informative. As soon as this session was over I went and bought the speakers book.
  • The Way of the Whiteboard: Persuading with Pictures - Anotehr great session, but not necessarily directly related to web design. It's on how to get ideas out of your head and communicate them properly to people via a whiteboard of napkin.
  • Measuring Social Media Marketing - If you or your company does any kind of social media marketing, this is a great one.

The following sessions I did not attend, but they seem great:

And finally, for any other ASP.NET or Visual Studio users, These are somre great previews of what's coming soon!

Finding Unused CSS Rules

Wednesday, March 04, 2009

The other day I ran across a very useful article about the $$ selector in Firebug for Javascript and how to use it to loop through your stylesheets to find unused CSS styles. Very cool. The original code snippet would output everything to the firebug console, which I found to be useless on larger sites because I would hit Firebug's limit too often.

I modified it a bit to output the CSS to the actual site instead inside a styled element. So to use this on your own site, just copy and paste the code below into Firebug's console and hit run.

//Create a styled place to output styles to
var output = document.createElement('pre');
output.setAttribute("id","unusedCSSstyles");
output.setAttribute("style","height:95%; overflow:auto; text-align:left; background:#000000; border:2px outset #00CC33; color:#00CC33; opacity:0.9; padding:3px; position:fixed !important; left:5px; top:20px; width:95%; z-index:9998; font-size:12px;");

//create a styled close button
var closeBtn = document.createElement('a');
closeBtn.setAttribute("id","cssCloseBtn");
closeBtn.setAttribute("href","#");
closeBtn.setAttribute("onclick","document.body.removeChild(document.getElementById('unusedCSSstyles')); document.body.removeChild(document.getElementById('cssCloseBtn')); return false;");
closeBtn.setAttribute("style","position:fixed !important; left:2; top:0; z-index:9999; color:red; font-size:16px; padding:3px 20px; background-color:#000000; border:1px solid #FFF;");
closeBtn.innerHTML="close";

//add button and output element to body
document.body.appendChild(closeBtn);
document.body.appendChild(output);

//Find each stylesheet
for(var i = 0; i < document.styleSheets.length; i++) {
//write the filename to output element
output.innerHTML+="<br /><h3>"+document.styleSheets[i].href+"</h3>";
//find CSS rules
  for (var j = 0; j < document.styleSheets[i].cssRules.length; j++) {
    s = document.styleSheets[i].cssRules[j].selectorText;
    //write unused CSS rules to output element
    if ($$(s).length === 0) output.innerHTML+="<strong>["+j+"]</strong> "+s+"<br />";
  }
}

Do note that this has a few limitations:

  • It cannot find stylesheets from another domain or subdomains
  • It cannot find inline styles or the <style> tags anywhere
  • It will not work on sites that use Mootools since it also uses the $$ selector. (this site does, so don't try it here!)

If you're really serious about finding what CSS styles you haven't used on your site, you might want to check out a Firefox plugin called Dust Me Selectors

Posted by Chris Barr on 03/04 at 11:20 AM
Filed under Web, Code, Javascript, CSS, Productivity0 Comments

Disable Text Selection With jQuery

Saturday, February 07, 2009

I was recently working on an interface where there would be a log of dragging, scrolling and clicking - an unfortunate side effect of these type of things is that the user may sometimes unintentionally select text. Which this doesn't break anything, it just looks bad can ruin the smooth experience you are trying to present the user with. It turns out that every browser has either some kind of hidden CSS or javascript function to prevent text selection.

I searched around and eventually came across this page on James Dempster's site. He wrote a simple jQuery plugin to turn off text selection only for the elements you specify. His plugin works just fine, but I believe it can be simplified. Below is my version.

$(function(){
	$.extend($.fn.disableTextSelect = function() {
		return this.each(function(){
			if($.browser.mozilla){//Firefox
				$(this).css('MozUserSelect','none');
			}else if($.browser.msie){//IE
				$(this).bind('selectstart',function(){return false;});
			}else{//Opera, etc.
				$(this).mousedown(function(){return false;});
			}
		});
	});
	$('.noSelect').disableTextSelect();//No text selection on elements with a class of 'noSelect'
});

After you include jQuery on your page, just include this script and any element with a class of noSelect will not be able to have it's text highlighted — easy! (Obviously you can change the class name to be whatever you want though.)

Do take note that the plugin is contained within the $(document).ready(function(){/*your code here*/}); (which can also be written as $(function(){/*your code here*/}).) That just sets it up as a method to be called. To call the method and disable text selection you just get a standard jQuery element and add the method onto it : $('.noSelect').disableTextSelect();

Posted by Chris Barr on 02/07 at 07:30 PM
Filed under Web, Code, Javascript16 Comments

How to use the YUI compressor

Saturday, December 13, 2008

Compressing your javascript and CSS is a easy way to save bandwidth and make a site’s download and performance feel a bit snappier. There’s lots of tools to allow you to do this, but from my research it seems that Yahoo!‘s YUI compressor is the overall best.  Sure there’s others out there like JSmin and Dean Edward’s packer, but YUI offers a higher compression ratio, it also works with CSS files, and it’ won’t obfuscate your code.

Compressors work by removing all comments and whitespace (line breaks), and in some cases they will actually analyze your code and shrink variable names.  Using compression can result in up to a 60% decrease in file size!  So lets get started in learning how to use the YUI compressor!

Read more...
Posted by Chris Barr on 12/13 at 11:52 PM
Filed under General, Web, Code, Javascript10 Comments

Textarea resizer for Mootools 1.2

Saturday, December 06, 2008

A long time ago I wrote a small plugin for Mootools to resize textareas on the fly, which I simply called Textarea resizer.  It was only compatible with Mootools 1.11, and since then Mootools 1.2 has been released and I’ve switched to jQuery for all the stuff I do.

Someone over at ljpilon.nl emailed me to let me know they re-wrote my plugin for Mootools 1.2 compatibility!  You can find it over at their site at: http://ljpilon.nl/mootools/2008/12/03/textarea-resizer-for-mootools-12/

Posted by Chris Barr on 12/06 at 03:32 PM
Filed under Web, Code, Javascript0 Comments

Adding Table Rows With jQuery

Saturday, November 22, 2008

Recently I needed a way to click a button and add a new row to a table with an animation using jQuery for people to add new data for a section. Simple right? Well I set up my table with a blank row at the bottom that I hid with CSS, and then when I press a button it clones that row it and puts it at the top with a .slideDown() animation. Here's the code I used:

$("#addRow").click(function(){
	$("#blankRow").clone().prependTo("#myTable tbody").removeAttr("id").slideDown(500);
});

Looks pretty straightforward right? Well it works, but it doesn't seem to render correctly. Here's a demo of this in action to see what I mean.

Turns out that for most jQuery animations when they complete, the display CSS property is set to display:block;. Normally that's all fine and good, but a table row has to be set to display:table-row;. I can't edit how that animation finishes since it's part of jQuery, so now what?

View a Demo

View the Code

Download It!

Well someone on the jQuery Google Group had the great idea to just fill each table cell with a <div>, put all the contents I needed in there, and simply apply the .slideDown() animations to that <div> since by default they are set to display:block; anyway. Brilliant! Basically we never animate the table row itself, only the elements inside it.

I put together a pretty full featured demo with some other cool jQuery tricks I've been learning recently, so take a look and I hope this will help someone else out.

Posted by Chris Barr on 11/22 at 06:24 PM
Filed under Projects, Web, Code, Javascript27 Comments

Ajax Forms in Expression Engine with FreeForm

Friday, March 21, 2008

Introduction

Something I've been wanting for a while was a way to integrate a contact form in Expression Engine with some nice AJAX effects from my favorite Javascript library, Mootools. I've not been able to find anything out there that does exactly what I want, so I've made my own. This does require the FreeForm Module for Expression Engine from Solspace as well as Mootools 1.11.

View a Demo

Download It! (v. 1.1.1)

Click the jump for more information on how to set this up...

Read more...
Posted by Chris Barr on 03/21 at 12:00 AM
Filed under Projects, Web, Code, Javascript9 Comments