Tag: kranthi

Developing WordPress Locally With MAMP





 



 


Local development refers to the process of building a website or Web application from the comfort of a virtual server, and not needing to be connected to the Internet in order to run PHP and MySQL or even to test a contact form. One of the most annoying parts of development, at least for me, is the constant cycle of edit, save, upload and refresh, which, depending on bandwidth and traffic, can turn a menial task into a nightmare.

With application platforms such as WordPress, which require a server back end to work, you would normally be constrained to develop on a live server, with the headaches that go along with that. MAMP and its Windows counterpart, WAMP, are tools that allow you to locally develop applications that require a server on the back end.

The Local Server

MAMP, which stands for Macintosh, Apache, MySQL and PHP, is an application that allows you to install a local server-type environment in order to construct websites that would normally require you be on a live server somewhere. Ever opened a contact form in a browser from your desktop and wondered why it doesn’t work? The server-side components cannot operate without (in this case) the PHP back end, and this is where MAMP comes in. By installing this application, we can have a virtual server locally as our development sandbox. It is worth noting, from a portability standpoint, that this component can be run only from your desktop environment and cannot be installed on a USB drive. With that all settled, let’s get to it.

In order to be able to work with MAMP, we must first obtain it. So, head over to the project page and download the disc image. Double-click to begin the installation, and you will be presented with a choice:

MAMP Installation Screen
MAMP and MAMP Pro are on the installation disc image.

Both MAMP and MAMP Pro come in the same download. You need to install only one, and for most scenarios, MAMP is more than adequate. The pro version costs $59.00 USD and offers more options, and you can compare the two versions for yourself.

Drag the MAMP folder onto the “Applicationâ€� shortcut, and the installation will be underway. Once it’s completed, feel free to eject the disc image. Open up your “Applicationsâ€� folder, and locate the new MAMP directory. Inside you’ll find MAMP.app, so — you guessed it — open it up. The program should start right away and open up your default browser, pointing to the start page. Congratulations, you now have a local server!

Preferences

From the main MAMP app screen, you will notice a “Preferences� button. Feel free to click on it to view the few options available.

MAMP App Screen
The MAMP app.

1. Start/Stop

From here, you have the option to tell MAMP when to start and stop the servers. If you choose to not start the servers automatically, then you will need to explicitly tell them to run each time you open the app. You may also set your home page, which defaults to the MAMP start screen, giving you quick access to phpMyAdmin; but you may set it to something like a WordPress directory.

MAMP Start/Stop Screen
Configuring the server.

2. Ports

In the “Ports� tab, the default Apache port will usually be 8888, and the default MySQL port will be 8889. I, for one, do not change these because they do not interfere with any of my other settings and do not require me to enter my password every time I start and stop the servers. You must include the port number in your URL this way; so, it would be localhost:8888/. To avoid this, you could change the ports to what general Web servers operate on: ports 80 and 3306. This will allow your URL to simply be localhost/; but you will most likely need to enter your password when switching the servers on and off. Another factor to consider is whether you are installing WordPress “multisite�; if you are, then you are required to set the ports to the default Apache and SQL ports of 80 and 3306, respectively.

MAMP ports setup
Setting up MAMP ports.

3. PHP

The “PHP� tab allows you to choose which version of PHP to run in the set-up. It will default to 5.3, and I do not change this because most applications I run either require PHP 5.3 or do not care. Just know that this option is available if you need it to run something such as legacy software.

MAMP PHP setup
Setting up the MAMP PHP version.

4. Apache

The “Apache� tab is one that I like to mess with, to change the document root directory. The root is where all of your websites and directories will be stored and accessed by MAMP, and it defaults to /Applications/MAMP/htdocs, which I find annoying to get to. So, I change mine to my sites folder. From the MAMP app window, click on “Preferences,� then on “Apache.� You can click “Select� and then set the installation to use the location of your choice for your websites. Again, I set mine to the sites folder for easier access.

MAMP Apache setup
Setting up MAMP Apache.

Installing WordPress

Now it is time to install WordPress. Head to the WordPress website and download the latest version, 3.2 as of this writing. Unzip the folder, and then simply drag it to your sites folder, (or wherever you chose to set the document root for MAMP). WordPress requires PHP and MySQL to operate, which is why we needed MAMP to develop locally; so, we now need need to make a database. Fear not: it is simple!

Open the MAMP start page — you can access it via the button in the main app — and click on “phpMyAdminâ€� in the top menu. Creating a new database is as simple as typing a name in the field and hitting the “Createâ€� button. You can see below that I am creating a new database aptly named “wordpress.â€� Once that’s done, feel free to close phpMyAdmin, and navigate to the WordPress directory in your document root.

Creating the Database
Simply type a name for the database, and hit “Create.�

Basic Configuration

Find the file named wp-config-sample.php, and open it in your favorite text editor. We have to configure a few settings. The default values for MAMP installations make this really easy to fill out, so follow the table below to see what to type where:

Variable Value
DB_NAME wordpress
DB_USER root
DB_PASSWORD root

Editing Variables
Change the values of the variables to match the table above.

You should not need to alter anything else in this file, at least for now. You could add in the unique keys and salts, but I recommend doing that once you move the website into production.

Save and close wp-config-sample.php. We’re nearly done. Rename this file to wp-config.php — removing the -sample — and we are ready to complete the installation. You should now be able to point your browser to http://localhost:8888/wordpress and see the WordPress installation screen. Enter in your basic data and install the app. You are now ready to log into the admin section and get going!

WordPress Install Screen
Enter your information… but choose a stronger password.

Permalinks

Always follow WordPress’ permalink structure. In order for you to get these “pretty URLs,� Apache will need mod_rewrite to update your .htaccess file, so let’s make sure that is set up.

The file we have to edit is httpd.conf, and you can find it in Applications → MAMP → conf → apache → /. Open this file, and search for a line like this:

LoadModule rewrite_module modules/mod_rewrite.so

Note that a hash (#) may or may not be in front of it. The hash indicates a comment, and if you see it, you must remove it to allow the mod_rewrite module to load. If the line is not commented out, then congratulations: you are already done! Close the file, and permalinks should now work in your local installation.

The Final Countdown

By now, a local server set up with WordPress should be installed and running. The remaining steps are both short and crucial to sharing your creation with the Internet. All that remains is to transfer your local accomplishments to a global environment by moving both our WordPress files and our content. So, let’s finish this up!

Going Live

The time has finally arrived. So, how do you bring your WordPress creation to the live server? Well, we have two options.

Just Grab the Content

A sometimes simpler way, with only a few steps, is to just grab all of your content. This is easiest if WordPress is already installed and you just need to import your theme and content. To do this, head to the admin dashboard, to the “Tools� section in the sidebar. Click on “Export,� and choose “All content.� This will export a file that you can then import into your new installation.

WordPress Content Export
Exporting WordPress content.

You can now upload your WordPress theme files to the live location. Head to the “Tools� section of the dashboard again, and choose “Import.� Simply point to the file that you just exported, and bring in your content.

Bringing In Everything

I use this method if I have done everything locally from the ground up. I’ll upload my entire local WordPress directory (in this case, http://localhost:8888/wordpress) to the live server and then grab the database file and transfer that from local to live as well.

Because you could certainly build nearly the entire website in your development environment, bear in mind that WordPress uses absolute paths for URLs. So, every image and link will be prepended with http://localhost:8888/ (depending on your set-up). We need a way to alter this to fit the live website. We have a few options.

1. Export, Search and Replace

Using this method, we export our local database as a text file and run a “Find and replace� on the text to replace all occurrences of the localhost URL with the production URL.

WordPress Database Export
Exporting the WordPress database (click image for full-size view).

Begin by opening phpMyAdmin and clicking on your WordPress database on the left. Click on the “Export� tab in the top menu, and be sure to choose “Select all� when choosing which tables to export. At the bottom, check the box to “Save as file,� and then hit “Go.� Open the resulting file in your favorite text editor, and simply run a “Find and replace� to replace all instances of http://localhost:8888/wordpress with http://www.YOUR_SITE_URL.com.

Save the edited file, and visit phpMyAdmin on your live server. Again, click on your WordPress database, and this time choose the “Import� option from the top menu, and browse for your newly edited file. Once it successfully imports, upload your WordPress directory to the live server. If WordPress is already installed, simply upload your theme, any plug-ins you have installed locally and the contents of your wp-content/uploads folder; or else, upload the entire local directory to your live website’s root. Once that’s uploaded, be sure you can log into wp-admin, and browse around to make sure everything made it in. Update your permalink’s structure to something friendlier, and you are off!

2. Using SQL Queries

A second way to alter URL paths is to first bring everything into the live server version, and then use a few SQL queries to find and replace the necessary strings. Open phpMyAdmin on your local server, and export the database, again making sure to select all tables and to save it as a file. Go to your live server, and import the .sql file that you just saved. In the top menu, click on the tab for “SQL,â€� whereupon you will see a text area. You will need to enter some query syntax; be sure to replace the URLs in these code fragments with the ones that pertain to your set-up — namely, the localhost’s path and the URL of your new live website.

SQL Query Screen
Running SQL queries to update the URL paths (click image for full-size view).

Replacing WordPress’ base URL path:

UPDATE wp_options SET option_value = replace(option_value, 'http://localhost:8888/wordpress', 'http://www.YOUR_SITE_URL.com') WHERE option_name = 'home' OR option_name = 'siteurl';

Update the GUID that controls WordPress’ translating paths and post locations:

UPDATE wp_posts SET guid = REPLACE (guid, 'http://localhost:8888/wordpress', 'http://www.YOUR_SITE_URL.com');

Update the URL paths in the content:

UPDATE wp_posts SET post_content = REPLACE (post_content, 'http://localhost:8888/wordpress', 'http://www.YOUR_SITE_URL.com');

Update the URLs in the meta data of posts, such as attachments:

UPDATE wp_postmeta SET meta_value = REPLACE (meta_value, 'http://localhost:8888/wordpress','http://www.YOUR_SITE_URL.com');

Final Thoughts

We have managed to install MAMP to set up a local server sandbox to develop in, and we’ve configured and installed a WordPress platform to develop in, saving the need for purely online development tactics.

I hope this has given you some insight into setting up a local environment to work with WordPress. Keep in mind that this is just scratching the surface; WordPress is versatile. Now that we have this faster new way to develop, the next time we’ll get into some custom WordPress configurations.

Helpful Links

You may be interested in these related resources:

(al)


© Ryan Olson for Smashing Magazine, 2011.


You’re Pricing It Wrong: Software Pricing Demystified





 



 


Pricing your own product is always a tricky proposition, and the more critical the price is to your product’s success, the more difficult it is to set. It’s easy to look at another product and say how much you would be willing to pay for it, but how can you know how much people would be willing to pay for yours?

There are no absolute truths or perfect formulas for finding the best price, assuming that the “best price� even exists. Instead, take a structured approach to finding a good starting point, and improve it through feedback and testing. But first, you need to understand what the best price actually is.

Riding the Demand Curve

When we price a product, our goal (assuming we’re running a business) is to maximize revenue. We want sales × price = highest possible value.

Economic theory suggests that as we raise the price, the number of sales will drop. Each intersection of price and number of sales can be plotted on a graph, creating what is called a demand curve.

The sweet point is where the intersection forms the largest rectangle. This rectangle represents the calculation of sales × price, and the biggest rectangle represents the biggest revenue.

This makes sense… until you consider that your clients are people, and people do not often make rational purchasing decisions. In his excellent eBook Don’t Just Roll the Dice, Neil Davidson says (emphasis is mine):

Once you’ve determined what your product is, you need to consider its value to your customers. In the case of the Time Tracker 3000, let’s say that it will save a particular customer, Willhelm, three hours of work and that Willhelm prices his time at $50 an hour. That means that Willhelm should buy the Time Tracker 3000 at any price under $150, assuming he has nothing better to spend his money on.

Of course, this assumes that Willhelm is the rational, decision-making machine that economists love. In fact, Willhelm is a flesh-and-blood, irrational human being who doesn’t price his time and calculate costs and benefits. He has a perceived value of the Time Tracker 3000, which may or may not be linked to its objective value.

Neil goes into much more detail than I can in this article, but to recap quickly: perceived value can be different than objective value, and it can affect sales in ways that the demand curve does not predict. For example, when buying a brand-name product, you are intentionally paying a premium because the perceived value is higher, even if the objective value is the same. Some brands purposely price higher in order to increase the perceived value and thus sell more.

Pricing Higher And Selling More

Taking the fictional issue tracker in Neil’s book:

Back to Willhelm and the Time Tracker 3000. If you want to change how much Willhelm will pay for your product, then changing the product is one option, but only if you can also change his perception too. In fact, it turns out that you can change Willhelm’s perception of your product’s worth without touching the product at all. That’s one of the things marketing is for.

That’s right. You can set a higher price without changing your product just by changing the potential customer’s perception of the product. For example, you could increase perceived value by writing better marketing copy (focusing on the value that you’re providing or the pain that you’re solving). A killer demo can do wonders, as can strong testimonials and well-known partners.

One of the best ways to increase perceived value is to have better visual design — which, not surprisingly, is one the weakest links in marketing for most software developers. A well-known fruit company has become a giant by out-designing its competition, and it’s no coincidence: Apple charges a premium because of the perceived value of its products.

One common way to identify perceived value is to check the competition. Are you selling a WordPress plug-in for newsletter management? Google the keywords to see what else is on the market. If you’re in luck, you’ll be providing the only solution in this space. If not, you’ll have to consider that your clients can use Google just as well as you can and thus take your competitors’ pricing into account.

What do you do if a free product does what your product does? In this case, you have four options:

  1. Demonstrate that your product either is clearly superior or has features unique to it;
  2. Work on creating such differentiators;
  3. Win on marketing;
  4. Provide support.

Providing support is an important differentiator; one of people’s biggest deterrents from using a lesser-known free or cheap product is their concern about ongoing problems and future needs. A commercial product that comes with support will often win over customers who want that assurance that someone will be on the other end of the line should they need it.

Providing support has another benefit in addition to increasing the value of the product: it’s a chance to get real feedback! The feedback you get from support requests will enable you to improve the product and thus sell more (or increase the price) in the future.

A Real-World Example

The start-up that I co-founded, Binpress, is a marketplace for source-code components. One of our components, an import and export rules module for Magento, started out priced very low: $4.99 for a basic license, which is actually the minimum price that we allow.

We noticed that it was getting good traction and that people were looking for this particular functionality and that no good alternatives existed. We suggested to the developer that he raise the price. And he did, in stages:

  • At first, he raised the price to $9.99, which did not affect sales (i.e. the conversion rate stayed the same);
  • He then raised the price to $14.99 — again, the rate of sales remained the same;
  • The price is now $19.99, and sales are slowing down somewhat.

So, the optimized point lies somewhere between $14.99 and $19.99 — more than three times the original price! That is, the developer will generate over three times the revenue simply by optimizing the price and not actually changing the product. Without having tested different points, the developer would still be stuck at $4.99.


The prices should attract your customers, not drive them away. Image Source

Pricing A New Product

So far, I’ve talked about perceived and objective value and maximizing the demand curve. But what about the initial price tag?

When you go about pricing a product, run through the following exercise.

1. Determine the Product’s Objective Value

How much would people pay if they were indeed rational decision-making machines. With software, the calculation can be as simple as:

(Hourly rate × Development time in hours) − Price = Value

This simple calculation would determine the product’s value if the customer were making a completely logical decision. (Of course, this will vary depending on the hourly rate of the developer and their experience, which will affect development time. But those two numbers are usually related.)

2. Understand the Product’s Perceived Value

Who is your target audience? How will the product help them? (Will it save them time, improve their business, etc.?) Who will ultimately be making the decision to buy your product? (A developer? A project manager? The dude holding the company’s credit card?)

To answer these questions, research your market. What are the competing products? What is the demand? Who needs this solution, and how unique is it? How hard would it be to develop the product from scratch?

The Programmers section of StackExchange has a good overview of these considerations. Unless your circumstances are highly unusual, you can find answers to these questions relatively easily by using Google and by visiting relevant community-powered forums and Q&A websites such as StackExchange.

3. What Value Do I Want to Convey Though the Price?

A product priced at $1.99 sends a very different message to potential customers than one priced at $19.99 — the difference in conveyed value is by an order of magnitude. Don’t lower the price early on merely to try to generate more sales, because you would be conveying to customers that the product is worthless.

After determining the perceived value of the product and deriving a price from that, we can try to optimize the price in several ways…

1. Improve Perceived Value With Marketing

I’ve already covered several factors related to marketing, such as copy, visual design and demos, and I might expand on others in a future post. Consider these elements when trying to increase perceived value. If we find that the perceived value is below our objective value, then we can almost certainly raise it to at least the objective value. And with creative marketing, we could probably go far past that.

2. Improve Objective Value

To quote Joel Spolsky in his excellent article on Simplicity (bolding is mine):

With six years of experience running my own software company I can tell you that nothing we have ever done at Fog Creek has increased our revenue more than releasing a new version with more features. Nothing. The flow to our bottom line from new versions with new features is absolutely undeniable. It’s like gravity. When we tried Google ads, when we implemented various affiliate schemes, or when an article about FogBugz appears in the press, we could barely see the effect on the bottom line. When a new version comes out with new features, we see a sudden, undeniable, substantial, and permanent increase in revenue.

Going back to the point I made earlier, you can price higher through differentiation if you understand what people need and then exploit weaknesses in the competition. Everybody uses Magento because it delivers a lot of value, but customers keep complaining about its speed, among other things. Suppose you built a similar e-commerce platform that is blazingly fast? Bingo! You’ve targeted the biggest pain point for your competitor’s clients. Sometimes, having competition is helpful just to know what people really need.

3. Testing

When all is said and done, determining the ideal price from the get go is hard. You’ll need to test several prices and plot the demand curve of your product to find that sweet spot.

4. Tiered Pricing

This is critical from a psychological point of view. By setting just one price for your product, you don’t provide any points of reference (except those of your competition). You can increase the perceived value of your regular price by adding a premium package that is priced much higher. The point of the premium package is not to generate revenue (although it will do that — always give people the option to pay more if they want to), but rather to make the regular price seem like a better deal.

Basecamp pricing options

Start With A Good Guess And Then Optimize

By now, you should have the basic process down for how to price your product. There are no absolute truths in pricing: it’s best to start from a good guess and then test as much as possible. This article is meant to lay out the process to make that initial guess and the considerations that go into it.

There could be any number of reasons why a product is not selling as well as it should, aside from pricing. Always try to get feedback from potential customers (i.e. your website’s visitors) using tools such as KISSinsights, Total Feedback and even a simple contact form. The reasons could be a lack of information, missing features or simply a broken purchasing link.

What experience do you have in pricing software? I would love to hear about it and any questions you have in the comments!

Related Articles

You might be interested in the following related articles:

Front Cover: Image Source.

(al)


© Eran Galperin for Smashing Magazine, 2011.


Searchable Dynamic Content With AJAX Crawling





 



 


Google Search likes simple, easy-to-crawl websites. You like dynamic websites that show off your work and that really pop. But search engines can’t run your JavaScript. That cool AJAX routine that loads your content is hurting your SEO.

Google’s robots parse HTML with ease; they can pull apart Word documents, PDFs and even images from the far corners of your website. But as far as they’re concerned, AJAX content is invisible.

The Problem With AJAX

AJAX has revolutionized the Web, but it has also hidden its content. If you have a Twitter account, try viewing the source of your profile page. There are no tweets there — just code! Almost everything on a Twitter page is built dynamically through JavaScript, and the crawlers can’t see any of it. That’s why Google developed AJAX crawling.

Because Google can’t get dynamic content from HTML, you will need to provide it another way. But there are two big problems: Google won’t run your JavaScript, and it doesn’t trust you.

Google indexes the entire Web, but it doesn’t run JavaScript. Modern websites are little applications that run in the browser, but running those applications as they index is just too slow for Google and everyone else.

The trust problem is trickier. Every website wants to come out first in search results; your website competes with everyone else’s for the top position. Google can’t just give you an API to return your content because some websites use dirty tricks like cloaking to try to rank higher. Search engines can’t trust that you’ll do the right thing.

Google needs a way to let you serve AJAX content to browsers while serving simple HTML to crawlers. In other words, you need the same content in multiple formats.

Two URLs For The Same Content

Let’s start with a simple example. I’m part of an open-source project called Spiffy UI. It’s a Google Web Toolkit (GWT) framework for REST and rapid development. We wanted to show off our framework, so we made SpiffyUI.org using GWT.

GWT is a dynamic framework that puts all of our content in JavaScript. Our index.html file looks like this:

<body>
   <script type="text/javascript" language="javascript"
   src="org.spiffyui.spsample.index.nocache.js"></script>
</body>

Everything is added to the page with JavaScript, and we control our content with hash tags (I’ll explain why a little later). Every time you move to another page in our application, you get a new hash tag. Click on the “CSS� link and you’ll end up here:

http://www.spiffyui.org#css

The URL in the address bar will look like this in most browsers:

http://www.spiffyui.org/?css

We’ve fixed it up with HTML5. I’ll show you how later in this article.

This simple hash works well for our application and makes it bookmarkable, but it isn’t crawlable. Google doesn’t know what a hash tag means or how to get the content from it, but it does provide an alternate method for a website to return content. So, we let Google know that our hash is really JavaScript code instead of just an anchor on the page by adding an exclamation point (a “bang�), like this:

http://www.spiffyui.org#!css

This hash bang is the secret sauce in the whole AJAX crawling scheme. When Google sees these two characters together, it knows that more content is hidden by JavaScript. It gives us a chance to return the full content by making a second request to a special URL:

http://www.spiffyui.org?_escaped_fragment_=css

The new URL has replaced the #! with ?_escaped_fragment_=. Using a URL parameter instead of a hash tag is important, because parameters are sent to the server, whereas hash tags are available only to the browser.

That new URL lets us return the same content in HTML format when Google’s crawler requests it. Confused? Let’s look at how it works, step by step.

Snippets Of HTML

The whole page is rendered in JavaScript. We needed to get that content into HTML so that it is accessible to Google. The first step was to separate SpiffyUI.org into snippets of HTML.

Google still thinks of a website as a set of pages, so we needed to serve our content that way. This was pretty easy with our application, because we have a set of pages, and each one is a separate logical section. The first step was to make the pages bookmarkable.

Bookmarking

Most of the time, JavaScript just changes something within the page: when you click that button or pop up that panel, the URL of the page does not change. That’s fine for simple pages, but when you’re serving content through JavaScript, you want give users unique URLs so that they can bookmark certain areas of your application.

JavaScript applications can change the URL of the current page, so they usually support bookmarking via the addition of hash tags. Hash tags work better than any other URL mechanism because they’re not sent to the server; they’re the only part of the URL that can be changed without having to refresh the page.

The hash tag is essentially a value that makes sense in the context of your application. Choose a tag that is logical for the area of your application that it represents, and add it to the hash like this:

http://www.spiffyui.org#css

When a user accesses this URL again, we use JavaScript to read the hash tag and send the user to the page that contains the CSS.

You can choose anything you want for your hash tag, but try to keep it readable, because users will be looking at it. We give our hashes tags like css, rest and security.

Because you can name the hash tag anything you want, adding the extra bang for Google is easy. Just slide it between the hash and the tag, like this:

http://www.spiffyui.org#!css

You can manage all of your hash tags manually, but most JavaScript history frameworks will do it for you. All of the plug-ins that support HTML4 use hash tags, and many of them have options for making URLs bookmarkable. We use History.js by Ben Lupton. It’s easy to use, it’s open source, and it has excellent support for HTML5 history integration. We’ll talk more about that shortly.

Serving Up Snippets

The hash tag makes an application bookmarkable, and the bang makes it crawlable. Now Google can ask for special escaped-fragment URLs like so:

screenshot

When the crawler accesses our ugly URL, we need to return simple HTML. We can’t handle that in JavaScript because the crawler doesn’t run JavaScript in the crawler. So, it all has to come from the server.

You can implement your server in PHP, Ruby or any other language, as long as it delivers HTML. SpiffyUI.org is a Java application, so we deliver our content with a Java servlet.

The escaped fragment tells us what to serve, and the servlet gives us a place to serve it from. Now we need the actual content.

Getting the content to serve is tricky. Most applications mix the content in with the code; but we don’t want to parse the readable text out of the JavaScript. Luckily, Spiffy UI has an HTML-templating mechanism. The templates are embedded in the JavaScript but also included on the server. When the escaped fragment looks for the ID css, we just have to serve CSSPanel.html.

The template without any styling looks very plain, but Google just needs the content. Users see our page with all of the styles and dynamic features:

screenshot

Google gets only the unstyled version:

screenshot

You can see all of the source code for our SiteMapServlet.java servlet. This servlet is mostly just a look-up table that takes an ID and serves the associated content from somewhere on our server. It’s called SiteMapServlet.java because this class also handles the generation of our site map.

Tying It All Together With A Site Map

Our site map tells the crawler what’s available in our application. Every website should have a site map; AJAX crawling doesn’t work without one.

Site maps are simple XML documents that list the URLs in an application. They can also include data about the priority and update frequency of the app’s pages. Normal entries for site maps look like this:

<url>
   <loc>http://www.spiffyui.org/</loc>
   <lastmod>2011-07-26</lastmod>
   <changefreq>daily</changefreq>
   <priority>1.0</priority>
</url>

Our AJAX-crawlable entries look like this:

<url>
   <loc>http://www.spiffyui.org/#!css</loc>
   <lastmod>2011-07-26</lastmod>
   <changefreq>daily</changefreq>
   <priority>0.8</priority>
</url>

The hash bang tells Google that this is an escaped fragment, and the rest works like any other page. You can mix and match AJAX URLs and regular URLs, and you can use only one site map for everything.

You could write your site map by hand, but there are tools that will save you a lot of time. The key is to format the site map well and submit it to Google Webmaster Tools.

Google Webmaster Tools

Google Webmaster Tools gives you the chance to tell Google about your website. Log in with your Google ID, or create a new account, and then verify your website.

screenshot

Once you’ve verified, you can submit your site map and then Google will start indexing your URLs.

And then you wait. This part is maddening. It took about two weeks for SpiffyUI.org to show up properly in Google Search. I posted to the help forums half a dozen times, thinking it was broken.

There’s no easy way to make sure everything is working, but there are a few tools to help you see what’s going on. The best one is Fetch as Googlebot, which shows you exactly what Google sees when it crawls your website. You can access it in your dashboard in Google Webmaster Tools under “Diagnostics.�

screenshot

Enter a hash bang URL from your website, and click “Fetch.� Google will tell you whether the fetch has succeeded and, if it has, will show you the content it sees.

screenshot

If Fetch as Googlebot works as expected, then you’re returning the escaped URLs correctly. But you should check a few more things:

  • Validate your site map.
  • Manually try the URLs in your site map. Make sure to try the hash-bang and escaped versions.
  • Check the Google result for your website by searching for site:www.yoursite.com.

Making Pretty URLs With HTML5

Twitter leaves the hash bang visible in its URLs, like this:

http://twitter.com/#!/ZackGrossbart

This works well for AJAX crawling, but again, it’s slightly ugly. You can make your URLs prettier by integrating HTML5 history.

Spiffy UI uses HTML5 history integration to turn a hash-bang URL like this…

http://www.spiffyui.org#!css

… into a pretty URL like this:

http://www.spiffyui.org?css

HTML5 history makes it possible to change this URL parameter, because the hash tag is the only part of the URL that you can change in HTML4. If you change anything else, the entire page reloads. HTML5 history changes the entire URL without refreshing the page, and we can make the URL look any way we want.

This nicer URL works in our application, but we still list the hash-bang version on our site map. And when browsers access the hash-bang URL, we change it to the nicer one with a little JavaScript.

Cloaking

Earlier, I mentioned cloaking. It is the practice of trying to boost a website’s ranking in search results by showing one set of pages to Google and another to regular browsers. Google doesn’t like cloaking and may remove offending websites from its search index.

AJAX-crawling applications always show different results to Google than to regular browsers, but it isn’t cloaking if the HTML snippets contain the same content that the user would see in the browser. The real mystery is how Google can tell whether a website is cloaking or not; crawlers can’t compare content programmatically because they don’t run JavaScript. It’s all part of Google’s Googley power.

Regardless of how it’s detected, cloaking is a bad idea. You might not get caught, but if you do, you’ll be removed from the search index.

Hash Bang Is A Little Ugly, But It Works

I’m an engineer, and my first response to this scheme is “Yuck!� It just feels wrong; we’re warping the purpose of URLs and relying on magic strings. But I understand where Google is coming from; the problem is extremely difficult. Search engines need to get useful information from inherently untrustworthy sources: us.

Hash bangs shouldn’t replace every URL on the Web. Some websites have had serious problems with hash-bang URLs because they rely on JavaScript to serve content. Simple pages don’t need hash bangs, but AJAX pages do. The URLs do look a bit ugly, but you can fix that with HTML5.

Further Reading

We’ve covered a lot in this article. Supporting AJAX crawling means that you need to change your client’s code and your server’s code. Here are some links to find out more:

Thanks to Kristen Riley for help with some of the images in this article.

(al)


© Zack Grossbart for Smashing Magazine, 2011.


Content Prototyping In Responsive Web Design





 



 


You might be interested in further articles and resources related to this article.

Michelangelo once said,

The best of artists has no conception that the marble alone does not contain within itself.

Translate this to the world of Web design and you might say,

No matter how great a designer you are, you’re only as good as your content.

While the reality of client work sometimes makes it challenging to gather and produce content prior to starting the design, this is now widely accepted as being necessary. You may have heard this referred to as “content-driven design.� I’m not the first to suggest that our current approach to responsive Web design could be improved by imparting a bigger role to content in determining how our websites respond. However, I haven’t seen many (if not any) practical explanations on how to do this. I’d like to start this conversation by introducing a theoretical concept called a “content prototype.�

What Is A Content Prototype?

A content prototype is an HTML-and-CSS-based fluid-grid prototype, consisting of layout and typography, that consists of the project’s actual content. Its greatest usefulness may be in determining where to apply media queries to make the Web design responsive.

For centuries, we have shaped our layouts and typefaces according to the meaning of the content. This has traditionally been done on fixed-width pages. We have inherited a fixed-width mentality in designing for the Web, when in fact the Web is not fixed-width. Users come to our websites for content. We should strive to present this content in the most appropriate and readable way possible.

Let’s Get Theoretical

The following is a theoretical walk-through of how one might use a content prototype in real life. Again, this is intended to begin a conversation on how we can marry the concepts underlying content-driven design and those of responsive Web design.

Imagine that you are about to begin designing a website. The website will consist of a single page, which contains a block of text and a few short excerpts of related text. You’ve done your homework, and the content is fully written. You have solid documents of the architecture and wireframe that establish the priorities for this page. You also know that the website will be responsive. You’ve opened up your design tool of choice, and you’re now looking at the “File → New� dialog. What to enter in those pesky little “width� and “height� fields?

Photoshop’s new file dialog box
Photoshop’s new file dialog box.

Perhaps it doesn’t matter.

Consider this. The goal of this process is to create a website that begs to be read at any resolution. So, start at whatever resolution you’d like, whatever you’re comfortable with. Every resolution is important, not just the resolutions that last month’s analytics say are the most popular.

Because we’re following the principles of content-driven design, start with the highest-priority content on the page (the real content). Don’t worry about anything other than the typeface, font size, column width and layout. Make it a pleasure to read. This is about as basic as you can get, because you haven’t yet created icons, textures or illustrations; those elements are important, but they should support the content, and you can work on them later.

Next, code the simple page that you’ve designed using a fluid grid. This is critical; when your browser’s window is about the same width as the canvas that you started with, the content prototype should look very much the same. This gives you the chance to play with the prototype in a browser and make informed decisions about where your media queries should fire. Using this method, the content will dictate where your fluid grid breaks down. These breakages are where you should apply media queries; they are opportunities for more dramatic changes. Make these changes, always focusing on the legibility of the content.

Following this pattern, you would add media queries at points where the fluid grid falls apart. Soon, you will have a full spectrum of resolutions, with beautiful and appropriate reading experiences. Once this is done, you will have a finished content prototype that demonstrates the readability of your content outside of the context of any device-specific resolutions.

Benefits Of A Content Prototype

Thinking this way about the process of responsive Web design makes the content a filter through which all other decisions are made. The goal is to add a degree of cohesion between the message and the design of the website that would be difficult to achieve without such an approach.

Another challenge with responsive Web design is in testing usability across all resolutions. A round of usability testing with a completed content prototype could quite possibly give an early glimpse of problems with changes to the layout. The sooner you can identify these problems, the lower the cost of fixing them.

Additionally, content prototypes give you an opportunity to show that layout changes are possible before spending days designing every detail. The iterative nature of content prototyping invites collaboration between designer and coder — even if they happen to be the same person.

Design In The Browser

If you are one of those designers who also codes, then you’ve probably recognized that this can all happen right in the browser. If you have the skills to do both, then by all means, start in the browser. With the emergence of CSS3 features like border-radius, text-shadow and gradient, designing in the browser is more feasible today than ever before.

We’re all frustrated with our tools. Perhaps this is because they are all fixed-width tools! But regardless of whether we have the right tools for the job, we cannot continue to rely on common device-specific resolutions if we want to build websites that work well into the future. A content prototype gets our content into the browser as early as possible.

Problems With Content Prototypes

Obviously, this approach does have some limitations. Foremost, not every website is content-driven; many websites are workflow-driven. Without getting sidetracked by the whole question of what content is, we can recognize that this process wouldn’t necessarily work if you don’t have the content first.

Also, if you’re a designer who is not also a front-end developer, then a lot of back and forth will be required to complete the content prototype. This is not necessarily bad, but it will certainly take time.

Then there is the problem of what to do once you have a completed the content prototype. You could continue designing and adding to the code that you have. But if you do choose this route, then you will need to start with the smallest resolution first, because this is the best practice for coding a responsive website.

Alternatively, you could use this process merely to determine where your media queries should fall. In this case, this would be a lot of work just to find the proper breaks in the content’s readability.

Alternative Approaches

There are other ways to make these decisions. Using traffic data, some people might build a graph to determine the breaking points in their design.

Breaking point graph
Using traffic data to determine where to apply media queries.

Ethan Marcotte describes a similar process in his book Responsive Web Design, but he also suggests resolutions that are common among popular devices these days. Also, coding a responsive website that has already been fully designed could cause problems if you’re not sure whether the layout can be achieved with CSS alone. As mentioned, content prototyping lets you experiment with these layouts before fully committing to a change for a given resolution.

The point of all this is to make our content more readable, independent of what device it’s being viewed on. If content prototyping doesn’t work, maybe we could find some way — other than relying on which devices are currently popular — to make content-driven decisions about the design and layout. The guys at Front have been experimenting with this as well, calling it “The Goldilocks Approach to Responsive Design.� Their technique is to use an em-based layout (instead of the typical fluid-grid approach of percentage widths) to create a great reading experience at all resolutions.

A Helpful Tool

One of the developers on our team recently created a media query bookmarklet, which displays in real time your browser’s width and height and any media queries that have been triggered. This tool can be very helpful when doing responsive Web design. Feel free to experiment with it; I hope it simplifies the process for you as it has for us.

Building For The Future

The aim is lofty, designing for the future. Just as we build websites to be accessible to the widest audience possible — because that is the right way to build them — we should build websites that embrace the fluidity of the Web. A challenge is before us to find ways to present our content appropriately without knowing which devices it will be viewed on. We must shift our focus back to the user. A content-out approach is a user-centered approach.

It won’t be long before we’re interacting with the Web in ways we never imagined. We may be near a time when fixed-width websites are considered outdated. Whether or not that happens, our websites should be flexible enough to present readable content to all of our users. Moreover, assuming what a user with a small screen wants from your website can be dangerous. Mobile-specific websites are certainly appropriate at times, but there are a few reasons why a website should not (at a minimum) be built responsively.

In order to get better at what we do, we must keep pushing the process forward. If you have other ideas on how to separate our decisions about a website’s design from popular device resolutions, or even knowledge of the benefits or problems of content prototyping, please share.

Further Resources

You might be interested in further articles and resources related to this article.

(al)


© Ben Callahan for Smashing Magazine, 2011.


Create An Animated Bar Graph With HTML, CSS And jQuery





 



 


People in boardrooms across the world love a good graph. They go nuts for PowerPoint, bullet points and phrases like “run it up the flagpole,� “blue-sky thinking� and “low-hanging fruit,� and everything is always “moving forward.� Backwards is not an option for people who facilitate paradigm shifts in the zeitgeist. Graphs of financial projections, quarterly sales figures and market saturation are a middle-manager’s dream.

screenshot

How can we as Web designers get in on all of this hot graph action? There are actually quite a few ways to display graphs on the Web. We could simply create an image and nail it to a Web page. But that’s not very accessible or interesting. We could use Flash, which is quite good for displaying graphs — but again, not very accessible. Besides, designers, developers and deities are falling out of love with Flash. Technologies such as HTML5 can do many of the same things without the need for a plug-in. The new HTML5 <canvas> element could even be adapted to the task. Plenty of charting tools are online that we might use. But what if we wanted something a little more tailored?

There are pros and cons to the wide range of resources available to us, but this tutorial will not explore them all. Instead, we’ll create our graph using a progressively enhanced sprinkling of CSS3 and jQuery. Because we can.

What Are We Making?

We’re making this. And more! Here are some possibilities on how you can extend the techniques explored in this tutorial:

  • A progress bar that indicates how long until the end of all humanity in the event of a zombie plague;
  • A graph indicating the decline in safe outdoor activities during a zombie plague;
  • A frighteningly similar graph indicating the decline in manners during a zombie plague;
  • The increase of people who were unaware of the zombie plague because they were sharing with all of their now-deceased friends on Facebook what they did on FarmVille.

Or you could create a graph or quota bar that simply illustrates something useful and less full of dread and zombies. So, let’s get on with it.

What You’ll Need

  • A text or HTML editor. Take your pick; many are out there.
  • jQuery. Practice safe scripting and get the latest one. Keep the jQuery website open so that you can look up the documentation as you go.
  • Possibly an image editor, such as Paint, to mock up what your graph might look like.
  • A modern and decent Web browser to preview changes.

That should do it. Please note that this tutorial is not designed as an introduction to either HTML, CSS, jQuery or zombies. Some intermediate knowledge of these three technologies and the undead is assumed.

The Mark-Up

You can create the underlying HTML for a graph in a number of ways. In this tutorial, we’ll start with a table, because it will make the most sense visually if JavaScript or CSS is not applied. That’s a big checkmark in the column for accessibility.

Quick! You’ve just been given some alarming figures. The population of tanned zombies is projected to spiral out of control in the next few years. The carbon tigers and blue monkeys are under immediate threat. Then the tanned zombies will probably come for us. But you’re just a designer. What could you possibly do to help?

I know! You could make a Web page that illustrates our imminent demise with nice, calming, smoothly animated graphics!

To begin, let’s put this data into a table, with columns for each year, and rows for the different species.

<!doctype html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=1024">
      <title>Example 01: No CSS</title>
   </head>

   <body>
      <div id="wrapper">
         <div class="chart">
            <h3>Population of endangered species from 2012 to 2016</h3>
            <table id="data-table" border="1" cellpadding="10" cellspacing="0"
            summary="The effects of the zombie outbreak on the populations
            of endangered species from 2012 to 2016">
               <caption>Population in thousands</caption>
               <thead>
                  <tr>
                     <td>&nbsp;</td>
                     <th scope="col">2012</th>
                     <th scope="col">2013</th>
                     <th scope="col">2014</th>
                     <th scope="col">2015</th>
                     <th scope="col">2016</th>
                  </tr>
               </thead>
               <tbody>
                  <tr>
                     <th scope="row">Carbon Tiger</th>
                     <td>4080</td>
                     <td>6080</td>
                     <td>6240</td>
                     <td>3520</td>
                     <td>2240</td>
                  </tr>
                  <tr>
                     <th scope="row">Blue Monkey</th>
                     <td>5680</td>
                     <td>6880</td>
                     <td>6240</td>
                     <td>5120</td>
                     <td>2640</td>
                  </tr>
                  <tr>
                     <th scope="row">Tanned Zombie</th>
                     <td>1040</td>
                     <td>1760</td>
                     <td>2880</td>
                     <td>4720</td>
                     <td>7520</td>
                  </tr>
               </tbody>
            </table>
         </div>
      </div>
   </body>
</html>

View the example below to see how it looks naked, with no CSS or JavaScript applied. The accessibility of this table will enable people using screen readers to understand the data and the underlying message, which is “Run for your life! The zombies are coming!�

screenshot

The easy part is now out of the way. Now, let’s tap into the power of CSS and JavasScript (via jQuery) to really illustrate what the numbers are telling us. Technically, our aim is to create a graph that works in all modern browsers, from IE 8 on.

Did I say all modern browsers? IE 8 is lucky: it gets to hang out with the cool kids. Browsers that support CSS3 will get a few extra sprinkles.

“By Your Powers Combined…�

If you wish to summon Captain Planet, you may have to look elsewhere. If you want to learn how to combine CSS and jQuery to create a graph that illustrates our impending doom at the hands of a growing army of zombies who prefer bronzer over brains, then read on.

The first thing to do is style our table with some basic CSS. This is a nice safety net for people who haven’t enabled JavaScript in their browser.

screenshot

Getting Started In jQuery

We’ll use jQuery to create our graph on the fly, separate from the original data table. To do this, we need to get the data out of the table and store it in a more usable format. Then, we can add to our document new elements that use this data in order to construct our graph.

Let’s get started by creating our main createGraph() function. I’ve abbreviated some of the inner workings of this function so that you get a clearer picture of the structure. Don’t forget: you can always refer to the source code that comes with this tutorial.

Here’s our basic structure:

// Wait for the DOM to load everything, just to be safe
$(document).ready(function() {

   // Create our graph from the data table and specify a container to put the graph in
   createGraph('#data-table', '.chart');

   // Here be graphs
   function createGraph(data, container) {
      // Declare some common variables and container elements
      …

      // Create the table data object
      var tableData = {
         …
      }

      // Useful variables to access table data
      …

      // Construct the graph
      …

      // Set the individual heights of bars
      function displayGraph(bars) {
         …
      }

      // Reset the graph's settings and prepare for display
      function resetGraph() {
         …
         displayGraph(bars);
      }

      // Helper functions
      …

      // Finally, display the graph via reset function
      resetGraph();
   }
});

We pass two parameters to this function:

  1. The data, in the form of a table element;
  2. A container element, where we’d like to place our graph in the document.

Next up, we’ll declare some variables to manage our data and container elements, plus some timer variables for animation. Here’s the code:

// Declare some common variables and container elements
var bars = [];
var figureContainer = $('<div id="figure"></div>');
var graphContainer = $('<div class="graph"></div>');
var barContainer = $('<div class="bars"></div>');
var data = $(data);
var container = $(container);
var chartData;
var chartYMax;
var columnGroups;

// Timer variables
var barTimer;
var graphTimer;

Nothing too exciting here, but these will be very useful later.

Getting The Data

Besides simply displaying the data, a good bar chart should have a nice big title, clearly labelled axes and a color-coded legend. We’ll need to strip the data out of the table and format it in a way that is more meaningful in a graph. To do that, we’ll create a JavaScript object that stores our data in handy little functions. Let’s give birth to our tableData{} object:

// Create table data object
var tableData = {
   // Get numerical data from table cells
   chartData: function() {
      …
   },
   // Get heading data from table caption
   chartHeading: function() {
      …
   },
   // Get legend data from table body
   chartLegend: function() {
      …
   },
   // Get highest value for y-axis scale
   chartYMax: function() {
      …
   },
   // Get y-axis data from table cells
   yLegend: function() {
      …
   },
   // Get x-axis data from table header
   xLegend: function() {
      …
   },
   // Sort data into groups based on number of columns
   columnGroups: function() {
      …
   }
}

We have several functions here, and they are explained in the code’s comments. Most of them are quite similar, so we don’t need to go through each one. Instead, let’s pick apart one of them, columnGroups:

// Sort data into groups based on number of columns
columnGroups: function() {
   var columnGroups = [];
   // Get number of columns from first row of table body
   var columns = data.find('tbody tr:eq(0) td').length;
   for (var i = 0; i < columns; i++) {
      columnGroups[i] = [];
      data.find('tbody tr').each(function() {
         columnGroups[i].push($(this).find('td').eq(i).text());
      });
   }
   return columnGroups;
}

Here’s how it breaks down:

  • Create the columnGroups[] array to store the data;
  • Get the number of columns by counting the table cells (td) in the first row;
  • For each column, find the number of rows in the table body (tbody), and create another array to store the table cell data;
  • Then loop through each row and grab the data from each table cell (via the jQuery text() function), and then add it to the table cell data array.

Once our object is full of juicy data, we can start creating the elements that make up our graph.

Using The Data

Using the jQuery $.each function, we can now loop through our data at any point and create the elements that make up our graph. One of the trickier bits involves inserting the bars that represent each species inside the yearly columns.

Here’s the code:

// Loop through column groups, adding bars as we go
$.each(columnGroups, function(i) {
   // Create bar group container
   var barGroup = $('<div class="bar-group"></div>');
   // Add bars inside each column
   for (var j = 0, k = columnGroups[i].length; j < k; j++) {
      // Create bar object to store properties (label, height, code, etc.) and add it to array
      // Set the height later in displayGraph() to allow for left-to-right sequential display
      var barObj = {};
      barObj.label = this[j];
      barObj.height = Math.floor(barObj.label / chartYMax * 100) + '%';
      barObj.bar = $('<div class="bar fig' + j + '"><span>' + barObj.label + '</span></div>')
         .appendTo(barGroup);
      bars.push(barObj);
   }
   // Add bar groups to graph
   barGroup.appendTo(barContainer);
});

Excluding the headings, our table has five columns with three rows. For our graph, this means that for each column we create, three bars will appear in that column. The following image shows how our graph will be constructed:

screenshot

Breaking it down:

  • For each column, create a container div;
  • Loop inside each column to get the row and cell data;
  • Create a bar object (barObj{}) to store the properties for each bar, such as its label, height and mark-up;
  • Add the mark-up property to the column, applying a CSS class of '.fig' + j to color code each bar in the column, wrapping the label in a span;
  • Add the object to our bars[] array so that we can access the data later;
  • Piece it all together by adding the columns to a container element.

Bonus points if you noticed that we didn’t set the height of the bars. This is so that we have more control later on over how the bars are displayed.

Now that we have our bars, let’s work on labelling our graph. Because the code to display the labels is quite similar, talking you through all of it won’t be necessary. Here’s how we display the y-axis:

// Add y-axis to graph
var yLegend   = tableData.yLegend();
var yAxisList   = $('<ul class="y-axis"></ul>');
$.each(yLegend, function(i) {
   var listItem = $('<li><span>' + this + '</span></li>')
      .appendTo(yAxisList);
});
yAxisList.appendTo(graphContainer);

This breaks down as follows:

  • Get the relevant table data for our labels,
  • Create an unordered list (ul) to contain our list items;
  • Loop through the label data, and create a list item (li) for each label, wrapping each label in a span;
  • Attach the list item to our list;
  • Finally, attach the list to a container element.

By repeating this technique, we can add the legend, x-axis labels and headings for our graph.

Before we can display our graph, we need to make sure that everything we’ve done is added to our container element.

// Add bars to graph
barContainer.appendTo(graphContainer);      

// Add graph to graph container
graphContainer.appendTo(figureContainer);

// Add graph container to main container
figureContainer.appendTo(container);

Displaying The Data

All that’s left to do in jQuery is set the height of each bar. This is where our earlier work, storing the height property in a bar object, will come in handy.

We’re going to animate our graph sequentially, one by one, uno por uno.

One possible solution is to use a callback function to animate the next bar when the last animation is complete. However, the graph would take too long to animate. Instead, our graph will use a timer function to display each bar after a certain amount of time, regardless of how long each bar takes to grow. Rad!

Here’s the displayGraph() function:

// Set the individual height of bars
function displayGraph(bars, i) {
   // Changed the way we loop because of issues with $.each not resetting properly
   if (i < bars.length) {
      // Animate the height using the jQuery animate() function
      $(bars[i].bar).animate({
         height: bars[i].height
      }, 800);
      // Wait the specified time, then run the displayGraph() function again for the next bar
      barTimer = setTimeout(function() {
         i++;
         displayGraph(bars, i);
      }, 100);
   }
}

What’s that you say? “Why aren’t you using the $.each function like you have everywhere else?� Good question. First, let’s discuss what the displayGraph() function does, then why it is the way it is.

The displayGraph() function accepts two parameters:

  1. The bars to loop through,
  2. An index (i) from which to start iterating (starting at 0).

Let’s break down the rest:

  • If the value of i is less than the number of bars, then keep going;
  • Get the current bar from the array using the value of i;
  • Animate the height property (calculated as a percentage and stored in bars[i].height);
  • Wait 100 milliseconds;
  • Increment i by 1 and repeat the process for the next bar.

“So, why wouldn’t you just use the $.each function with a delay() before the animation?”

You could, and it would work just fine… the first time. But if you tried to reset the animation via the “Reset graph� button, then the timing events wouldn’t clear properly and the bars would animate out of sequence.

I would like to be proven wrong, and if there is a better way to do this, feel free to sound off in the comments section.

Moving on, here’s resetGraph():

// Reset graph settings and prepare for display
function resetGraph() {
   // Stop all animations and set the bar's height to 0
   $.each(bars, function(i) {
      $(bars[i].bar).stop().css('height', 0);
   });

   // Clear timers
   clearTimeout(barTimer);
   clearTimeout(graphTimer);

   // Restart timer
   graphTimer = setTimeout(function() {
      displayGraph(bars, 0);
   }, 200);
}

Let’s break resetGraph() down:

  • Stop all animations, and set the height of each bar back to 0;
  • Clear out the timers so that there are no stray animations;
  • Wait 200 milliseconds;
  • Call displayGraph() to animate the first bar (at index 0).

Finally, call resetGraph() at the bottom of createGraph(), and watch the magic happen as we bask in the glory of our hard work.

Not so fast, sunshine! Before we go any further, we need to put some clothes on.

The CSS

The first thing we need to do is hide the original data table. We could do this in a number of ways, but because our CSS will load well before the JavaScript, let’s do this in the easiest way possible:

#data-table {
   display: none;
}

Done. Let’s create a nice container area to put our graph in. Because a few unordered lists are being used to make our graph, we’ll also reset the styles for those. Giving the #figure and .graph elements a position: relative is important because it will anchor the place elements exactly where we want in those containers.

/* Containers */

#wrapper {
   height: 420px;
   left: 50%;
   margin: -210px 0 0 -270px;
   position: absolute;
   top: 50%;
   width: 540px;
}

#figure {
   height: 380px;
   position: relative;
}

#figure ul {
   list-style: none;
   margin: 0;
   padding: 0;
}

.graph {
   height: 283px;
   position: relative;
}

Now for the legend. We position the legend right down to the bottom of its container (#figure) and line up the items horizontally:

/* Legend */

.legend {
   background: #f0f0f0;
   border-radius: 4px;
   bottom: 0;
   position: absolute;
   text-align: left;
   width: 100%;
}

.legend li {
   display: block;
   float: left;
   height: 20px;
   margin: 0;
   padding: 10px 30px;
   width: 120px;
}

.legend span.icon {
   background-position: 50% 0;
   border-radius: 2px;
   display: block;
   float: left;
   height: 16px;
   margin: 2px 10px 0 0;
   width: 16px;
}

The x-axis is very similar to the legend. We line up the elements horizontally and anchor them to the bottom of its container (.graph):

/* x-axis */

.x-axis {
   bottom: 0;
   color: #555;
   position: absolute;
   text-align: center;
   width: 100%;
}

.x-axis li {
   float: left;
   margin: 0 15px;
   padding: 5px 0;
   width: 76px;
}

The y-axis is a little more involved and requires a couple of tricks. We give it a position: absolute to break it out of the normal flow of content, but anchored to its container. We stretch out each li to the full width of the graph and add a border across the top. This will give us some nice horizontal lines in the background.

Using the power of negative margins, we can offset the numerical labels inside the span so that they shift up and to the left. Lovely!

/* y-axis */

.y-axis {
   color: #555;
   position: absolute;
   text-align: right;
   width: 100%;
}

.y-axis li {
   border-top: 1px solid #ccc;
   display: block;
   height: 62px;
   width: 100%;
}

.y-axis li span {
   display: block;
   margin: -10px 0 0 -60px;
   padding: 0 10px;
   width: 40px;
}

Now for the meat in our endangered species sandwich: the bars themselves. Let’s start with the container element for the bars and the columns:

/* Graph bars */

.bars {
   height: 253px;
   position: absolute;
   width: 100%;
   z-index: 10;
}

.bar-group {
   float: left;
   height: 100%;
   margin: 0 15px;
   position: relative;
   width: 76px;
}

Nothing too complicated here. We’re simply setting some dimensions for the container, and setting a z-index to make sure it appears in front of the y-axis markings.

Now for each individual .bar:

.bar {
   border-radius: 3px 3px 0 0;
   bottom: 0;
   cursor: pointer;
   height: 0;
   position: absolute;
   text-align: center;
   width: 24px;
}

.bar.fig0 {
   left: 0;
}

.bar.fig1 {
   left: 26px;
}

.bar.fig2 {
   left: 52px;
}

The main styles to note here are:

  • position: absolute and bottom: 0, which means that the bars will be attached to the bottom of our graph and grow up;
  • the bar for each species (.fig0, .fig1 and .fig2), which will be positioned within .bar-group.

Now, why don’t we minimize the number of sharp edges on any given page by using the border-radius property to round the edges of the top-left and top-right corners of each bar? OK, so border-radius isn’t really necessary, but it adds a nice touch for browsers that support it. Thankfully, the latest versions of the most popular browsers do support it.

Because we’ve placed the values from each table cell in each bar, we can add a neat little pop-up that appears when you hover over a bar:

.bar span {
   #fefefe url(../images/info-bg.gif) 0 100% repeat-x;
   border-radius: 3px;
   left: -8px;
   display: none;
   margin: 0;
   position: relative;
   text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
   width: 40px;
   z-index: 20;

   -webkit-box-shadow: rgba(0, 0, 0, 0.6) 0 1px 4px;
   box-shadow: rgba(0, 0, 0, 0.6) 0 1px 4px;
}

.bar:hover span {
   display: block;
   margin-top: -25px;
}

First, the pop-up is hidden from view via display: none. Then, when a .bar element is hovered over, we’ve set display: block to bring it into view, and set a negative margin-top to make it appear above each bar.

The text-shadow, rgba and box-shadow properties are currently supported by most modern browsers as is. Of these modern browsers, only Safari requires a vendor prefix (-webkit-) to make box-shadow work. Note that these properties are simply enhancements to our graph and aren’t required to understand it. Our baseline of Internet Explorer 8 simply ignores them.

Our final step in bringing everything together is to color code each bar:

.fig0 {
   background: #747474 url(../images/bar-01-bg.gif) 0 0 repeat-y;
}

.fig1 {
   background: #65c2e8 url(../images/bar-02-bg.gif) 0 0 repeat-y;
}

.fig2 {
   background: #eea151 url(../images/bar-03-bg.gif) 0 0 repeat-y;
}

In this example, I’ve simply added a background-color and a background-image that tiles vertically. This will update the styles for the bars and the little icons that represent them in the legend. Nice.

And, believe it or not, that is it!

The Finished Product

screenshot

That about wraps it up. I hope we’ve done enough to alert the public to the dangers of zombie over-population. More than that, however, I hope you’ve gained something useful from this tutorial and that you’ll continue to push the boundaries of what can be done in the browser — especially with proper Web standards and without the use of third-party plug-ins. If you’ve got ideas on how to extend or improve anything you’ve seen here, don’t hesitate to leave a comment below, or find me on Twitter @derek_mack.

Bonus: Unleashing The Power Of CSS3

This bonus is not as detailed as our main example. It serves mainly as a showcase of some features being considered in the CSS3 specification.

Because support for CSS3 properties is currently limited, so is their use. Although some of the features mentioned here are making their way into other Web browsers, Webkit-based ones such as Apple Safari and Google Chrome are leading the way.

We can actually create our graph using no images at all, and even animate the bars using CSS instead of jQuery.

Let’s start by removing the background images from our bars, replacing them with the -webkit-gradient property:

.fig0 {
   background: -webkit-gradient(linear, left top, right top, color-stop(0.0, #747474), color-stop(0.49, #676767), color-stop(0.5, #505050), color-stop(1.0, #414141));
}

.fig1 {
   background: -webkit-gradient(linear, left top, right top, color-stop(0.0, #65c2e8), color-stop(0.49, #55b3e1), color-stop(0.5, #3ba6dc), color-stop(1.0, #2794d4));
}

.fig2 {
   background: -webkit-gradient(linear, left top, right top, color-stop(0.0, #eea151), color-stop(0.49, #ea8f44), color-stop(0.5, #e67e28), color-stop(1.0, #e06818));
}

We can do the same with our little number pop-ups:

.bar span {
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0.0, #fff), color-stop(1.0, #e5e5e5));
   …
}

For more information on Webkit gradients, check out the Surfin’ Safari blog.

Continuing with the pop-ups, let’s introduce -webkit-transition. CSS transitions are remarkably easy to use and understand. When the browser detects a change in an element’s property (height, width, color, opacity, etc.), it will transition to the new property.

Again, refer to Surfin’ Safari for more information on -webkit-transition and CSS3 animation.

Here’s an example:

.bar span {
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0.0, #fff), color-stop(1.0, #e5e5e5));
   display: block;
   opacity: 0;

   -webkit-transition: all 0.2s ease-out;
}

.bar:hover span {
   opacity: 1;
}

When you hover over the bar, the margin and opacity of the pop-up will change. This triggers a transition event according to the properties we have set. Very cool.

Thanks to -webkit-transition, we can simplify our JavaScript functions a bit:

// Set individual height of bars
function displayGraph(bars, i) {
   // Changed the way we loop because of issues with $.each not resetting properly
   if (i < bars.length) {
      // Add transition properties and set height via CSS
      $(bars[i].bar).css({'height': bars[i].height, '-webkit-transition': 'all 0.8s ease-out'});
      // Wait the specified time, then run the displayGraph() function again for the next bar
      barTimer = setTimeout(function() {
         i++;
         displayGraph(bars, i);
      }, 100);
   }
}
// Reset graph settings and prepare for display
function resetGraph() {
   // Set bar height to 0 and clear all transitions
   $.each(bars, function(i) {
      $(bars[i].bar).stop().css({'height': 0, '-webkit-transition': 'none'});
   });

   // Clear timers
   clearTimeout(barTimer);
   clearTimeout(graphTimer);

   // Restart timer
   graphTimer = setTimeout(function() {
      displayGraph(bars, 0);
   }, 200);
}

Here are the main things we’ve changed:

  • Set the height of the bars via the jQuery css() function, and allowed CSS transitions to take care of the animation;
  • When resetting the graph, turned transitions off so that the height of the bars is instantly set to 0.

Check out the example if you have the latest version of Safari or Chrome installed.

Ultra-Mega Webkit Bonus: Now In 3-D!

For a sneak peek of what the future holds, check out a little experiment that I put together, with a 3-D effect and CSS transforms. Again, it requires the latest versions of Safari or Chrome:

As in our previous Webkit example, there are no images, and all animation is handled via CSS. Kiss my face!

I can’t tell you what to do with all this information. But I do caution you about the potential misuse of your new powers. In the words of our friend Captain Planet, “The power is yours!�

Use it wisely.

(al) (kw) (il)


© Derek Mack for Smashing Magazine, 2011.


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress