Chapter 2. Basic iPhone Styling

Ultimately, we are going to build a native iPhone app using HTML, CSS, and JavaScript. The first step on this journey is to get comfortable styling HTML to look like an iPhone app. In this chapter, I’ll show you how to apply CSS styles to a bunch of existing HTML pages so that they are easily navigable on an iPhone. So, in addition to moving closer to building a native app, you’ll be learning a practical (and valuable) skill that you can use immediately.

5 comments

  1. Geoff R Hobbs Posted 1 month, 22 days and 12 hours ago

    Box below should be Host your web pages on a web server (chances are that your Internet Service Provider offers a complimentary web hosting service) and connect to that server from your iPhone

  2. Garrett Murray Posted 1 month, 20 days and 12 hours ago

    You can in fact load your local websites on your iPhone quite easily by using a service such as DynDNS, which is free and simple to use. You simply tell it your IP Address, and it gives you a domain name. You can then use that domain name in the iPhone simulator and on the iPhone itself.

  3. Linda Posted 1 month, 17 days and 14 hours ago

    Box below: Shouldn't "you won't be able to load them from your iPhone" be "you won't be able to load them onto your iPhone"

  4. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Thanks for the comments!

  5. Leslie Murphy Posted 11 days and 11 hours ago

    I think Garrett's DynDNS comment is a great tip you should include!

Add a comment

2 comments

  1. William Doane Posted 1 month, 4 days and 10 hours ago

    "Internet Service Provider offers complimentary a web hosting service" -> "Internet Service Provider offers a complimentary web hosting service"

  2. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Got it - thanks!

Add a comment

First Steps

Theory is great, but I’m a “show me, don’t tell me” kinda guy so let’s dive in.

2 comments

  1. William Doane Posted 1 month, 4 days and 10 hours ago

    “show me, don’t tell” me ---> “show me, don’t tell me” (misplaced quote)

  2. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Good catch.

Add a comment

Imagine that you have a website that you want to iPhone-ize (Figure 2.1, “Desktop version of a typical website looks fine in Safari on a computer.”). In this scenario, there are a number of easy things you can do to optimize a site for iPhone. I’ll go over your options in this chapter.

Figure 2.1. Desktop version of a typical website looks fine in Safari on a computer.

Desktop version of a typical website looks fine in Safari on a computer.

Figure 2.2, “Desktop version of a typical website looks alright on an iPhone, but we can do a lot better.” shows what this web page looks like on the iPhone. It’s usable, but far from optimized for the iPhone.

Figure 2.2. Desktop version of a typical website looks alright on an iPhone, but we can do a lot better.

Desktop version of a typical website looks alright on an iPhone, but we can do a lot better.

Example 2.1, “The HTML document we’ll be styling.” shows an abbreviated version of the website shown above. This is the HTML you’ll be working with in this chapter. You can download it from the book's website (see the section called “How to Contact Us”) if you'd like to try styling it as you go through the chapter. The desktop style sheet (screen.css is not shown as it is not essential, but you can use the style sheet from the previous chapter if you'd like to have something to play with.

2 comments

  1. Joe Bossalini Posted 15 days and 11 hours ago

    Maybe it's not been posted there yet but I couldn't find the downloadable HTML files at the Contact Us page. I really like the idea of having the code be downloadable; maybe this paragraph should be more prominent to let people know that option will be available?

    Also, the referenced HTML below has links to other pages (about.html, blog.html, etc.) I don't see those code snippets listed and it looks like they are used in chapter 3.

    Looks like it will be a great book, though! Thanks for the preview!

  2. Joe Bossalini Posted 15 days and 11 hours ago

    oops! ignore my comment :-) I see it is discussed already in Chapter 3! Feel free to delete my comments here

Add a comment

Example 2.1. The HTML document we’ll be styling.

<html>
<head>
  <link rel="stylesheet" href="screen.css" type="text/css" />
  <title>Jonathan Stark</title>
</head>
<body>
<div id="container">
  <div id="header">
    <h1><a href="./">Jonathan Stark</a></h1>
    <div id="utility">
        <ul>
            <li><a href="about.html">About</a></li>
            <li><a href="blog.html">Blog</a></li>
        </ul>
    </div>
    <div id="nav">
        <ul>
            <li><a href="consulting-clinic.html">Consulting Clinic</a></li>
            <li><a href="on-call.html">On Call</a></li>
            <li><a href="development.html">Development</a></li>
        </ul>
    </div>
  </div>
  <div id="content">
    <h2>About</h2>
    <p>Jonathan Stark is a web developer, speaker, and author. His 
       consulting firm, Jonathan Stark Consulting, Inc., has attracted
       clients such as Staples, Turner Broadcasting, and the PGA Tour.
       ...
       </p>
  </div>
  <div id="sidebar">
    <img alt="Manga Portrait of Jonathan Stark" 
         src="http://jonathanstark.com/images/jonathanstark-manga-small.png"/>
    <p>Jonathan Stark is a mobile and web application developer who the
       Wall Street Journal has called an expert on publishing desktop 
       data to the web.</p>
  </div>
  <div id="footer">
    <ul>
        <li><a href="services.html">Services</a></li>
        <li><a href="about.html">About</a></li>
        <li><a href="blog.html">Blog</a></li>
    </ul>
    <p class="subtle">Jonathan Stark Consulting, Inc.</p>
  </div>
</div>
</body>
</html>     
            

Tip

For years, web developers used tables to lay out elements in a grid. Advances in CSS and HTML have rendered that approach not only obsolete, but undesirable. Today, we primarily use the div element (along with a variety of attributes) to accomplish the same thing, but with more control. Although a complete explanation of div-based layouts is well outside the scope of this book, you'll see plenty of examples of it as you read through the book. To learn more, please check out Designing with Web Standards by Jeffrey Zeldman which covers the issue in greater detail.

4 comments

  1. Andrew Posted 1 month, 5 days and 4 hours ago

    Not sure that DWWS is "the definitive work" on div-based grid layouts, which is what you're specifically talking about here. DWWS is a good book on semantic HTML.

  2. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    True dat. I'll update.

  3. Scott Jungling Posted 28 days and 14 hours ago

    Might consider using the code formatting for 'div' in the 3rd sentence: "Today, we primarily use the div element…" to help it standout.

  4. Leslie Murphy Posted 11 days and 11 hours ago

    Might as well give Zeldman a plug - include the URL http://www.zeldman.com/dwws/

Add a comment

Prepare a Separate iPhone Stylesheet

I’m as DRY as the next guy, but in the real world you’re better off making a clean break between your desktop browser stylesheet and your iPhone stylesheet. Take my word for it and just make two completely independent files; you’ll sleep better. The alternative would be to wedge all of your CSS rules into a single stylesheet, which ends up being a bad idea for a number of reasons, the most obvious of which is that you’d be sending a bunch of irrelevant desktop style rules to the phone, which is a waste of precious bandwidth and memory.

6 comments

  1. Doug Rowe Posted 1 month, 21 days and 6 hours ago

    I think the DRY comments are a little off base. I would think that a good DRY programmer would have html that was general, and then style sheets for each different platform.

  2. Garrett Murray Posted 1 month, 20 days and 12 hours ago

    Agreed with Doug above.

  3. Andrew Posted 1 month, 5 days and 4 hours ago

    Also agreed. I'm not sure it seems more DRY to somehow try to combine the stylesheets into one, as you imply here. Also, "take my word for it" isn't really a compelling argument, can you explain why your way is better?

  4. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    @Doug and @Garrett - Well, I was thinking that it's not very DRY to have 2 different stylesheet that have many of the same rules. I would certainly consider all the colors for a site in two places repeating myself. PLMK if you still disagree...

  5. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    @Andrew - You're right. I'll update.

  6. Leslie Murphy Posted 11 days and 11 hours ago

    Jonathan, is there a reason that what seems like a middle ground does not work? A common stylesheet for colors and styling elements that "brand" the app, and then a browser-specific style sheet? It sounds like you've been down this road and have some strong opinions - like Andrew I would like to better understand what bullet's a developer will dodge by taking your advice.

Add a comment

Note

DRY stands for “Don’t repeat yourself,” and is a software development principle that states that “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” The term was coined by Andrew Hunt and David Thomas in their book The Pragmatic Programmer.

To specify a stylesheet specifically for iPhone, replace the stylesheet link tags in the sample HTML document with ones that use the following expressions:

4 comments

  1. Mike Boulet Posted 1 month, 21 days and 10 hours ago

    Will not work on Safari 4.03 for the PC. Styles do not get applied. Had Safari useragent set to Mobile Safari 3 IPod Touch, if that matters.

    I took off the "only screen and (max-device-width: 480px)" and I could then see the style.

  2. Garrett Murray Posted 1 month, 20 days and 12 hours ago

    Strange, this code is perfectly valid and should work. I wonder if there's a bug in Safari 4.03 that caused this to revert, because it used to work fine. (Works fine on Mac, btw).

  3. C.W.Zachary Posted 1 month, 16 days and 12 hours ago

    Comparing on 480px may not be a good forward-looking technique. Aple itself has suggested getting away from this hard-coded size, especially if Apple eventually produces the "iTablet", or whatever it calls it.

  4. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    @Mike - Thanks for the heads up. Are you sure you sized your window to less than 480px?

    @CWZ - Hmm... What would you suggest? I can't use device-width in this context. PLMK if you have an alternative.

Add a comment

<link rel="stylesheet" type="text/css" 
      href="iphone.css" media="only screen and (max-device-width: 480px)" />
<link rel="stylesheet" type="text/css" 
      href="desktop.css" media="screen and (min-device-width: 481px)" />
        

Caution

If you are testing your iPhone web pages using the desktop version of Safari as described in Don’t have a website?, this detection won’t work correctly. As a workaround, you can change desktop.css to iphone.css while you are testing, but don’t use this technique on a production web site, or all desktop browser users will get the iPhone-specific CSS when they visit your site.

Here, desktop.css refers to whatever your existing desktop stylesheet is, and iphone.css is a new file that we’ll be discussing in detail in a bit.

2 comments

  1. Ali B. Posted 1 month, 2 days and 16 hours ago

    I think it's worthy to explain the max/min width parts of the media attributes used in the previous example. Readers without prior knowledge to the details of the media attribute would end up in speculations here. This is a fundamental part of the process and it should not be neglected, IMO.

  2. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Thanks - I'll try to work that in.

Add a comment

Note

If you're following along using the sample HTML document shown earlier, you'll now need to rename screen.css to desktop.css, but since we're focused on the iPhone style sheet, you can ignore the desktop style sheet completely. If it fails to load, your browser won’t get too upset.

1 comment

  1. Leslie Murphy Posted 11 days and 11 hours ago

    Why not just name it desktop.css from the get go, and avoid taking up space in the book for this Note?

Add a comment

Regrettably, Internet Explorer will not understand these expressions, so we have to add a conditional comment (shown in bold) that links to the desktop version of the CSS:

1 comment

  1. Scott Posted 10 days and 12 hours ago

    The code for IE is not working. Any suggestions?

Add a comment

<link rel="stylesheet" type="text/css" 
      href="iphone.css" media="only screen and (max-device-width: 480px)" />
<link rel="stylesheet" type="text/css" 
      href="desktop.css" media="screen and (min-device-width: 481px)" />            
<!--[if IE]>
<link rel="stylesheet" type="text/css" href="explorer.css" media="all" />
<![endif]-->
        

3 comments

  1. Stefan Ladstätter Posted 26 days and 16 hours ago

    Shouldn't this link to "desktop.css" instead of "explorer.css"?

  2. Leslie Murphy Posted 11 days and 11 hours ago

    Should you mention that apple recommends using this approach? It sounds like media="handheld" will NOT work for the iPhone ...

  3. Leslie Murphy Posted 11 days and 11 hours ago

    A bit off topic - but is this library relevant to your book? Should it be mentioned somewhere?

    http://code.google.com/p/iui/

Add a comment

So now it’s time to edit the HTML document: delete the existing link to the screen.css CSS file, and replace it with the lines just shown. This way, you will have a clean slate for the iPhone-specific CSS that I’ll show you in this chapter.

Control the Page Scaling

Unless you tell it otherwise, Safari on iPhone is going to assume that your page is 980px wide (Figure 2.3, “iPhone assumes a normal web page is 980px wide”). In the majority of cases, this works great. However, you are going to format our content specifically for the smaller dimensions of the iPhone, so you must let Mobile Safari know about it by adding a viewport meta tag to the head element of the HTML document:

<meta name="viewport" content="user-scalable=no, width=device-width" />
        

3 comments

  1. Garrett Murray Posted 1 month, 20 days and 12 hours ago

    Remove spaces so it reads: <meta name="viewport" content="user-scalable=no, width=device-width" />

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    Also, ack, is setting user-scalable=no a good practice to teach here?

  3. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    @Andrew - I think that user-scalable=no is perfectly reasonable for a page that we are specifically optimizing for the iPhone. Eventually we are going to build up to web apps, and I always think it feels weird if an app can zoom. Maybe it's just me, though ;-)

Add a comment

Note

The viewport meta tag will be ignored by browsers other than Mobile Safari, so you can include it without worrying about the desktop version of your site.

Caution

If you don’t set the viewport width, the page will be zoomed way out when it first loads.

Figure 2.3. iPhone assumes a normal web page is 980px wide

iPhone assumes a normal web page is 980px wide

1 comment

  1. Stefan Ladstätter Posted 26 days and 16 hours ago

    This is trivial: none of the screenshots match the HTML source code from above.

Add a comment

Figure 2.4. Setting the viewport to the width of the device make your pages a lot more readable on iPhone.

Setting the viewport to the width of the device make your pages a lot more readable on iPhone.

Merely by suppressing the desktop stylesheet and configuring your viewport, you will have already given your iPhone users an enhanced experience (Figure 2.4, “Setting the viewport to the width of the device make your pages a lot more readable on iPhone.”). To really impress them, let’s start building the iphone.css stylesheet.

2 comments

  1. Marcel Grünauer Posted 1 month, 20 days and 11 hours ago

    "suppressing" (missing "p")

  2. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Nice! Thanks.

Add a comment

Adding the iPhone CSS

There are a number of user interface (UI) conventions that make an iPhone app look like an iPhone app. In the next section, I’ll add the distinctive title bar, lists with rounded corners, finger friendly links that look like glossy buttons, etc. With the text editor of your choice, create a file named iphone.css and add the following to it, then save the file in the same directory as your HTML document:

3 comments

  1. Garrett Murray Posted 1 month, 20 days and 12 hours ago

    "HTML I'll BE working with" not "b working with"

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    Suggest removing "Please follow along while I give this page...." sentence. As readers, we are always following along, we have no choice in this. (Good general rule: "omit needless words.")

  3. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Good points. I'll update.

Add a comment

Example 2.2. Setting some general site-wide styles on the HTML body element.

body {
    background-color: #ddd; /* Background color */
    color: #222;            /* Foreground color used for text */
    font-family: Helvetica; 
    font-size: 14px;
    margin: 0;              /* Amount of negative space around the outside of the body */
    padding: 0;             /* Amount of negative space around the inside of the body */
}
            

Tip

Note that I have set the overall font for the document to Helvetica, which is the font used by most of the applications on the iPhone. If you are trying to achieve a professional look, you should probably stick with Helvetica unless you have a specific reason not to.

1 comment

  1. Ali B. Posted 1 month, 2 days and 15 hours ago

    A very quick roundup of fonts available for use by iPhone applications would be good here.

Add a comment

Now, I’ll attack the header div that contains the main home link (i.e. the logo link) and the primary and secondary site navigation. The first step is to format the logo link as a clickable title bar. Add the following to the iphone.css file:

#header h1 {
    margin: 0;
    padding: 0;
}
#header h1 a {
    background-color: #ccc;
    border-bottom: 1px solid #666;
    color: #222;
    display: block;
    font-size: 20px;
    font-weight: bold;
    padding: 10px 0;
    text-align: center;
    text-decoration: none;
}
        

I’m going to format the primary and secondary navigation ul blocks identically, so I can just use the generic tag selectors (i.e. #header ul) as opposed to the tag ids (i.e. #header ul#utility, #header ul#nav):

#header ul {
    list-style: none;
    margin: 10px;
    padding: 0;
}
#header ul li a {
    background-color: #FFFFFF;
    border: 1px solid #999999;
    color: #222222;
    display: block;
    font-size: 17px;
    font-weight: bold;
    margin-bottom: -1px;
    padding: 12px 10px;
    text-decoration: none;
}
        

Figure 2.5. A little bit of CSS can go a long way toward enhancing the usability of your iPhone app.

A little bit of CSS can go a long way toward enhancing the usability of your iPhone app.

3 comments

  1. Garrett Murray Posted 1 month, 20 days and 12 hours ago

    Figure 2.5 seems out of order here. You've already styled the lists, yet the figure shows plain text. The reference in the following para makes no sense. This should come BEFORE the lists are styled, and shouldn't be referenced after.

  2. Matthew Simon Ryan Cavalletto Posted 1 month, 8 days and 8 hours ago

    Image above is ch2-iPhoneCssStep1.png but should be ch2-iPhoneCssStep2.png.

  3. Jonathan Stark Posted 1 month, 2 days and 2 hours ago

    Fixed. Thanks!

Add a comment

Pretty simple so far, right? With this little bit of CSS, we have already made a big improvement on the iPhone page design (Figure 2.5, “A little bit of CSS can go a long way toward enhancing the usability of your iPhone app.”). Next, add some padding to the content and sidebar divs to indent the text from the edge of the screen a bit (Figure 2.6, “Indenting text from the edges.”):

#content, #sidebar {
    padding: 10px;
}
        

3 comments

  1. Ben Parizek Posted 1 month, 5 days and 5 hours ago

    content is an id here in the stylesheet but it is a class in the html above.

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    Seems a little weird to me to break out the addition of padding as a separate step here. Is it so critical that it needs this specificity?

  3. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Ben - Great eye. Thanks!

    @Andrew - I called out padding because I wanted to support the tip below about not adding padding to the body.

Add a comment

Tip

You might be wondering why I added padding to the content and sidebar elements instead of setting it globally on the body element itself. The reason is that it’s very common to have elements that you want to have displayed edge to edge (as with the header in this example). Because of this, padding applied to the body or some other global wrapper element can become more trouble than it’s worth.

The content in the footer of this page is basically a rehash of the navigation element (the ul element with the id nav) at the top of the page, so you can remove the footer from the iPhone version of the page by setting the display to none.

#footer {
    display: none;
}
        

Figure 2.6. Indenting text from the edges.

Indenting text from the edges.

Adding the iPhone Look and Feel

Time to get a little fancier. Starting from the top of the page, add a 1 pixel white drop shadow to the logo link text, and a CSS gradient to the background:

#header h1 a {
    text-shadow: 0px 1px 0px #fff;
    background-image: -webkit-gradient(linear, left top, left bottom, 
                                       from(#ccc), to(#999));
}
        

If you are not familiar with the text-shadow declaration, the parameters from left to right are: horizontal offset, vertical offset, blur, and color. Most of the time, you’ll be applying the exact values shown here to your text because that’s what usually looks good on the iPhone, but it is fun to experiment with text-shadow because it can add a subtle but sophisticated touch to your design.

The -webkit-gradient line deserves special attention. It’s an instruction to the browser to generate a gradient image on the fly. Therefore, a CSS gradient can be used anywhere you would normally specify a url() (e.g. background image, list style image). The parameters from left to right are as follows: the gradient type (can be linear or radial), the starting point of the gradient (can be left top, left bottom, right top, or right bottom), the end point of the gradient, the starting color, and the ending color.

3 comments

  1. Andrew Posted 1 month, 5 days and 4 hours ago

    Perhaps it's supposed to be obvious, but it seems worth pointing out that the -webkit* family of CSS selectors are unique to WebKit browsers, that they'll be things you'll be using to apply more iPhone-specific styles later in the book, and maybe how these weirdo custom selectors relate to CSS as a whole.

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Andred - good point about -webkit selectors. I'll try to work it in.

  3. Leslie Murphy Posted 11 days and 11 hours ago

    Jonathan, can you give a link to learn more about Webkit and all the custom goodies you are using? As a reader I'm wondering "how did Jonathan learn about this in the first place", and "where would I go for more information" (other than Google) :-)

Add a comment

Tip

Note that you cannot reverse the horizontal and vertical portions of the four gradient start and stop point constants (i.e. left top, left bottom, right top, or right bottom). In other words, top left, bottom left, top right, and bottom right are invalid values.

The next step is to add the traditional rounded corners to the navigation menus.

#header ul li:first-child a {
    -webkit-border-top-left-radius: 8px;
    -webkit-border-top-right-radius: 8px;
}
#header ul li:last-child a {
    -webkit-border-bottom-left-radius: 8px;
    -webkit-border-bottom-right-radius: 8px;
}
        

As you can see, I’m using corner-specific versions of the -webkit-border-radius property to apply an 8 pixel radius to both the top two corners of the first list item, and the bottom two corners of the last list item (Figure 2.7, “Gradients, text shadows, and rounded corners start to transform your web page into a native looking iPhone app.”).

It would be cool if you could just apply the border radius to the enclosing ul, but it doesn’t work. If you try it you’ll see that the square corners of the child list items will overflow the rounded corners of the ul, thereby negating the effect.

2 comments

  1. Garrett Murray Posted 1 month, 20 days and 11 hours ago

    It would be worth quickly describing WHY this doesn't work, and what first-child and last-child mean.

  2. Garrett Murray Posted 1 month, 20 days and 11 hours ago

    Oops, didn't see the notes below--ignore my previous comment.

Add a comment

Figure 2.7. Gradients, text shadows, and rounded corners start to transform your web page into a native looking iPhone app.

Gradients, text shadows, and rounded corners start to transform your web page into a native looking iPhone app.

Note

Technically, I could achieve the rounded list effect by applying the radius corners to the ul if I set the background color of the ul to white, and set the background of its child elements to transparent. However, when you click the first or last items in the list, the tap highlight will show up squared off and it looks terrible. Your best bet is to apply the rounding to the a tags themselves as I’ve demonstrated here.

Caution

The first-child and last-child pseudo classes can be a bit confusing. For example, li:first-child will select the first li that is the child of its ul parent. It does not select whatever is the first child of the li.

1 comment

  1. Leslie Murphy Posted 11 days and 11 hours ago

    This might be a good place to remind the user where to read more about complex CSS selectors. Not sure if this is a URL you would want to use or not:

    "For more information on CSS pseudo classes, see http://www.w3.org/TR/CSS2/selector.html#first-child" or http://www.w3schools.com/Css/pr_pseudo_first-child.asp

Add a comment

1 comment

  1. Andrew Posted 1 month, 5 days and 4 hours ago

    This comment's a little unrelated to this specific node, but again I want to suggest you reconsider that "crash course" stuff at the start of the book. It doesn't give enough background for a newbie to understand concepts like :first-child psuedo classes or other advanced topics you'v already covered. You should use that space to give some brief examples of the kind of HTML/CSS/JS that you should already know before starting this book.

Add a comment

Adding Basic Behavior with jQuery

One of my favorite things about building web apps for the iPhone is that I can be reasonably sure that JavaScript is enabled. Regrettably, this is not the situation when building websites for desktop browsers. My next step is to add some JavaScript to my page to support some basic dynamic behavior. In particular, I want to allow the user to show and hide the big honking navigation section in the header so that they only see it when they want to. In order to make this work, I’m going to write some new CSS, and use some JavaScript to apply the new CSS to the existing HTML.

6 comments

  1. Andy Frazier Posted 1 month, 20 days and 14 hours ago

    I think you meant "this is not the situation when building websites for desktop browsers" or "when building a website for..." - i.e., pluralize website or add "a" before it...

  2. Marcel Grünauer Posted 1 month, 20 days and 11 hours ago

    "JQuery" in the header should be "jQuery".

  3. Linda Posted 1 month, 17 days and 13 hours ago

    Unless the OS has changed, you cannot be sure that JavaScript is enabled. I have had this problem in the past. It can be changed in the iPhone's Preferences.

  4. Andrew Posted 1 month, 5 days and 4 hours ago

    "Big honking"? Is it really?

  5. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Andrew - yeah, you can't hear that thing? Like flock of geese ;-)

  6. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Changes made - thanks for all these comments!

Add a comment

First, let’s take a look at the new CSS. Step one is to hide the ul elements in the header so they don’t show up when the user first loads the page. If you are following along at home, open your iphone.css file and add the following:

#header ul.hide {
    display: none;
}
        

Next, I’ll define the styles for the button that will show and hide the menu. Note that the button does not exist in the HTML yet; For your information, the HTML for the button is going to look like this:

1 comment

  1. Stefan Ladstätter Posted 26 days and 16 hours ago

    Spelling mistake: "yet; For" should either be "yet; for" or "yet. For"

Add a comment

            
<div class="leftButton" onclick="toggleMenu()">Menu</div>
            
        

2 comments

  1. Mike Boulet Posted 1 month, 21 days and 10 hours ago

    When and where to I put this HTML code fragment?

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Thanks, I'll update with a reference.

Add a comment

I’ll describe the button HTML in detail a bit further down (the section called “Adding Basic Behavior with jQuery”), so don’t bother adding the preceding line of code to your HTML file yet. The important thing to note is that it’s a div with the class leftButton and it’s going to be in the header.

3 comments

  1. Garrett Murray Posted 1 month, 20 days and 11 hours ago

    Actually, you classed it .button.left not leftButton, which makes this reference and the following CSS incorrect

  2. Jonathan Stark Posted 1 month, 20 days and 1 hour ago

    That's why you make the big bucks ;-) Good catch, thx!

  3. Andrew Posted 1 month, 5 days and 4 hours ago

    Wait, he's making money off this? :-)

Add a comment

Here is the CSS style for the button (you can go ahead and add this to the iphone.css file):

#header div.leftButton {
    position: absolute;1
    top: 7px;
    left: 6px;
    height: 30px;2
    font-weight: bold;3
    text-align: center;
    color: white;
    text-shadow: rgba(0,0,0,0.6) 0px -1px 0px;4
    line-height: 28px;5
    border-width: 0 8px 0 8px;6
    -webkit-border-image: url(images/button.png) 0 8 0 8;7
}
        

5 comments

  1. Nile Posted 1 month, 13 days and 12 hours ago

    Where do I get the "button.png" and "button_clicked.png" graphics?

    This button graphic does not load with this CSS in the iphone.css stylesheet. However, it does load if I include the CSS in the head section of the HTML.

    The button_clicked graphic is not working at all.

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Good question. I'll update with links.

  3. Scott Jungling Posted 28 days and 14 hours ago

    As a thought, have you tried putting the number graphics on the left? It might be easier for the reader to scan

  4. Anders Monsen Posted 28 days and 4 hours ago

    When I tried < top: 7px; left: 6px > the button from jqTouch and text did not appear centered, but rather high and to the left. Also, the button was not blue as your image, but rather black. Not sure if changes were made to the graphics.

  5. Anders Monsen Posted 28 days and 4 hours ago

    Hmm, maybe I did something in the CSS. When I changed the background-color for the body to #CCCCCC the header adjusted, and I could revert to < top: 7px; left: 6px > and reset the background-color to #ddd. Very strange.

Add a comment

Tip

For the graphics used in this chapter, you can download jQTouch from http://jqtouch.com/ and copy them from the themes/jqt/img directory. Put these copies into an images subdirectory beneath the directory that contains your HTML document (you'll probably need to create the images directory). We’ll be talking about jQTouch in detail in Chapter 4, Animation.

1

Taking it from the top, I set the position to absolute to remove the div from the document flow, which allows me to set its top and left pixel coordinates.

3 comments

  1. Andrew Posted 1 month, 5 days and 4 hours ago

    Maybe a good place to start introducing iPhone UI guidelines like "make buttons big enough to tap"?

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Will do.

  3. Leslie Murphy Posted 11 days and 11 hours ago

    What does "remove from the document flow" mean? Please explain.

Add a comment

2

Here, I set the height to 30px so it’s big enough to tap easily.

3

Next, I style the text bold, white with a slight drop shadow, and centered in the box.

4

In CSS, the rgb function is an alternative to the familiar hex notation typically used to specify colors (e.g. #FFFFFF). rgb(255, 255, 255) or rgb(100%, 100%, 100%) are both the same as #FFFFFF. More recently, the rgba() function has been introduced, which allows you to specify a fourth parameter that defines the alpha value (i.e. opacity) of the color. The range of allowable values is 0 to 1, where 0 is fully transparent and 1 is fully opaque; decimal values between 0 and 1 will be rendered translucent.

1 comment

  1. Leslie Murphy Posted 11 days and 11 hours ago

    which versions of common browsers support rgba? FF, Safari, IE, Opera, ...

Add a comment

5

The line-height declaration moves the text down vertically in the box so it’s not flush up against the top border.

6

The border-width and -webkit-border-image lines require a bit of explanation. These two properties together allow you to assign portions of a single image to the border area of an element. This means no more non-semantic nested divs or slicing images into topLeftCorner.png, topRightCorner.png, etc. If the box resizes because the text increases or decreases, the border image will stretch to accommodate it. It’s really a great thing; fewer images means less work, less bandwidth, and shorter load times.

3 comments

  1. Mike Boulet Posted 1 month, 21 days and 10 hours ago

    spelling: propoerties

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    "Non-semantic divs" might be better than "pointless divs". After all, those extra divs had a point: to provide hooks for extra background images.

  3. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Thanks guys - I'll update.

Add a comment

With the border-width line, I’m telling the browser to apply a 0 width border to the top, an 8px border to the right, a 0 width border to the bottom, and an 8px width border to the left (i.e. the four parameters start at the top of the box and work their way around clockwise). Note that I don’t need to specify a color or style for the border.

7

With the border widths in place, I can apply the border image. The five parameters from left to right are: the url of the image, the top width, the right width, the bottom width, and the left width (again, clockwise from top). The url can be absolute (http://example.com/myBorderImage.png) or relative. Relative paths are based on the location of the stylesheet, not the HTML page that includes the stylesheet.

Tip

When I first encountered the border image property, I found it odd that I had to specify the border widths when I had already done so with the border-width property. After some painful trial and error, I discovered that the widths in the border-image property are not border widths; they are the widths to slice from the image. Taking the right border as an example, I’m telling the browser to take the left 8px of the image and apply them to the right border, which also happens to have an 8px width.

1 comment

  1. Leslie Murphy Posted 11 days and 11 hours ago

    Do you want to mention here where to go to learn more about borders, etc.? e.g. provide a link to http://www.w3schools.com/css/css_boxmodel.asp or mention the right google phrase to search

Add a comment

It is possible to do something irrational such as applying the right 4 pixels of an image to a border that is 20px wide. To make this work properly, you have to use the optional parameters of webkit-border-image that instruct the image what to do with the slice in the available border space (repeat, stretch, round, etc.). In three years of trying, I have failed to come up with any sane reason to do this, so I won’t waste space here describing this confusing and impractical option of an otherwise killer feature.

1 comment

  1. Leslie Murphy Posted 11 days and 11 hours ago

    You lost me here. "I have failed to come up with any sane reason to do this" yet it is "an otherwise killer feature". I did not understand the take-away point

Add a comment

Okay, time for some JavaScript. In preparation for the JavaScript you’re about to write, you need to update HTML document to include jquery.js and iphone.js. Add these lines to the head section of your HTML document:

1 comment

  1. Linda Posted 13 days and 10 hours ago

    "you need to update HTML" should be add "the" before "HTML"

Add a comment

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="iphone.js"></script>

5 comments

  1. Nile Posted 1 month, 13 days and 12 hours ago

    Where does the jquery.js script come from?

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    In order to let readers test each step as they copy it, it would be better to have us add jquery.js in an earlier step. Otherwise the document.ready stuff above won't work until you also complete this later step. In general, the project should work after each discrete step.

  3. William Doane Posted 1 month, 4 days and 6 hours ago

    the SRCs should probably not go to the root... src="/scripts/jquery.js" --> src="scripts/jquery.js"

  4. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Nile - it comes from jquery.com. See the note above. I'm not sure if the note was there when you posted your question.

    @Andrew - Fixed, thanks.

    @William - As the examples get more complex, I do have readers move the scripts into their own directory.

  5. James Greenwood Posted 8 days and 15 hours ago

    Isnt it a more accepted practice to link to the jQuery file on Google Code? Caching amongst other reasons!

Add a comment

Note

jQuery downloads, documentation, and tutorials are available at http://jquery.com. To use jQuery, you will need to download it from there, rename the file you downloaded (such as jquery-1.3.2.min.js) to jquery.js, and put a copy of it in the same directory as your HTML document.

The primary duty of the JavaScript we need to write is to allow the user to show and hide the nav menus. Copy the following JavaScript into a file called iphone.js and save it in the same folder as the HTML file:

3 comments

  1. William Doane Posted 1 month, 4 days and 6 hours ago

    The navigation menus were already hidden by pure CS, above: #header ul.hide { display: none; }

  2. William Doane Posted 1 month, 4 days and 6 hours ago

    CSS*

  3. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Good catch - I changed the way the example worked and didn't update the prose. Thanks!

Add a comment

            
if (window.innerWidth && window.innerWidth <= 480) { 1
    $(document).ready(function(){ 2
        $('#header ul').addClass('hide'); 3
        $('#header').append('<div class="leftButton" onclick="toggleMenu()">Menu</div>'); 4
    });
    function toggleMenu() { 
        $('#header ul').toggleClass('hide'); 5
        $('#header .leftButton').toggleClass('pressed'); 6
    }
}
            
        

1 comment

  1. Andrew Posted 1 month, 5 days and 4 hours ago

    Wasn't the header ul already hidden by default with a css display:none declaration?

Add a comment

2 comments

  1. Mike Boulet Posted 1 month, 21 days and 10 hours ago

    I like the number highlights.

    There was no reference to what I should do with the javascript code. I notice a little way down there is a reference to the iphone.js file. Maybe say something like "Create the iphone.js file and copy the following code into it".

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    I'll update. Thanks!

Add a comment

1

The entire page is wrapped in an if statement that checks to make sure the innerWidth property of the window object exists (it doesn’t exist in some versions of Internet Explorer) and that the width is less or equal to than 480 (the max width for the iPhone). By adding this line, we ensure that the code only executes when the user is browsing the page with an iPhone, or some other similarly sized device.

3 comments

  1. Linda Posted 1 month, 17 days and 13 hours ago

    "checks to make sure the innerWidth property" should be "checks to make sure that the innerWidth property"

    "that that" should be "that the"

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    Hmm, is this a good way to identify the iPhone browser? Is it worth mentioning more reliable ways here, like checking the user-agent?

  3. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Linda - thanks!

    @Andrew - Maybe, but I'm secretly trying to keep things android friendly without being overly explicit.

Add a comment

Caution

If you are testing your iPhone web pages using the desktop version of Safari as described in Don’t have a website?, the if statement here will fail if your browser’s window width is too large. As a workaround, you enter the following line of JavaScript into Safari’s location bar to resize your browser to more iPhone-esque dimensions:

javascript:window.scrollTo(0,0);resizeTo(320,480);

Note, however, that this will have no effect on which stylesheet is selected (see the section called “Prepare a Separate iPhone Stylesheet”).

1 comment

  1. Leslie Murphy Posted 11 days and 10 hours ago

    Jonanthan, would you recommend that users also consider using an iPhone browser simulator? A quick search turned up: http://testiphone.com/ and http://labs.blackbaud.com/NetCommunity/article?artid=662

Add a comment

2

Here we have the so called “document ready” function. If you are new to jQuery, this can be a bit intimidating, and I admit that it took me a while to memorize the syntax. However, it’s worth taking the time to commit it to memory because you’ll be using it a lot. The document ready function basically says, “when the document is ready, run this code.” More on why this is important in a sec.

3 comments

  1. Marcel Grünauer Posted 1 month, 20 days and 11 hours ago

    Again, "JQuery" should be "jQuery". This probably occurs more often in the book (e.g., in the next paragraph as well), so I'm not going to mention it from now on.

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    Thanks! I'll try to be more careful.

  3. Leslie Murphy Posted 11 days and 10 hours ago

    I would call out that this design pattern is very common in Javascript, and that what you are doing here is defining a function that the browser calls when a particular event is triggered. e.g. "The function defined in this statement will be triggered when the page is fully loaded"

Add a comment

3

This is typical jQuery code that begins by selecting the uls in the header and adding the “hide” CSS class to them. Remember, hide is the selector we used in the CSS above. The net effect of executing this line is to, well, “hide” the header ul elements. Take special note: had we not wrapped this line in the document ready function, it would have mostly likely executed before the uls were even finished loading. This means that the JavaScript would load, and this line would fail because the uls wouldn’t exist yet, the page would continue loading, the uls would appear, and you’d be scratching your head (or smashing your keyboard) wondering why the JavaScript wasn’t working.

6 comments

  1. Jakob Torp Svendsen Posted 1 month, 13 days and 23 hours ago

    Is there a reason for making the css and adding a class to hide, instead of just using the jQuery hide() function to hide the element. Also using HTML classes such as, hide, red, etc. is not what HTML is meant for. It is a semantic language.

  2. Jonathan Stark Posted 1 month, 13 days and 7 hours ago

    Thanks for the comment. My reasoning is that this code is more explicit for folks who are not familiar with these concepts. Folks like yourself who are already cool with this stuff are automatically going to optimize with toggle(), etc... Hopefully this seems like a fair compromise?

  3. Andrew Posted 1 month, 5 days and 4 hours ago

    I'm not sure I agree, mostly because of my comments elsewhere that I'm not sure you're really hitting your target audience here. I think you'd be better off assuming the audience is familiar with these concepts, which would let you illustrate examples with better code.

  4. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    I hear where y'all are coming from, but my primary goal is to make the concepts understandable to a broad range of skill levels. There are a number of places where I've felt it was important to trade best-practices for clarity. This is not a perfect compromise, but it is a conscious one.

  5. Stefan Ladstätter Posted 25 days ago

    I don't see how adding unnecessary and non-semantic CSS classes makes this more clear for the beginner. Although I have developed web sites in the old days, I am pretty inexperienced when it comes to Web 2.0/CSS, and I would appreciate not defining extra classes in CSS for this purpose. I'd rather just leverage the jQuery functions, especially if we're going to work with them throughout the book anyway.

  6. Leslie Murphy Posted 11 days and 10 hours ago

    I agree with Jakob and Stefan - use the jQuery hide() here

Add a comment

4

Here is where I append a button to the header that will allow the user to show and hide the menu (Figure 2.8, “The menu button has been added to the toolbar dynamically using jQuery.”). It has a class that corresponds to the CSS we wrote previously for .leftButton, and it has an onclick handler that calls the function toggleMenu() that comes next.

5

The toggleMenu() function uses jQuery’s toggleClass() function to add or remove the specified class to the selected object. On this line, I’m toggling the hide class on the header uls.

2 comments

  1. Jakob Torp Svendsen Posted 1 month, 13 days and 23 hours ago

    Again, why not just use .toggle(), instead of using classes. It's less verbose, more readable and a "better" practice.

  2. Andrew Posted 1 month, 5 days and 4 hours ago

    Agreed.

Add a comment

6

Here, I’m toggling the pressed class on the header leftButton.

Figure 2.8. The menu button has been added to the toolbar dynamically using jQuery.

The menu button has been added to the toolbar dynamically using jQuery.

Come to think of it, we haven’t written the CSS for the pressed class yet so let’s do so now. Go back to iphone.css and insert the following:

#header div.pressed {
    -webkit-border-image: url(images/button_clicked.png) 0 8 0 8;
}
        

2 comments

  1. Leslie Murphy Posted 11 days and 10 hours ago

    When and why is the 0 8 0 8 needed? Won't the browser use the png image size by default?

  2. Scott Murphy Posted 3 days and 8 hours ago

    The 0 8 0 8 corresponds to image padding [top right bottom left] not the image size.

Add a comment

As you can see, I’m simply specifying a different image for the button border (it happens to be slightly darker). This will add a two-state effect to the button that should make it evident to the user that the button can both show and hide the menu (Figure 2.9, “The menu button displays darker when it has been pressed to display the menu options.”).

1 comment

  1. Leslie Murphy Posted 11 days and 10 hours ago

    Is the latest standard to use css to do this (and rollover effects) without requiring a 2nd image? I'm new to this, but it seems like that is what folks are moving to. e.g. http://www.elated.com/articles/css-rollover-buttons/ or http://www.xul.fr/en/css/button.php

Add a comment

Figure 2.9. The menu button displays darker when it has been pressed to display the menu options.

The menu button displays darker when it has been pressed to display the menu options.

Figure 2.10. A tall view of the completed basic iPhone CSS.

A tall view of the completed basic iPhone CSS.

4 comments

  1. Mike Boulet Posted 1 month, 21 days and 9 hours ago

    Where did the about text come into this example?

  2. Garrett Murray Posted 1 month, 20 days and 11 hours ago

    The JS code doesn't remove the menu button, so why is it missing from this screenshot?

  3. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Mike - I've updated the HTML at the top of the chapter to include the about text.

    @Garrett - Another great catch, thanks!

  4. Jason Borgmann Posted 27 days and 3 hours ago

    You have the #footer set to display: none; above so it probably shouldn't be showing in your screenshots.

Add a comment

What You’ve Learned

In this chapter, I covered the basics of converting an existing web page to a more iPhone friendly format. I even used on a bit of dynamic HTML to show and hide the navigation panels. In the next chapter, I’ll build on these examples while introducing some more advanced JavaScript concepts; in particular, some yummy Ajax goodness.

2 comments

  1. Andrew Posted 1 month, 5 days and 4 hours ago

    Some yummy what now? Ajax? Has this concept been introduced yet?

  2. Jonathan Stark Posted 1 month, 2 days and 1 hour ago

    @Andrew - That is precisely the question I want the reader to ask; it is answered on the next page. ;-)

Add a comment

You must sign in or register before commenting

Atom Icon Comments on this page or Comments on the whole book.