CARVIEW |
Chapter 3. Advanced iPhone Styling
In our quest to build an iPhone app without Objective-C, we’ve so far learned how to use CSS to style a collection of HTML pages to look like an iPhone app. In this chapter, we’ll lay the groundwork to make those same pages behave like an iPhone app. Specifically, we’ll discuss using Ajax to turn a full website into a single page app, how to create a back button with history using JavaScript, and how to take advantage of the Web Clip Icon and Full Screen Mode features of the iPhone to launch your app without Mobile Safari.
Adding a Touch of Ajax
The term Ajax has become such a buzzword that I’m not even sure I know what it means anymore. For the purposes of this book, I’m going to use Ajax to refer to the technique of using JavaScript to send requests to a web server without reloading the current page (e.g. to retrieve some HMTL, submit a form, etc.). This approach makes for a very smooth user experience, but does require that the developer reinvent much of the browser wheel.
For example, if you are loading external pages dynamically, the browser will not give any indication of progress or errors to the users. Furthermore, the back button will not work as expected unless you take pains to support it. In other words, you have to do a lot of work to make a sweet Ajax app. Even so, there are some very good reasons go to the trouble. In particular, it opens the door to creating iPhone apps that can run full-screen and even offline, topics that I’ll cover in a later chapter.
-
Geoff R Hobbs Posted 3 days and 21 hours ago
very good reasons to go to the trouble
Add a comment
Traffic Cop
For my next series of examples, I’m going to write a single page called iphone.html that will sit in front of all of the other site pages, handling requests from the user. Here’s how it works: When someone browses the site with Mobile Safari, he will be redirected to iphone.html. On first load, the page will present the user with a nicely formatted version of the site navigation. I’ll then use JQuery to “hijack” the onclick actions of the nav links so that when the user clicks on one, the browser page will not navigate to the target link. Rather, jQuery will load a portion of the HTML from the remote page and deliver the data to the user by updating the current page. I’ll start with the most basic functional version of the code and improve it as we go along.
-
Geoff R Hobbs Posted 3 days and 21 hours ago
he/she will be redirected to iphone.html
Add a comment
The HTML for the wrapper page is extremely simple (see Example 3.1, “This simple HMTL wrapper markup will sit in front of the rest of the site pages.”). In the head section, I set the title and viewport options, and include links to a stylesheet (iphone.css
) and two JavaScript files: jquery.js
, and a custom JavaScript file named iphone.js
.
The body just has two divs: a header with the intial title in an h1
tag, and an empty div
container, which will end up holding HTML snippets retrieved from remote pages.
Example 3.1. This simple HMTL wrapper markup will sit in front of the rest of the site pages.
<html> <head> <title>Jonathan Stark</title> <meta name="viewport" content="user-scalable=no, width=device-width" /> <link rel="stylesheet" href="iphone.css" type="text/css" media="screen" /> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="iphone.js"></script> </head> <body> <div id="header"><h1>Jonathan Stark</h1></div> <div id="container"></div> </body> </html>
Moving on to the CSS, you can see in Example 3.2, “The base CSS for the page is just a slightly reshuffled version of previous examples. Please refer to the previous chapter if anything looks unfamiliar.” that I’ve reshuffled some of the properties from previous examples (e.g. some of the #header h1
properties have been moved up to #header
), but overall everything should look familiar.
Example 3.2. The base CSS for the page is just a slightly reshuffled version of previous examples. Please refer to the previous chapter if anything looks unfamiliar.
body { background-color: #ddd; color: #222; font-family: Helvetica; font-size: 14px; margin: 0; padding: 0; } #header { background-color: #ccc; background-image: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#999)); border-color: #666; border-style: solid; border-width: 0 0 1px 0; } #header h1 { color: #222; font-size: 20px; font-weight: bold; margin: 0 auto; padding: 10px 0; text-align: center; text-shadow: 0px 1px 0px #fff; } ul { list-style: none; margin: 10px; padding: 0; } ul li a { background-color: #FFF; border: 1px solid #999; color: #222; display: block; font-size: 17px; font-weight: bold; margin-bottom: -1px; padding: 12px 10px; text-decoration: none; } ul li:first-child a { -webkit-border-top-left-radius: 8px; -webkit-border-top-right-radius: 8px; } ul li:last-child a { -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px; } ul li a:active,ul li a:hover { background-color:blue; color:white; } #content { padding: 10px; text-shadow: 0px 1px 0px #fff; } #content a { color: blue; }
-
Mike Boulet Posted 4 days and 20 hours ago
kinda obvious, but I think it is worth mentioning that this is the iphone.css file
Add a comment
The JavaScript is where all the magic happens in this example. Please refer to Example 3.3, “This bit of JavaScript converts the links on the page to Ajax requests.” as I go through it line by line.
Example 3.3. This bit of JavaScript converts the links on the page to Ajax requests.
1 $(document).ready(function(){ 2 loadPage(); 3 }); 4 function loadPage(url) { 5 if (url == undefined) { 6 $('#container').load('index.php #header ul', hijackLinks); 7 } else { 8 $('#container').load(url + ' #content', hijackLinks); 9 } 10 } 11 function hijackLinks() { 12 $('#container a').click(function(e){ 13 e.preventDefault(); 14 loadPage(e.target.href); 15 }); 16 }
-
Mike Boulet Posted 4 days and 20 hours ago
mention this is iphone.js
Add a comment
On lines 1-3, I’m using jQuery’s document ready function to have the browser run the loadPage()
function when the DOM is complete. The loadPage()
function accepts a single parameter called url, and then checks (on line 5) whether a value has been sent. If a value is not sent into the funtion, url
will be undefined and the line 6 will execute. Otherwise, line 8 will execute.
Both lines 6 and 8 are examples of JQuery’s load()
function. The load()
function is excellent for adding quick and dirty Ajax functionality to a page. If line 6 was translated into in English, it would read: “Get all of the ul
elements from the #header
element of index.php
and insert them into the #container
element of the current page. When you're done, run the hijackLinks()
function.”
Line 8, then, is saying: “Get the #content
element from the url
that was passed into the loadPages()
function and insert it into the #container
element of the current page. When you're done, run the hijackLinks()
function.”
Once the load()
function has completed, the #container
element of the current page will contain the HTML snippet that was retrieved. Then, load()
will run the hijackLinks()
function. On line 12, hijackLinks()
finds all of the links that are in the new HTML, and binds a click handler to them (lines 13 and 14).
Tip
One of my favorite things about JavaScript is that you can pass a function as a parameter to another function. Although this looks weird at first, it’s extremely powerful and allows you to make your code modular and reusable.
It’s outside the scope of this book to get into the intricacies of this, but if you’d like to learn more, you should check out “JavaScript: The Good Parts” by Douglas Crockford. In fact, if you are working with JavaScript, you should check out everything by Douglas Crockford; you’ll be glad you did.
Note
Note that click handlers do not run when the page first loads; they run when the user has read some stuff on the page and decides to click a link. Assigning click handlers is like setting booby traps; you do some initial setup work for something that may or may not be triggered later.
Click handlers are automatically passed an event object, which I’m capturing on line 12 as the function parameter e
. The event object of a clicked link contains the url of the remote page in e.target.href
. When the user clicks, I pass the url of the remote page to the loadPage()
function (line 14), and the cycle starts all over again.
Normally, a web browser will navigate to a new page when a link is clicked. This navigation response is called the “default behavior” of the link. Since we are handling clicks and loading pages manually, we need to prevent this default behavior. On line 13, I’ve done so by calling the built-in preventDefault()
method of the event object. If I had left that line out, the browser would have dutifully left the current page and navigated to the url of clicked link.
Tip
It’s worth taking a few minutes to read up on the properties of event object that JavaScript creates in response to user actions in the browser. A good reference is located at https://www.w3schools.com/htmldom/dom_obj_event.asp
.
Simple Bells and Whistles
With this tiny bit of HTML, CSS, and JavaScript, we have essentially turned an entire website into a single page application. However, it does still leave quite a bit to be desired. Let’s slick things up a bit.
Since we are not allowing the browser to navigate from page to page, the user will not see any indication of progress while data is loading. We need to provide some feedback to the user to let them know that something is, in fact, happening. Without this feedback, the user will wonder if they actually clicked the link or missed it, and will often start clicking all over the place in frustration. This can lead to increased server load and application instability (i.e. crashing).
Thanks to jQuery, providing this sort of feedback only takes two lines of code. I just append a loading div
to the body when loadPage()
starts, and I remove the loading div
when hijackLinks()
is done (see Example 3.4, “Adding a simple progress indicator to the page.”).
Example 3.4. Adding a simple progress indicator to the page.
$(document).ready(function(){ loadPage(); }); function loadPage(url) { $('body').append('<div id="progress">Loading...</div>'); if (url == undefined) { $('#container').load('index.php #header ul', hijackLinks); } else { $('#container').load(url + ' #content', hijackLinks); } } function hijackLinks() { $('#container a').click(function(e){ e.preventDefault(); loadPage(e.target.href); }); $('#progress').remove(); }
See Example 3.5, “CSS used to style the progress indicator.” for the CSS used style to the progress div
.
Example 3.5. CSS used to style the progress indicator.
#progress { -webkit-border-radius: 10px; background-color: rgba(0,0,0,.7); color: white; font-size: 18px; font-weight: bold; height: 80px; left: 60px; line-height: 80px; margin: 0 auto; position: absolute; text-align: center; top: 120px; width: 200px; }
Figure 3.1. Without a progress indicator of some kind, your app will seem unresponsive and your users will get frustrated.
![]() |
My site happens to have a single h2
at the beginning of each page that would make a nice page title (see Figure 3.2, “Before moving the page heading to the toolbar...”). To be more iPhone-esque, I’m going to pull that title out of the content and put it in the header (see Figure 3.3, “...and after moving the page heading to the toolbar.”). Again, JQuery to the rescue: I just add three lines to the hijackLinks()
function to make it happen (See Example 3.6, “Using the h2 from the target page as the toolbar title.”).
Figure 3.2. Before moving the page heading to the toolbar...
![]() |
Figure 3.3. ...and after moving the page heading to the toolbar.
![]() |
Example 3.6. Using the h2
from the target page as the toolbar title.
function hijackLinks() { $('#container a').click(function(e){ e.preventDefault(); loadPage(e.target.href); }); var title = $('h2').html() || 'Hello!'; $('h1').html(title); $('h2').remove(); $('#progress').remove(); }
The double pipe in the first new line is the JavaScript logical operator OR. Translated into English, that line would read: “Set the title variable to the HTML contents of the h2
element, or to the string ‘Hello!’ if there is no h2
element.” This is important because the first page load won’t contain an h2
because we are just grabbing the nav ul
s.
Note
Note that I added the title lines before the line that removes the progress indicator. I like to remove the progress indicator as the very last action because I think it makes the application feel more responsive.
I have a few pages on my site that have titles that are longer than can fit in the header bar (Figure 3.4, “Text wrapping in the toolbar is not very iPhone-ish...”). I could just let the text break onto more than one line, but that would not be very iPhone-ish. Rather, I’ve updated the #header h1
styles such that long text will be truncated with a trailing ellipis (see Figure 3.5, “...but we can beautify it with a CSS ellipsis.” and Example 3.7, “Adding an ellipsis to text that is too long for its container.”). This might be my favorite little-known CSS trick.
Figure 3.4. Text wrapping in the toolbar is not very iPhone-ish...
![]() |
Figure 3.5. ...but we can beautify it with a CSS ellipsis.
![]() |
Example 3.7. Adding an ellipsis to text that is too long for its container.
#header h1 { color: #222; font-size: 20px; font-weight: bold; margin: 0 auto; padding: 10px 0; text-align: center; text-shadow: 0px 1px 0px #fff; max-width: 160px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
Here’s the rundown: max-width: 160px
instructs the browser not to allow the h1
element to grow wider than 160px
. Then, overflow: hidden
instructs the browser to chop off any content that extends outside of the element borders. Next, white-space: nowrap
prevents the browser from breaking the line into two. Without this line, the h1
would just get taller to accommodate the text at the defined width. Finally, text-overflow: ellipsis
appends three dots to the end of any chopped off text to indicate to the user that she is not seeing the entire string.
Let’s say you have an About page that is longer than the viewable area on the iPhone. The user visits the page, scrolls down to the bottom, and clicks on a link to your Contact page. If you have more than a screenful of text on your Contact page, the new data will appear with the window still scrolled all the way to the bottom.
Technically, this makes sense because we are not actually leaving the current (scrolled) page, but it’s certainly a confusing situation for the user. To rectify the situation, I have added a scrollTo()
command to the loadPage()
function (see Example 3.8, “It’s a good idea to scroll back to the top when a user navigates to a new page.”).
Whenever a user clicks a link, the page will first jump to the top. This has the added benefit of ensuring that the loading graphic is visible if the user clicks a link at the bottom of a long page.
Example 3.8. It’s a good idea to scroll back to the top when a user navigates to a new page.
function loadPage(url) {
$('body').append('<div id="progress">Loading...</div>');
scrollTo(0,0);
if (url == undefined) {
$('#container').load('https://jonathanstark.com/index.php #header ul', hijackLinks);
} else {
$('#container').load('https://jonathanstark.com/' + url + ' #content', hijackLinks);
}
}
Like most sites, mine has links to external pages (i.e. pages hosted on other domains). I don’t want to hijack these external links because it wouldn’t make sense to inject their HTML into my iPhone-specific layout. In Example 3.9, “You can allow external pages to load normally by checking the domain name of the url.”, I have added a conditional that checks the url for the existence of my domain name. If it’s found, the link is hijacked and the content is loaded into the current page; i.e. Ajax is in effect. If not, the browser will navigate to the url normally.
Example 3.9. You can allow external pages to load normally by checking the domain name of the url.
function hijackLinks() { $('#container a').click(function(e){ var url = e.target.href; if (url.match(/jonathanstark.com/)) { e.preventDefault(); loadPage(url); } }); var title = $('h2').html() || 'Hello!'; $('h1').html(title); $('h2').remove(); $('#progress').remove(); }
Tip
Regular expressions can be a bit intimidating, but are well worth becoming familiar with. My favorite regex page is located at https://www.regular-expressions.info/javascriptexample.html
.
Roll Your Own Back Button
The elephant in the room at this point is that the user has no way to navigate back to previous pages. Let’s address that by adding a back button to the top left corner of the screen. First, I’ll update the JavaScript, and then we’ll do the CSS.
Adding a standard iPhone-ized back button to the app means keeping track of the user’s click history. To do this, we’ll have to A) store the url of the previous page so we know where to go back to, and B) store the title of the previous page, so we know what label to put on the back button.
Adding this feature touches on most of the JavaScript we’ve written so far in this chapter, so I’ll go over the entire new version of iphone.js
line by line (see Example 3.10, “Expanding the existing JavaScript example to include support for a back button.”). The result will look like Figure 3.6, “It wouldn’t be an iPhone app without a glossy, left-arrow back button.”
Figure 3.6. It wouldn’t be an iPhone app without a glossy, left-arrow back button.
![]() |
Example 3.10. Expanding the existing JavaScript example to include support for a back button.
1 var hist = []; 2 var startUrl = 'index.php'; 3 $(document).ready(function(){ 4 loadPage(startUrl); 5 }); 6 function loadPage(url) { 7 $('body').append('<div id="progress">Loading...</div>'); 8 scrollTo(0,0); 9 if (url == startUrl) { 10 var element = ' #header ul'; 11 } else { 12 var element = ' #content'; 13 } 14 $('#container').load(url + element, function(){ 15 var title = $('h2').html() || 'Hello!'; 16 $('h1').html(title); 17 $('h2').remove(); 18 $('.leftButton').remove(); 19 hist.unshift({'url':url, 'title':title}); 20 if (hist.length > 1) { 21 $('#header').append('<div class="leftButton">'+hist[1].title+'</div>'); 22 $('#header .leftButton').click(function(){ 23 var thisPage = hist.shift(); 24 var previousPage = hist.shift(); 25 loadPage(previousPage.url); 26 }); 27 } 28 $('#container a').click(function(e){ 29 var url = e.target.href; 30 if (url.match(/jonathanstark.com/)) { 31 e.preventDefault(); 32 loadPage(url); 33 } 34 }); 35 $('#progress').remove(); 36 }); 37 }
On line 1, I’m initializing a variable named hist
as an empty array. Since I’ve defined it outside of any functions, it exists in the global scope and will be available everywhere in the page. Note that I didn’t use the full word history
as my variable name because that is a predefined object property in JavaScript and should be avoided.
On line 2, I’m defining the relative url of the remote page to load when the user first visits iphone.html
. You might recall that previously I just checked for url == undefined
to handle the first page load, but in this example we are going to use the start page in a few places. Therefore, it makes sense to define it globally.
Lines 3 and 4 make up the document ready function definition. Note that unlike previous examples, I’m passing the start page to the loadPage()
function.
On to the loadPage()
function. Lines 7 and 8 are verbatim from previous examples. On lines 9-13 I’m indicating which elements to load from the remote page. i.e if we want the start page, grab the uls from the header; otherwise, grab the content div.
On line 14, the url parameter and the appropriate source element are concatenated as the first parameter passed to the load function. As for the second parameter, I’m passing an anonymous function directly. As we go through the anonymous function, you’ll notice a strong resemblance to the hijackLinks()
function. For example, lines 15-17 are identical to previous examples.
On line 18, I’m removing the .leftButton
object from the page. This might seem weird because I haven’t yet added it to the page, but it will make sense once we move on.
On line 19, I’m using the built-in unshift
method of the JavaScript array to add an object to the beginning of hist
array. The object I’m adding has two properties: url
and title
- the two pieces of information we need to support the back button display and behavior.
On line 20, I’m using the built-in length
method of the JavaScript array to find out how many objects are in the history array. If there is only one object in the history array, it means that the user is on the first page. Therefore, we don’t need to display a back button. However, if there is more than one object in the hist array, we need to add a button to the header.
The text of the button will be the same as title of the page before the current page, which is what I’m accessing with the hist[1].title
code. JavaScript arrays are zero-based, so the first item in the array (the curent page) has an index of 0. In other words, index 0 is the current page, index 1 is the previous page, index 2 is the page before that, and so on.
On lines 22-26, I’m binding an anonymous function to the click handler of the back button. Remember, click handler code executes when the user clicks, not when the page loads. So, after the page loads and the user clicks to go back, the code on lines 23-25 will run.
Lines 23 and 24 use the built-in shift
method of the array to remove the first two items from the hist array, and then line 25 sends the url of the previous page to the loadPage()
function.
The remaining lines (28-37) were copied exactly from previous examples, so I won’t rehash them here.
Tip
Please visit https://www.hunlock.com/blogs/Mastering_Javascript_Arrays
for a full listing of JavaScript array functions with descriptions and examples.
Now that we have our back button, all that remains is to purty it up with some CSS (see Example 3.11, “Using the a border image to beautify the back button.”). I start off by styling the text with font-weight
, text-align
, line-height
, color
, and text-shadow
. I continue by placing the div
precisely where I want it on the page with position
, top
, and left
. Then, I make sure that long text on the button label will truncate with an ellipis using max-width
, white-space
, overflow
, and text-overflow
. Finally, I apply a graphic with border-width
and -webkit-border-image
. Unlike my earlier border image example, this image has a different width for the left and right borders because the image is made asymetrical by the arrowhead on the left side.
Example 3.11. Using the a border image to beautify the back button.
#header div.leftButton { font-weight: bold; text-align: center; line-height: 28px; color: white; text-shadow: rgba(0,0,0,0.6) 0px -1px 0px; position: absolute; top: 7px; left: 6px; max-width: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-width: 0 8px 0 14px; -webkit-border-image: url(images/back_button.png) 0 8 0 14; }
By default, Mobile Safari displays a translucent gray box over clickable objects that have been tapped (Figure 3.7, “By default, Mobile Safari displays a translucent gray box over clickable objects that have been tapped.”). Since our back button is not rectangular, this effect looks a little lame. Fortunately, Mobile Safari supports a property called -webkit-tap-highlight-color
that allows you to change the default to whatever color you like. I want to remove the highlight completely, which I’ve done here by setting the tap highlight to a fully transparent color (see Example 3.12, “Removing the default tap highlight from Mobile Safari.”).
Figure 3.7. By default, Mobile Safari displays a translucent gray box over clickable objects that have been tapped.
![]() |
-
Janos Rusiczki Posted 5 days and 23 hours ago
Screenshot has "messy" background.
Add a comment
Example 3.12. Removing the default tap highlight from Mobile Safari.
#header div.leftButton {
font-weight: bold;
text-align: center;
line-height: 28px;
color: white;
text-shadow: rgba(0,0,0,0.6) 0px -1px 0px;
position: absolute;
top: 7px;
left: 6px;
max-width: 50px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-width: 0 8px 0 14px;
-webkit-border-image: url(images/back_button.png) 0 8 0 14;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
In the case of the back button, there will be at least a second or two of delay before the content from the previous page appears. To avoid frustration, I want the button to look clicked the instant it’s tapped. In a desktop browser, this would be a simple process; you’d just add a declaration to your CSS using the :active psuedo class to specify an alternate style for the object that was clicked. I don't know if it’s a bug or a feature, but this approach does not work on the iPhone; the :active style is ignored.
I toyed around with combinations of :active and :hover, which brought me some success with non-Ajax apps. However, with an Ajax app like the one we are using here, the :hover style is sticky (i.e. the button appears to remain "clicked" even after the finger is removed).
-
Michael Korican Posted 4 days and 20 hours ago
3.13, "title" ???
Add a comment
Fortunately, the fix is pretty simple. I use jQuery to add the class clicked
to the button when the user taps it. I’ve opted to apply a darker version of the border image to the button in the example (see Figure 3.8, “It might be tough to tell in print, but the clicked back button is a bit darker than the default state.” and Example 3.13, “title”).
Figure 3.8. It might be tough to tell in print, but the clicked back button is a bit darker than the default state.
![]() |
-
Michael Korican Posted 4 days and 20 hours ago
Examp;e 3.13. title ???
Add a comment
Example 3.13. title
#header div.leftButton.clicked { -webkit-border-image: url(images/back_button_clicked.png) 0 8 0 14; }
Note
Since I’m using an image for the clicked style, it would be smart to preload the image. Otherwise, the unclicked button graphic will disappear the first time it’s tapped while the clicked graphic downloads. I’ll cover image preloading in the next chapter.
Note
A special note to any CSS gurus in the crowd: the CSS Sprite technique–popularized by A List Apart–is not an option in this case because it requires setting offsets for the image. Image offsets are not suppored by the -webkit-border-image
property.
With the CSS in place, I can now update the portion of the iphone.js
that assigns the click handler to the back button. First, I add a variable name to the anonymous function in order to capture the incoming click event. Then, I wrap the event target in a JQuery selector and call JQuery's addClass()
function to assign my clicked CSS class to the button (see listing 3.x).
-
Michael Korican Posted 4 days and 20 hours ago
See 3.10 lines 23, 24, 25: vars have different names
Add a comment
$('#header .leftButton').click(function(e){ $(e.target).addClass('clicked'); var thisUrl = hist.shift(); var lastUrl = hist.shift(); loadPage(lastUrl.url); });
-
Mike Boulet Posted 4 days and 19 hours ago
The following code:
var thisUrl = hist.shift(); var lastUrl = hist.shift(); loadPage(lastUrl.url);
should be:
var thisPage = hist.shift(); var previousPage = hist.shift(); loadPage(previousPage.url);
Add a comment
Web Clip Icon
Hopefully, users will want to add an icon for your webapp (called a “web clip icon”) to their home screens. By default, iPhone will create this icon by thumbnailing the current page (including position and zoom), and applying rounded corners and a glossy effect.
Figure 3.9. Adding a web clip icon to your home screen, step 1: Click the plus button at the bottom of the Safari window.
![]() |
Figure 3.10. Adding a web clip icon to your home screen, step 2: Click the “Add to Home Screen” button in the dialog.
![]() |
Figure 3.11. Adding a web clip icon to your home screen, step 3: Click the “Add” button in the “Add to Home” Screen panel.
![]() |
Figure 3.12. Adding a web clip icon to your home screen, step 4: The 57 x 57 pixel image that you provided will show up on the home screen.
![]() |
This might be fine for slackers, but the cool kids provide a custom web clip icon. The simplest way to do this is specify a single icon for your entire site by uploading a file named apple-touch-icon.png
to your web root. The file should be 57 pixels square, and without gloss or rounded corners because the iPhone will add these automatically. If you don’t want the iPhone to add effects to your webclip icon, change the name of the file to apple-touch-icon-precomposed.png
.
In some cases, you might want to provide a web clip icon for a page that is different from the rest of your site. You can do this by adding one of the following lines to the head of the page (you’d replace myCustomIcon.png
with the absolute or relative path to the image):
<link rel="apple-touch-icon" href="myCustomIcon.png" />
<link rel="apple-touch-icon-precomposed" href="myCustomIcon.png" />
Note
If you are going to use precomposed images, make the corner radius 10 pixels or more. Otherwise iPhone will round the corners to 10 pixels. In either case, using precomposed does suppress the addition of the glossy effect.
Full Screen Mode
Feel like reclaiming a quarter of the available vertical space from Mobile Safari (104 pixels to be precise)? Add the following line to the head section of your HTML and your web app will in display full screen mode when launched from the web clip icon:
<meta name="apple-mobile-web-app-capable" content="yes" />
I would’ve told you about this feature earlier, but it’s only useful once you have hijacked all of your hyperlinks with Ajax. As soon as a user clicks on a non-Ajax link - one that actually navigates to a new page - Mobile Safari will launch and load the page normally. This behavior is perfect for the example we’ve been working with because external links (Amazon, Twitter, Facebook, etc.) will open in Safari.
Once you’ve added the apple-mobile-web-app-capable
meta tag, you have the option to control the background color of the 20 pixel status bar at the top of the screen using the apple-mobile-web-app-status-bar-style
meta tag. The normal gray Safari status bar is the default, or you can change it to black
(see Figure 3.13, “Full screen mode gives you about 25% more screen real estate (and looks way cooler).”). You can also set it to black-translucent
which makes it partialy transparent and additionally removes it from the document flow. In other words, your content will be shifted up by 20 pixels and behind the status bar the when page first loads, so you might have to position your header a little lower to compensate.
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
Figure 3.13. Full screen mode gives you about 25% more screen real estate (and looks way cooler).
![]() |
What we’ve learned
In this chapter, you’ve learned how to convert a normal website into a full screen Ajax application, complete with progress indicators, a native looking back button, and a custom web clip icon. In the next chapter, you’ll learn how to make your app come alive by adding native user interface animations. That’s right; here comes the fun stuff!
-
Mike Boulet Posted 4 days and 19 hours ago
I'm totally confused.. :) Was I supposed to reuse code from the last chapter? I think scattering code fragments throughout a chapter and then showing screen shots of pages that will not look like anything I'm working is very confusing and a little frustrating. At the end of this chapter I didn't have anything that looked like the screen shot. Breaking up the code into fragments that you then subsequent explain makes a lot of sense, but I think there needs to be a complete listing of the final html/js/css code. This way you can compare the listing against what you just created in the etxt editor.
Add a comment
You must sign in or register before commenting
Copyright © 2009 Jonathan Stark
No comments yet
Add a comment