Mobile Compatibility and Degradation on Mobile Devices

March 7, 2012 at 6:00 pm By

I recently made a post about creating a share button that zoomed out with transitions on hover. Although I had been targeting desktops with the demo, a user called egypturnash pointed out that the demo didn’t work on iPads or touch enabled devices because there is no hover option available. You touch or you don’t touch. My demo simply wouldn’t work if there was no way to hover. So how do we go about fixing this problem?

Method 1: CSS Only

One of the most ways of dealing with mobile only design is through media queries. It’s become pretty standard, and mobile browsers will support these so assuming you’re using them for mobile, you shouldn’t run into much support issues.

The idea here is to change the item in such a way so that hovering is no longer needed. You could have a mobile only version without the effect, and then have the effect on desktops. To accomplish this we just need to pick a size which most mobile phone screens wont exceed. Then we can apply some CSS to this screen size.

@media screen and (max-width: 700px) {
    // ... CSS for mobiles
}

We can then override the default values for this screen size using !important if necessary. This is a type of degradation, which seems the first call of action when it comes to mobile devices.

Is Degradation Always Necessary?

Well no, of course not. There are various other options. Degradation as become a buzz word in the web design domain, often thrown about as a cure for the mobile plague, removing cool features and giving mobile users the barebones of a design. To look at an alternative to degradation, we need to include some Javascript.

Method 2: Javascript Only

This is useful though if you need to include a file only on mobile devices. Again, the easiest way to do this is by checking screen width. An alternative though would be to check the user agent, but that would be a very time consuming and silly thing to do. All you have to do is this:

<script type="text/javascript">
 
if(screen.width <= '700') { 
    // Javascript for small screen
}

</script>

Now it’s very easy to just include a different Javascript file or run a different CSS script, but if we put in a bit more of an effort we could make something truly mobile compatible.

Method 3: CSS+Javascript

The idea behind this method is we use some of the Javascript touch related event handlers. I covered this before, but here’s a little run down. The main event handlers are touchstart (when the user makes contact), touchend (when the user ends contact) and touchmove (when the user moves their point of contact).

We can then gather information using some arrays containing information. These variables are touches (the initial point of contact), targetTouches (information within a certain element), and changedTouches (the current position). So here’s a quick example:

if(screen.width <= '700') {
     
    function tutorial(e) {
        var touch = e.touches[0]; // If multiple fingers touch an array is created. We want the first finger
        document.write(touch.pageX); // Change content to the value of the initial X value of the finger
    }

    addEventListener('touchstart', tutorial, false); // Run the function when the user touches down
    
}

So that’s great and all, but how do we combine these? Pretty easy, actually. We have two options. Change the CSS manually in the Javascript, or import some new Javascript. If you’re using jQuery it’s even more straight forward. Taking the tutorial I did last week, I decided to on touch add the CSS for the hover state. Then when the user touched again, the CSS hover state would be removed so return it to its initial state. This would leave it much more mobile compatible.

Before we start, go check out what I’m talking about first! Here’s the original tutorial. First off, we want to include all the CSS initiating hover effects to be desktop only. So take all the CSS that has ‘hover’ in it, and include it in a media query.

@media screen and (min-width: 800px) {

	#buttons:hover {
		border: 15px solid #ddd;
		width: 160px;
		height: 160px;
		left: -40px;
		opacity: 1;
		top: -40px;
	}
	
	#buttons:hover .text {
		top: 60px;
		left: 35px;
		opacity: 0;
	}
	
	#buttons:hover div { opacity: 1; }
	
	#buttons:hover div:nth-of-type(2) { top: 0; left: -20px; }
	#buttons:hover div:nth-of-type(3) { top: 5px; left: 120px; }
	#buttons:hover div:nth-of-type(4) { top: 65px; left: -68px; }
	#buttons:hover div:nth-of-type(5) { top: 48px; left: 155px; }
	#buttons:hover div:nth-of-type(6) { top: 125px; left: -45px; }
	#buttons:hover div:nth-of-type(7) { top: 105px; left: 125px; }

}

Now we need to do another media query, for screen widths below a certain threshold. Remove all the hover psudeo-types and apply the same CSS to a class id called ‘buttons-touched’.


@media screen and (max-width: 700px) {

	#buttons {
		pointer-events: none;
		-webkit-transition: none !important;
	}
	
	#buttons div {
		-webkit-transition: none !important;
	}
	
	#buttons-touched {
		border: 15px solid #ddd;
		position: relative;
		width: 160px;
		pointer-events: auto !important;
		height: 160px;
		left: -40px;
		box-shadow: 0px 0px 10px #ddd, 0px 10px 0px #aaa;
		opacity: 1;
		top: -40px;
		-webkit-transition: none;
		border-radius: 100px;
		-moz-transition: none;
		-o-transition: none;
		-ms-transition: none;
	}
	
	#buttons-touched div {
		position: absolute;
		min-width: 100px;
		top: 15px;
	}
	
	#buttons-touched .text {
		top: 60px;
		left: 35px;
		opacity: 0;
	}
	
	#buttons-touched div { opacity: 1; }
	
	#buttons-touched div:nth-of-type(2) { top: 0; left: -20px; }
	#buttons-touched div:nth-of-type(3) { top: 5px; left: 120px; }
	#buttons-touched div:nth-of-type(4) { top: 65px; left: -68px; }
	#buttons-touched div:nth-of-type(5) { top: 48px; left: 155px; }
	#buttons-touched div:nth-of-type(6) { top: 125px; left: -45px; }
	#buttons-touched div:nth-of-type(7) { top: 105px; left: 125px; }

}

This required a little trial and error, but it wasn’t too difficult. I removed the transitions because these can be a little iffy on mobile devices. Go ahead and include your jquery.js file, and we’ll do a little bit of Javascript. First of all enclose the #buttons div in another div like this:

	
<div id="button_holder">

</div>

On the first click we want the CSS to be added, and on the second we want it to be removed, so I just used a variable and binded a function to the button holder. It wasn’t too difficult. Don’t forget to check the screen resolution too, to make sure that it’s a mobile sized screen!


$(document).ready(function() {

	if(screen.width <= '700') {	
	
		var x = 1;
	
		$('#button_holder').on('touchstart', function() {
					
			if(x == 1) {
				$("#buttons").attr('id', 'buttons-touched');
				x = 2;
			}
			else if(x == 2) {
				$("#buttons-touched").attr('id', 'buttons');
				x = 1;
			}
		});
	
	}

});

Problems

We made a few assumptions up above. We assumed that all mobile devices were touchscreens, and that all touchscreens had small screens. Is that true? Well we can safely assume that a mobile device with good web capabilities is touchscreen, and in fact very little traffic on mobile devices comes from non-touchscreens.

The problem arises when we assume that all touchscreens have small screens. With the advent of tablets, that is no longer true. So how do we approach that problem? We can use the screen size to cover most mobiles, but it won’t cover tablets. We need a way to determine if something is touch screen or not. One way is to manually check if the person is using a certain model or type:

if(navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || 
navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || 
navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/)) {
     // Touch Screen
}

This isn’t necessarily full proof though. You could have a blackberry without a touchscreen, or the user agent might change and you’d have to update the string. So what is the solution then? There is no if(mobile) but I found this pretty awesome piece of code from alastairc.ac. You can read more about it over there as I’d hate to steal credit.

function isTouchDevice() {
   var el = document.createElement('div');
   el.setAttribute('ongesturestart', 'return;');
   if(typeof el.ongesturestart == "function") {
      return true; // Is a touchscreen, run a function for touchscreens here
   } else {
      return false; // Is not a touchscreen. 
   }
}

Just run a function in the area where it returns true, and you should be able to pick out the touch screen specific devices. From there you can implement what we did earlier. For example:


$(document).ready(function() {	
	
	var el = document.createElement('div');
	el.setAttribute('ongesturestart', 'return;');
	if(typeof el.ongesturestart == "function") {
	
		var x = 1;
	
		$('#button_holder').on('touchstart', function() {
					
			if(x == 1) {
				$("#buttons").attr('id', 'buttons-touched');
				x = 2;
			}
			else if(x == 2) {
				$("#buttons-touched").attr('id', 'buttons');
				x = 1;
			}
		});
		
	} else {
		return false; // Is not a touchscreen. 
	}
});

Hopefully this will quell most problems, but who knows. If you have any questions leave them in the comments below! Thanks for reading. Have a good day!