InformIT

Improve Your Search Engine Ranking with AJAX

Date: Jul 28, 2006

Return to the article

Navigational elements embedded in your web pages can deteriorate your search engine ranking and reduce the responsiveness of your web site. Ivan Pepelnjak describes how you can use AJAX to solve both problems.

Many well-designed web sites contain significant amounts of navigational information together with the actual content. The HTML markup used for navigation can impact your search engine ranking as well as increase the page download time experienced by your visitors. In this article, you'll see how you can use AJAX to create more focused, faster-loading web pages.

Separate Navigation from Content

Let's start with an example. Consider the article you're reading right now—it has the following items:

This mixture can affect the way search engines index your data:

The navigational elements added to a web page can also impact users with low-speed Internet access, more so if the web page doesn't use positioned DIV elements (which are used by Informit) but rather uses tables. In this case, the whole table has to be loaded in some web browsers before it's displayed to the user.

Traditionally, web designers have tried to separate navigation from content with framesets or by building the whole navigational structure with extensive JavaScript code. Both approaches have drawbacks, so it's no wonder that a large number of major web sites avoid framesets.

Techniques used within the AJAX framework give you an alternate solution to this problem:

Before redesigning your web pages with this approach, you need to consider the following issues:

When you've decided which parts of your navigational structure should be attached with the page and which parts should be separated from it, you're ready for the next step.

Design Your Web Page

The first step in separation of content and navigation is the creation of placeholders on the web page where the navigational elements will be inserted. For each contiguous area of navigational elements, you should create a separate DIV element with a unique id, so that you can identify it later in your JavaScript code. To prevent excessive flicker during the page composition, the DIV elements above or to the right of the content should be sized close to the actual size of your navigational elements so the content won't shift when you replace them with the desired HTML code. The most versatile means of achieving this goal is to insert an empty, properly sized DIV element within the placeholder.

In the case of Informit, the page structure is already very well designed, with the DIV elements already in place, as shown in Figure 1.

Figure 1

Figure 1 Page structure of an Informit article.

You would only need to remove the content from the navigational DIV elements and insert an empty box where the header will appear, resulting in a web page structure similar to this example. (For the sake of simplicity, we'll conveniently forget the requirement to have logo and copyright information embedded in every page.) Here's the code:

<div id="header">
  <div style="height: 100px; width: 100%"></div>
</div>
<div id="contentArticle">
  <div id="firstCol">
  ... article content ....
  </div>
  <div id="secondCol" ></div>
</div>
<div id="footer"></div>

The navigational elements that have been removed from the web pages have to be re-created as independent pages. You should use static HTML files for static content (this will allow the content to be cached regardless of the web server you use) and create a server-side script that will display the dynamic elements based on the web page loading them. For Informit, each web page has a unique article identifier (the p= parameter in the URL), so you would need to create a server-side script that would accept the article identifier and create the right-hand column. In most cases, you can reuse server-side code that creates inline navigational elements.

After the web pages have been redesigned, you're ready to implement the AJAX portion of this solution. As always, you can work with inline frames (IFRAME elements) or use an XmlHttpRequest object.

Inline Frames

You should use inline frames if you're concerned about browser compatibility. Some older browsers support IFRAME elements, but not the XmlHttpRequest object. There are also a few other reasons to use this approach:

To implement this solution, insert an empty IFRAME into each DIV container and add a short JavaScript statement after each IFRAME, as follows:

<div id="header">
  <div style="height: 100px; width: 100%"></div>
  <iframe id="header_iframe" style="height: 0px;"></iframe>
  <script>loadIframe("header","/navigation/header.html")</script>
</div>

The id of the IFRAME should be equal to the id of the placeholder suffixed by _iframe. The loadIframe function takes two arguments: the id of the placeholder and the URL to load into it.

The loadIframe function that starts the load process is very simple:

function loadIframe(id,url) {
  try {
    var iframeObj = document.getElementById(id+"_iframe");
    iframeObj.src = url ;
  } catch (err) {
    alert("cannot load "+url+" into "+id) ;
  }
}

However, there's no mechanism to notify the requesting page that the desired content has been loaded into the placeholder IFRAME. The loaded content thus has to notify the parent page (via a JavaScript call) that it's ready to be used. The best moment to do this is after the page load has finished. The BODY tag in the IFRAME content should thus contain an onLoad event:

<body onload="contentLoaded('header')" style="margin: 0px 0px;
padding: 0px 0px">

The contentLoaded function executed in the context of the IFRAME will extract the HTML content of the body and pass it to a function executing in the context of the parent page, which will use it to populate the placeholder:

A careful reader should wonder by now about the reasons for this complexity—wouldn't it be simpler to load the navigational content in the IFRAME elements? As it turns out, there are a few caveats with that simplistic approach:

Working with XmlHttpRequest

If your audience primarily uses later versions of Internet Explorer or Gecko-based browsers (Mozilla, Firefox, Netscape 7), you could decide to use the XmlHttpRequest object to download additional content into your web pages. The initial step is very similar to the one described earlier. For each placeholder, you need a JavaScript function call to start the load process:

<div id="header">
  <div style="height: 100px; width: 100%"></div>
  <script>loadContent("header","/navigation/header.html")</script>
</div>

The loadContent function is radically different, however: It creates a new XmlHttpRequest object, assigns an event handler to it, and starts the asynchronous loading process:

function loadContent(id,url) {
  try {
    var rq = new XMLHttpRequest() ;
    rq.open("GET", url, true);
    rq.onreadystatechange =  function() { contentLoaded(rq,url,id) }
    rq.send(null);
  } catch (err) {
    alert("cannot load "+url+" into "+id) ;
  }
}

The callback function contentLoaded checks the readiness of the XmlHttpRequest object and the completion status (if the request has completed), and extracts the HTML markup from the response. The easiest way to extract the HTML code (unless you use XHTML, in which case you can use the XML DOM interface) is to use string-handling functions to find the text between the <body> and </body> tags:

function contentLoaded(rq,url,id) {
  try {
    if (rq.readyState != 4) { return; }
    if (rq.status != 200) { alert("failed to load "+url); return; }

    var txt = rq.responseText ;

// find the start of the <body> tag
    var startBodyTag = txt.indexOf("<body")

// find the end of the <body> tag, skipping any attributes
    var endOfStartTag = txt.indexOf(">",startBodyTag+1)

// find the </body> tag, copy until end of text if missing
    var endBodyTag = txt.indexOf("</body")
    if (endBodyTag == -1) { endBodyTag = txt.length ; }

// extract the actual content
    var bodyContent = txt.substring(endOfStartTag+1,endBodyTag)

    if (bodyContent) {
      var placeholder = document.getElementById(id) ;
      placeholder.innerHTML = bodyContent;
    }
  } catch (err) {
    alert("cannot load "+url+" into "+id) ;
  }
}

Compared to the IFRAME-based method described earlier, using the XmlHttpRequest object has the following benefits:

Summary

In this article, you've learned how you can separate the content of your web page from the navigational elements surrounding it. The separation results in a more focused presentation of your content to search engines, as well as reduced loading time for users with low-speed Internet access, since the actual content is shown to the user before the navigational elements are downloaded.

When redesigning your web page to take advantage of this solution, keep in mind that some basic form of navigation has to remain on the page in order to allow search engines and users who have decided to disable JavaScript to navigate between the pages on your site.

You can implement delayed loading of the navigational elements with inline frames (IFRAME) or by using the XmlHttpRequest object implemented in most modern browsers. The IFRAME approach is supported by older browsers and thus might be the method of choice if you're concerned about backward compatibility. The usage of XmlHttpRequest object, on the other hand, gives you tighter control over the loading process and the ability to detect and handle download errors.

800 East 96th Street, Indianapolis, Indiana 46240