How to Make an iPhone Back Button in jQuery Mobile

Creating an iOS-like back button using CSS3 without images is an interesting challenge. It gets tricky when you try to do it within the boundaries of jQuery Mobile 1.1.0. To get started, let’s consider a basic HTML code for a jQuery Mobile page with a simple back button located inside the header:

1
2
3
4
5
6
7
8
9
<div data-role="page" id="main">
    <div data-theme="c" data-role="header">
        <h3>
            Header
        </h3>
        <a href="#" data-role="button" data-rel="back" data-icon="arrow-l">Back</a>
    </div>
    <div data-role="content"></div>
</div>
<div data-role="page" id="main">
    <div data-theme="c" data-role="header">
        <h3>
            Header
        </h3>
        <a href="#" data-role="button" data-rel="back" data-icon="arrow-l">Back</a>
    </div>
    <div data-role="content"></div>
</div>

When the page is done loading, jQuery Mobile auto-magically modifies the structure of the back button. It adds new elements to accommodate and generate borders and shadows that look really professional.

iOS Button - Part 1

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- original button -->
<a href="#"
    data-role="button"
    data-rel="back"
    data-theme="a"
    data-icon="arrow-l"
    >
    Back
</a>
<!-- modified button -->
<a href="#"
    data-role="button"
    data-rel="back"
    data-theme="a"
    data-corners="true"
    data-shadow="true"
    data-iconshadow="true"
    data-wrapperels="span"
    class="ui-btn-left ui-btn ui-shadow ui-btn-corner-all ui-btn-up-a"
    >
    <span class="ui-btn-inner ui-btn-corner-all">
        <span class="ui-btn-text">
          Back
        </span>
        <span class="ui-icon ui-icon-arrow-l ui-icon-shadow">&nbsp;</span>
    </span>
</a>
<!-- original button -->
<a href="#"
	data-role="button"
	data-rel="back"
	data-theme="a"
	data-icon="arrow-l"
	>
    Back
</a>
<!-- modified button -->
<a href="#"
	data-role="button"
	data-rel="back"
	data-theme="a"
	data-corners="true"
	data-shadow="true"
	data-iconshadow="true"
	data-wrapperels="span"
	class="ui-btn-left ui-btn ui-shadow ui-btn-corner-all ui-btn-up-a"
	>
	<span class="ui-btn-inner ui-btn-corner-all">
		<span class="ui-btn-text">
          Back
        </span>
    	<span class="ui-icon ui-icon-arrow-l ui-icon-shadow">&nbsp;</span>
    </span>
</a>

As you can see the trickiness comes from the fact that we have to add a point to the left side of the button. This point should use the same background as the button without relying on any bitmap image. I am sure there are many ways to accomplish this task. For the purpose of this article I will take the following steps:

  1. Adding a custom theme to the button element
  2. Removing the icon and adding a new element to use it as the button point
  3. Customize the button’s background and borders
  4. Use CSS to transform and position the point
  5. Simplifying everything for future use

Adding a custom theme

When we assign a custom theme to a button, jQuery Mobile generates several CSS classes that allow us to modify the different states of the button. In this example I will assign a custom theme named app-ios which will expose the following CSS classes: ui-btn-up-app-ios; ui-btn-hover-app-ios; and ui-btn-down-app-ios.

1
<a data-role="button" data-rel="back" data-icon="arrow-l" data-theme="app-ios">Back</a>
<a data-role="button" data-rel="back" data-icon="arrow-l" data-theme="app-ios">Back</a>

Removing the icon and adding a point

To remove the icon we can simply select the .ui-icon element and remove it from the DOM. In addition to this, we will have to add an element to render the point. The goal is to create a small square and apply a gradient to it. We will also need to scale it and re-position it on the left side of the button.

1
2
3
4
5
// Javascript code to manipulate the DOM
$(document).ready(function(){
    $('a[data-theme="app-ios"]').find('.ui-icon').remove();
    $('a[data-theme="app-ios"]').append('<div class="ios-tip"><span>&nbsp;</span></div>');
});
// Javascript code to manipulate the DOM
$(document).ready(function(){
    $('a[data-theme="app-ios"]').find('.ui-icon').remove();
    $('a[data-theme="app-ios"]').append('<div class="ios-tip"><span>&nbsp;</span></div>');
});

Customize the background

Now that we have the modified structure we can start applying CSS rules to make the default button theme look like an iPhone button.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* button background and borders color */
a[data-theme="app-ios"] {
    border: none;
    }
    a[data-theme="app-ios"] .ui-btn-corner-all {
        border: 1px solid rgba(0,0,0, 0.4);
        -webkit-border-radius: 5px;
        background: -webkit-gradient(linear, left top, left bottom, from(#9fb3cc), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
        -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        overflow: visible;
        padding-left: 8px !important;
        padding-right: 8px !important;
        }
/* shadows and label color */
a[data-theme="app-ios"].ui-shadow,
a[data-theme="app-ios"] {
    box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
    background-clip: none; -webkit-background-clip: none; -moz-background-clip: none;
    color: white;
    font-weight: bold;
    top: 5px;
    text-decoration: none;
    text-shadow: 0 -1px 0 rgba(0,0,0, 0.4);
    }
/* button background and borders color */
a[data-theme="app-ios"] {
    border: none;
    }
    a[data-theme="app-ios"] .ui-btn-corner-all {
        border: 1px solid rgba(0,0,0, 0.4);
        -webkit-border-radius: 5px;
        background: -webkit-gradient(linear, left top, left bottom, from(#9fb3cc), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
        -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        overflow: visible;
        padding-left: 8px !important;
        padding-right: 8px !important;
        }
/* shadows and label color */
a[data-theme="app-ios"].ui-shadow,
a[data-theme="app-ios"] {
    box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
    background-clip: none; -webkit-background-clip: none; -moz-background-clip: none;
    color: white;
    font-weight: bold;
    top: 5px;
    text-decoration: none;
    text-shadow: 0 -1px 0 rgba(0,0,0, 0.4);
    }

Use CSS to transform and position the point

iOS Button - Part 1

This is now looking like an iPhone button –nice!– but we still have to render the point. To do so I will apply a gradient to the span tag inside the div container. I will also apply rotation and scale effects to the container itself using CSS transformation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* make room for the point */
a[data-theme="app-ios"].ui-btn-left {
    left: 14px;
    }
    a[data-theme="app-ios"].ui-btn-left .ui-btn-corner-all {
        padding-left: 5px !important;
        }
/* position the DIV that contains the point */
a[data-theme="app-ios"] .ios-tip {
    float: left;
    left: -9px;
    top: 4px;
    position: absolute;
    -webkit-transform: scale(.7, 1.0);
    }
/* apply gradient */
a[data-theme="app-ios"] .ios-tip span {
    display: block;
    width: 18px;
    height: 18px;
    border: 2px solid rgba(0,0,0, 0.4);
    border-right: 0;
    border-top: 0;
    /* the gradient color mus be slightly different since the point is within the body of the button */
    background: -webkit-gradient(linear, left top, right bottom, from(#94a8c2), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
    border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
    box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25);
    -webkit-transform: rotate(45deg) scale(.9, .9);
    }
/* make room for the point */
a[data-theme="app-ios"].ui-btn-left {
	left: 14px;
	}
	a[data-theme="app-ios"].ui-btn-left .ui-btn-corner-all {
        padding-left: 5px !important;
		}
/* position the DIV that contains the point */
a[data-theme="app-ios"] .ios-tip {
	float: left;
	left: -9px;
	top: 4px;
	position: absolute;
	-webkit-transform: scale(.7, 1.0);
	}
/* apply gradient */
a[data-theme="app-ios"] .ios-tip span {
    display: block;
    width: 18px;
    height: 18px;
    border: 2px solid rgba(0,0,0, 0.4);
    border-right: 0;
    border-top: 0;
    /* the gradient color mus be slightly different since the point is within the body of the button */
    background: -webkit-gradient(linear, left top, right bottom, from(#94a8c2), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
    border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
    box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25);
	-webkit-transform: rotate(45deg) scale(.9, .9);
	}

iOS Button - Part 2

With this final addition we can see the point on the left of the button. Now let’s put everything together.

Simplifying everything for future use

CSS code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* button background and borders color */
a[data-theme="app-ios"] {
    border: none;
    }
    a[data-theme="app-ios"] .ui-btn-corner-all {
        border: 1px solid rgba(0,0,0, 0.4);
        -webkit-border-radius: 5px;
        background: -webkit-gradient(linear, left top, left bottom, from(#9fb3cc), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
        -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        overflow: visible;
        padding-left: 8px !important;
        padding-right: 8px !important;
        }
/* shadows and label color */
a[data-theme="app-ios"].ui-shadow,
a[data-theme="app-ios"] {
    box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
    background-clip: none; -webkit-background-clip: none; -moz-background-clip: none;
    color: white;
    font-weight: bold;
    top: 5px;
    text-decoration: none;
    text-shadow: 0 -1px 0 rgba(0,0,0, 0.4);
    }
/* make room for the point */
a[data-theme="app-ios"].ui-btn-left {
    left: 14px;
    }
    a[data-theme="app-ios"].ui-btn-left .ui-btn-corner-all {
        padding-left: 5px !important;
        }
/* position the DIV that contains the point */
a[data-theme="app-ios"] .ios-tip {
    float: left;
    left: -9px;
    top: 4px;
    position: absolute;
    -webkit-transform: scale(.7, 1.0);
    }
/* apply gradient */
a[data-theme="app-ios"] .ios-tip span {
    display: block;
    width: 18px;
    height: 18px;
    border: 2px solid rgba(0,0,0, 0.4);
    border-right: 0;
    border-top: 0;
    /* the gradient color mus be slightly different since the point is within the body of the button */
    background: -webkit-gradient(linear, left top, right bottom, from(#94a8c2), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
    border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
    box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25);
    -webkit-transform: rotate(45deg) scale(.9, .9);
    }
/* button background and borders color */
a[data-theme="app-ios"] {
    border: none;
    }
    a[data-theme="app-ios"] .ui-btn-corner-all {
        border: 1px solid rgba(0,0,0, 0.4);
        -webkit-border-radius: 5px;
        background: -webkit-gradient(linear, left top, left bottom, from(#9fb3cc), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
        -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        overflow: visible;
        padding-left: 8px !important;
        padding-right: 8px !important;
        }
/* shadows and label color */
a[data-theme="app-ios"].ui-shadow,
a[data-theme="app-ios"] {
    box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;
    background-clip: none; -webkit-background-clip: none; -moz-background-clip: none;
    color: white;
    font-weight: bold;
    top: 5px;
    text-decoration: none;
    text-shadow: 0 -1px 0 rgba(0,0,0, 0.4);
    }
/* make room for the point */
a[data-theme="app-ios"].ui-btn-left {
	left: 14px;
	}
	a[data-theme="app-ios"].ui-btn-left .ui-btn-corner-all {
        padding-left: 5px !important;
		}
/* position the DIV that contains the point */
a[data-theme="app-ios"] .ios-tip {
	float: left;
	left: -9px;
	top: 4px;
	position: absolute;
	-webkit-transform: scale(.7, 1.0);
	}
/* apply gradient */
a[data-theme="app-ios"] .ios-tip span {
    display: block;
    width: 18px;
    height: 18px;
    border: 2px solid rgba(0,0,0, 0.4);
    border-right: 0;
    border-top: 0;
    /* the gradient color mus be slightly different since the point is within the body of the button */
    background: -webkit-gradient(linear, left top, right bottom, from(#94a8c2), to(#5b80ab), color-stop(0.5, #6b8bb2), color-stop(0.51, #597eaa));
    border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
    box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25); -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25);
	-webkit-transform: rotate(45deg) scale(.9, .9);
	}

CSS code:

1
2
3
4
5
6
$(document).ready(function(){
    // make sure we only add the point the back buttons
    var backButton = $('a[data-theme="app-ios"]').filter('[data-rel="back"]');
    backButton.find('.ui-icon').remove();
    backButton.append('<div class="ios-tip"><span>&nbsp;</span></div>');
});
$(document).ready(function(){
    // make sure we only add the point the back buttons
    var backButton = $('a[data-theme="app-ios"]').filter('[data-rel="back"]');
    backButton.find('.ui-icon').remove();
    backButton.append('<div class="ios-tip"><span>&nbsp;</span></div>');
});

Here is a final example of a page with a back button and non-back buttons:

iOS Button - Part 3