iPhone Buttons without Border Images

Works in Safari, Chrome, iPhone, iPad, Android

There are five frameworks for mobile Webkit Web app development: iUI, UiUIKit, iWebKit, jqTouch and Sencha. All of these frameworks provide a simple way to implement a common interface feature of the iPhone, the slightly translucent buttons used for implementing actions. By using the CSS3 border image property it becomes trivial to use a highly compact graphic as a border image to create the visual effect of a glossy, translucent button. It’s also economical because the images are single pieces. Here are the three main ones:

White Translucent ButtonBlack Translucent ButtonBlue Translucent Button

Using the CSS3 border image property, we can create fancy buttons that are dynamic. Here’s the necessary CSS:

.plasticButton {
	cursor: pointer;
	margin: 5px;	
	text-align: center;
	color: #ffffff;
	font: bold 16px/20px Helvetica, sans-serif;
	text-decoration: none;
	text-shadow: 1px 1px 1px #000;
	text-transform: capitalize;
	display: inline-block;
	font-size: 16px;
	border-width: 0 14px;
	padding: 12px 0px;
	min-width: 110px;
}
.plasticButton.white {
	color: #000;
	text-shadow: #fff 0px 1px 1px;
	-webkit-border-image: url(whiteButton.png) 0 14 0 14;
}
.plasticButton.gray {
	color: #fff;			
	text-shadow: #333 0px 1px 1px;
	-webkit-border-image: url(grayButton.png) 0 14 0 14;
}
.plasticButton:hover, .plasticButton.hover {
	color: #fff;
	text-shadow: #333 0px 1px 1px;
	-webkit-border-image: url(blueButton.png) 0 14 0 14;
}

This would give us buttons like these:
Example of translucent buttons using the border image property

Not too bad. Well, except for the images. What if we need to change the color of the buttons for a custom theme? These images are not easily modified in Photoshop. Without Apple releasing the original artwork for use by the general public, there is no way to fine tune them for different color schemes. Also, if you intend on using them in a Web app, you’ve got to include them in a cache.manifest, etc. After thinking about all the niggling aspects of buttons using border images, I started thinking about how I could reproduce their look using just the CSS3 features we have now. Here is what I came up with. All you need is a border-radius, a border, a gradient, a box-shadow and a text shadow:

.button.black {
	display: inline-block;
	-webkit-border-radius: 12px;
	-webkit-box-shadow: 2px 2px 3px #999; 
	border: solid 3px rgb(110,110,110);
	background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(74,74,74,0.85)), color-stop(0.5, rgba(20,20,20,0.75)), color-stop(0.5, rgba(2,2,2,0.75)), to(rgba(14,14,14,0.75))); 
	color: #fff;
	text-shadow: #000 0 1px 0;
	font: bold 16px/20px Helvetica, Sans-serif;
	padding: 9px 11px;
}
.button.black:hover, .button.black.hover {
	background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(135,148,203,0.85)), color-stop(0.5, rgba(34,56,159,0.75)), color-stop(0.5, rgba(0,27,145,0.75)), to(rgba(2,59,152,0.65)));  
	color: #fff;
	text-shadow: #000 0 1px 0;
	-webkit-box-shadow: inset rgba(207,207,255,0.75) 0px 1px 1px;
}

Because the gradients values use rbga colors with alpha values, they are slightly translucent. By changing the values of the gradient, you can easily create different colored buttons. I’ve upload a working example, and you can also download the code. Do so and play around with the values. I’ve included a number of different default colors: black, white, red, green, gold and blue. You can make other yourself.

Advertisements

iPad Dropdown Menu with CSS3

Works with Safari, iPhone, iPad

One thing noticeable about the iPad’s interface, in contrast to that of the iPhone, is the gorgeous dropdown menus. They have a highly polished look with their gradients and drop shadows. For a while now I was wondering if it would be possible to re-create their look using only CSS3. If you haven’t seen them yet, here is a sample:

Typical iPad dropdown menu

With CSS3 we can easily create the rounded corners, gradients and drop shadows. But what about the menu pointer? That part had me scratching my head for a while. I debated whether to use a canvas element. But I had already decided that I would pull this off using only CSS3. So, what I decided to do was use a rotated div. First I filled it with the last color at the top of the gradient that I used on the top of the menu. Since I was going to rotate the div, I didn’t need border on all four sides, just one two. I was rotating the div 90 degrees, so I gave it a border matching the menu on the left and bottom. Of course after rotating the div I still had the problem of the other half of the div. To remove it I used a CSS3 image mask. For the image I used a CSS3 gradient that went from solid black halfway and then turned transparent. Since the div was rotated 45 degrees, I needed to create a gradient mask from the bottom left to the top right:

-webkit-transform: rotate(45deg);
-webkit-mask-image: -webkit-gradient(linear, left top, right bottom, from(#000000), color-stop(0.5,#000000), color-stop(0.5, transparent), to(transparent));

This effective cut the div in half diagonally. I then used position to move the div to where it needed to be.

I originally designed this menu to work on desktop Safari/Chrome so that I could mimic the iPad menus. However, it also works on the iPad. The desktop version has some subtle differences because I used inset box shadows to create depth. That won’t be on the iPad until the iOS 4 update.

You can see the finished example or download the source to see how I put it together.

And here’s the finished menu using only CSS3:
An iPad style dropdown menu create with CSS3

Creating a Web App From a Single HTML5 Document

Works with Safari, Chrome, iPhone, iPad, Adroid

Because the focus of this blog is about CSS3 and HTML5, I will only be discussing their implementation on browsers that support these. If you’re using IE6, IE7 or IE8, you’re out of luck. These are very backwards as far as support for present day Web technologies are concerned. I’ll mostly be looking at the developments taking place on Safari/Chrome/Firefox/Opera. And if the IE team can ever ship IE9, we’ll include that as well.

With the widespread adoption of smart mobile devices the state of Web development has been transformed beyond recognition. First there was the Web 2.0 Ajax revolution. Instead of links leading off to another page, a click would result in only a part of the page being updated with new data retrieved from the server. The power of smart devices that are literally computers that fit in the hand has given rise to a new development module: Web apps. The Web part of the name can be misleading because, depending on its design and purpose, after the initial download, a Web app may not need any further connection to the Web. Also, a Web does not need to be for mobile devices. With special attention one could make an app that works for mobile and desktop/tablet.

To create a Web app can be quite complicated, or quite straightforward. I’m going to take the straightforward approach and show how with a minimum of code you can turn a single HTML page into a multipart Web app with cool CSS3-based animation during navigation. As a side benefit, no images shall be harmed in the creation of this app. All graphics will be created with CSS3. We’ll need to start with a basic document. For the purposes of this article I’m going to use HTML5. Actually, the markup and CSS3 code could be implemented in HTML 4 or XHTML. But since HTML5 is the new darling of techies and regular folks alike, I’m using it.

An HTML5 document starts with a doctype. We indicate what language the document uses and a meta tag to indicate the type of encoding used. For the purposes of this demo I’m also going to include a meta tag for viewport properties for mobile devices. This will affect the display of the app on iPhones, Adroids, and Palm Pres. Here’s the basic document structure:

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width; height=device-height; initial-scale=1;">
      <title>My Kick Ass Web App</title>
   </head>
   <body>
   </body>
</html>

The next thing we need to do is implement the structure that will allow us to create the experience of a multi-page layout while having only one document. We can easily do this by using HTML5 semantic markup. The article tag makes this possible. In fact, the browser treats each article tag as if it were its own document. Each one can have its own h1. Similarly, search engines will treat each article as separate from the others so that the content is classified per article, not per document. I’m also going to use section tags for some fencing in of content, some buttons to return to the home page. Oh, well, and I’ll set up the home or landing page with its menu for accessing the other parts. Here’s the markup:

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width; height=device-height; initial-scale=1;">
      <title>My Kick Ass Web App</title>
   </head>
   <body>
	<article id="Home" class="current">
		<section>
<h1>Home</h1>
<p>		   <nav></p>
<ul class="menuList">
<li rel="#Article1">News</li>
<li rel="#Article2">Things To Do</li>
<li rel="#Article3">Confidential</li>
<li rel="#Article4">What Next?</li>
</ul>
<p>		   </nav></p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>		</section>
	</article>
        <article id="Article1">
		<section></p>
<h1>Everything You Didn't Want to Know About</h1>
<p>		   <span class="button back">Back</span></p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>		</section>
	</article>
	<article id="Article2">
		<section></p>
<h1>Explain to Me Exactly Why You Came to This Page</h1>
<p>		   <span class="button back">Back</span></p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>		</section>
	</article>
	<article id="Article3">
		<section></p>
<h1>I Know What You Did and I'm Telling</h1>
<p>		   <span class="button back">Back</span></p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>		</section>
	</article>
	<article id="Article4">
		<section></p>
<h1>How Do I Get Out of Here?</h1>
<p>		   <span class="button back">Back</span></p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>		</section>
	</article>
   </body>
</html>

You’ll notice on the Home page section that I have a nav tag with a menu. Not that unusual except that the menu items are just plain old list items, not anchor tags with href attributes. Note that each list item has a rel attribute with the value that it corresponds to. With a little bit of JavaScript this will create my navigation system. Similarly, the back buttons are not inputs or anchor tags but just basic span tags with classes. Using CSS3 I’ll use those classes to make those spans look and act like buttons, and a bit of JavaScript will make them facilitate backward navigation.

If you opened the above markup in an HTML5 capable browser, you wouldn’t see much, pretty plain Jane stuff. We need some CSS to make it look like some. We’ll also need some CSS3 to make it look better than something. I’m going to use CSS3 to create repeating background patterns, as well as background gradients, box shadows, text shadows, border radii and transforms. The basic look we’re going for initially is something like following image. Later we’ll make each article zoom full screen and allow navigation between them.

Basic rendering of styled articles

We’ll start off by getting rid of default padding and margins on the html and body tags. Then we’ll give the body tag the basic underling styling for our app:

html, body {
    padding: 0px;
    margin: 0px;
}
body {
    background: #cbd2d8;
    background-image: -moz-linear-gradient(left, #c5ccd4, #c5ccd4 75%, transparent 75%, transparent);
    background-image: -moz-linear-gradient(90deg, #496178, #2E4960);
    background-image: -webkit-gradient(linear, left top, right top, from(#c5ccd4), color-stop(0.75, #c5ccd4), color-stop(0.75, transparent), to(transparent));
    -webkit-background-size: 7px 100%;
    -moz-background-size: 7px 100%;
    font: normal 16px/22px Helvetica, Arial, Sans-serif;
   -webkit-text-size-adjust: 100%;
}
section, nav {
    display: block;
    padding: 20px;
}
article {
    display: block;
}

Next let’s style the h1 tags so they look like a typical app title header. Using a fancy background gradient and some text shadow will do the trick:

h1 {
	padding: 10px 20px;
	margin: -20px -20px 20px -20px;
	background-image: -moz-linear-gradient(top, #b0bccd, #889bb3 50%, #8195af 50%, #6d84a2);
	background-image: -webkit-gradient(linear, left top, left bottom, from(#b0bccd), color-stop(0.5, #889bb3), color-stop(0.5, #8195af), to(#6d84a2));
	text-shadow: 1px 1px 1px rgba(250,250,250,0.5);
	font: bold 24px/26px "Lucida Grande";
	letter-spacing: -1px;
	border-top: 1px solid #cdd5df;
	border-bottom: 1px solid #2d3642;
	text-shadow: 2px 2px 1px rgba(0,0,0,0.4);
	color: #fff;
}

Rather than going bit by bit I’m giving you all the styling parts now, except for a couple of pieces that will add navigation transitions.

html, body {
	padding: 0px;
	margin: 0px;
}
body {
	background: #cbd2d8;
	background-image: -moz-linear-gradient(left, #c5ccd4, #c5ccd4 75%, transparent 75%, transparent);
	background-image: -moz-linear-gradient(90deg, #496178, #2E4960);
	background-image: -webkit-gradient(linear, left top, right top, from(#c5ccd4), color-stop(0.75, #c5ccd4), color-stop(0.75, transparent), to(transparent)); 
	-webkit-background-size: 7px 100%;
	-moz-background-size: 7px 100%;
	font: normal 16px/22px Helvetica, Arial, Sans-serif;
	-webkit-text-size-adjust: 100%;
}
section, nav {
	display: block;
	padding: 20px;
}
article {
	display: block;
}
.button {
	-webkit-box-shadow: 2px 2px 3px #999; 
	-moz-box-shadow: 2px 2px 3px #999; 
	border: solid 1px #000;
	display: inline-block;
	cursor: pointer;
	padding: 4px 15px;
	-webkit-transition: all 0.5s  ease-in-out;
	-moz-transition: all 0.5s  ease-in-out;
}
.button:hover {
	-webkit-box-shadow: 0px 0px 8px #000; 
	-moz-box-shadow: 0px 0px 8px #000; 
}
.back {
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;
	background-image: -moz-linear-gradient(top, lightblue, darkblue 50%, blue);
	background-image: -webkit-gradient(linear, left top, left bottom, from(lightblue), to(blue), color-stop(0.5, darkblue));
	color: #fff;
}
ul, li {
	list-style: none;
	margin: 0px;
	padding: 0px;
}
.menuList {
}
.menuList li {
	cursor: pointer;
	padding: 8px;
	border-left:  1px solid #AAA;
	border-right: 1px solid #AAA;
	border-bottom: 1px solid #AAA;
	background-color: #fff;
}
.menuList li:hover {
	background-color: lightblue;
}
.menuList li:first-of-type {
	border-top: 1px solid #AAA;
	-webkit-border-top-right-radius: 10px;
	-webkit-border-top-left-radius: 10px;
	-moz-border-radius-topright: 10px;
	-moz-border-radius-topleft: 10px;
}
.menuList li:last-of-type {
	-webkit-border-bottom-left-radius: 10px;
	-webkit-border-bottom-right-radius: 10px;
	-moz-border-radius-bottomleft: 10px;
	-moz-border-radius-bottomright: 10px;
}
#Home {
	background: #cbd2d8;
	background-image: -moz-linear-gradient(left, #c5ccd4, #c5ccd4 75%, transparent 75%, transparent);
	background-image: -webkit-gradient(linear, left top, right top, from(#c5ccd4), color-stop(0.75, #c5ccd4), color-stop(0.75, transparent), to(transparent)); 
	-webkit-background-size: 7px 100%;
	-moz-background-size: 7px 100%;
}
#Article1 {
	background-color: #f8ffac;
}
#Article2 {
	background-color: #beffca;
}
#Article3 {
	background-color: #dbfff4;
}
#Article4 {
	background-color: #c2bfd4;
	background-image: -moz-linear-gradient(top, #c3c6cc, #c3c6cc 50%, transparent 50%, transparent); 
	background-image: -webkit-gradient(linear, left top, left bottom, from(#c3c6cc), color-stop(0.5, #c3c6cc), color-stop(0.5, transparent), to(transparent)); 
	-webkit-background-size: 10px 10px;
	-moz-background-size: 10px 10px;
}
#Article3 p {
	border: solid 2px #666;
	-webkit-border-radius: 20px;
	-webkit-box-shadow: 2px 2px 6px #666;
	-moz-border-radius: 20px;
	-moz-box-shadow: 2px 2px 6px #666;
	background-color: #fff;
	padding: 10px;
}
#More p {
	border: solid 2px #666;
	-webkit-border-radius: 20px;
	-moz-border-radius: 20px;
	background-color: rgba(120,120,120, 0.75);
	padding: 10px;
	-webkit-box-shadow: 2px 2px 6px #666;
	-moz-box-shadow: 2px 2px 6px #666;
	color: #fff;
	text-shadow: 1px 1px 1px #000;
}
h1 {
	padding: 10px 20px;
	margin: -20px -20px 20px -20px;
	background-image: -moz-linear-gradient(top, #b0bccd, #889bb3 50%, #8195af 50%, #6d84a2); 
	background-image: -webkit-gradient(linear, left top, left bottom, from(#b0bccd), color-stop(0.5, #889bb3), color-stop(0.5, #8195af), to(#6d84a2)); 
	text-shadow: 1px 1px 1px rgba(250,250,250,0.5);
	font: bold 24px/26px "Lucida Grande";
	letter-spacing: -1px;
	border-top: 1px solid #cdd5df;
	border-bottom: 1px solid #2d3642;
	text-shadow: 2px 2px 1px rgba(0,0,0,0.4);
	color: #fff;
}

These styles give us everything to create the image above. But now we need to add a bit more to create some transitions for navigation. Before we can navigate from one article to another, we’ll need to style the articles so that they can behave like separate parts. We’ll use absolute positioning and give each article a height and width of 100%. This would by default cause all the articles to stack on top of each other. Therefore what we’re going to do is move them offscreen. We’ll create a special class called “current” for the article we want to display, otherwise they’ll be offscreen. OK, so to do this we’ll need a little bit of JavaScript. This is just for one purpose, to change which article has a class of “current”. Then we’ll use CSS3 transitions to move the not current article off the screen and the current article onto the screen. I’ve already introduced a CSS3 transition for the .button class and .button:hover. But instead of targeting the box shadow, we’re going to target the left position of the article.

So, as I had mentioned earlier, we’re going to put the articles offscreen by using absolute positioning and negative left. Then we’ll transition them onto the screen when we add the “current” class to the article by giving it a left value of 0. The animation is all accomplished very efficiently by the CSS3 transition rendering without any of the problems of trying to do this with JavaScript. So, we need to update the CSS for the article tag and add a new class for “current”:

article {
	display: block;
	wwidth: 100%;
	wheight: 100%;
	wposition: absolute;
	left: -10000px;
	-webkit-transition: all 0.5s  ease-in-out;
	-moz-transition: all 0.5s  ease-in-out;
}
.current {
	left: 0px;
}

Now all we need is the JavaScript to add and remove the “current” class from the articles. Although I’m using jQuery for this, you could just as easily write the necessary JavaScript to do this. Here’s the code:

var sectionStack = ["#Home", "#Article1", "#Article2", "#Article3", "#Article4"];
$(document).ready(function() {
	$(".menuList li").click(function() {
		$.each(sectionStack,
			function(index, value) {
				$(value).removeClass("current");
			}
		);
		$($(this).attr("rel")).addClass("current");
	});
	$(".back").click(function() {
		$(this).parents().removeClass("current");
		$("#Home").addClass("current");
	});
});

This code only does two things. When the user clicks on a menu list item, the code grabs that list items rel attribute, which indicates which article to show. Then it removes the “current” class from all articles and sets that class to the target article. When the browser sees that class has been added, it renders the CSS3 transition, sliding the article that was current (Home) off the screen and sliding in the target article. Similarly, when the user clicks on the back button, the code removes the “current” class from the article and puts it on the home article, causing a CSS3 transition to take place. If you wanted to have deeper, nested navigation, you would have to use an array to keep tract of where you came from and were you’re heading. Just use the JavaScript array’s built in push and pop methods. I’ll probably show this in a later post.

This was not that much JavaScript or CSS, yet the result was a slick Web app. At the moment this demo works with Firefox 3.6, Safari 3, Google Chrome, iPhone, iPad, Android and Palm Pre. Firefox 3.6 does not have CSS3 transitions, although it does have transforms. I could have refactored the JavaScript to animate the transforms for Firefox 3.6, but I didn’t want to fork the code. Firefox 3.7, presently a downloadable alpha build, does support CSS3 transitions and this works fine with it. I could have implemented support for Opera, but since it still doesn’t have support for gradients, it looks awfully flat. I didn’t want to use images just for Opera, so I left it out for now. Everything else in Opera works fine: text-shadow, box-shadow, border radius and CSS3 transitions.

You can try the app out online or download the complete file.