Eyetrack and Usability Notes

I recently discovered a new study on web site usage. Eyetrack III is a study of the eye movements of 46 people on fictional and real news web sites. They published a summary of their findings as well as an FAQ about Eyetrack. For ongoing reading on the topic, check out the Eyetools Blog.

While on the topic of eye tracking, I read one of the recent enties on the Eyetools blog and thought it was worthy of mention. The Washington Post web site just underwent a redesign. Eyetools created a Heatmap of the page from 19 visitors. The Heatmap reveals that the bottom of the page is getting very little attention.

What is interesting about this is that evidence demonstrates that this is NOT a below-the-fold problem. The Heatmap shows no dramatic drop in attention for areas below the fold.

So what is the problem? Eyetools says "ineffective line-height spacing and lack of white-space reduce reading". I think they are right, but their Heatmap shows a dramatic drop. I decided to go out to WashingtonPost.com myself. I scrolled down to around the end of the area where people seemed to be looking and here is what I saw:



Looks like the bottom of a web page doesn't it? It isn't. The page continues, but no one is looking. This seems to coordinate with the "Avoid Scroll Stoppers" (pdf) guideline on Usability.gov, which Usability.gov gave a "Strength of Evidence" of 4/5 and a "Relative Importance" of 2/5.

This certainly seems like something to watch out for in your designs!

Common Coding Problems with HTML and CSS

Sorry for the lack of posts recently, trying to get caught up on paying work.

Someone recently posted a link an article on the Web Standards Group mail list. The article, "Common Coding Problems with HTML and CSS", does a really good job of summarizing issues the possible issues in CSS/HTML web sites (most of them IE bugs).

In Defense of FLiP

In a previous blog entry, I criticized the Fusebox framework for some of its slight imperfections. So this may seem like a slight reversal. I still maintain that while Fusebox is a great framework, it isn't the choice for me. FLiP (Fusebox Lifecycle Process - the methodology associated with Fusebox and Mach-ii), on the other hand, is another matter.

[More]

Coding Style Article

Spike's blog had a link to an article on good coding style. I enjoyed the article, so I thought that I should link to it as well. It applies to any language, ColdFusion included (heck, it really even applies to HTML).

Little things in ColdFusion 7

Pete Frietag has been blogging about a lot of great new features of ColdFusion MX 7 that haven't received much hype. I had missed many of these. I highly recommend that you read up on the new features if you are getting (or thinking about getting) ColdFusion MX 7.

Steve's Guidelines

I have noticed that I not always been consistent in the past about making sure that all of the sites that I have worked on have consistently met any given set of criteria. So, I am here going to list out criteria that all future sites should have.

Requirements:

  • A custom 404 (page not found) error page (see guidelines)
  • Style sheets for print
  • robots.txt
  • ColdFusion error handler (for ColdFusion sites)
Aspirations
  • XHTML
  • Accessible HTML (508 complance)
  • Unobtrusive JavaScript
I am sure than I am missing things that all sites should have. I would love to hear feedback from anyone on criteria that I should add or take away.

Application Events: onRequest

I mentioned in a previous blog entry that I had a site (Oklahoma Medical Reserve Corps) that is XHTML 1.0 Strict and can also be served up in MS Word. As I mentioned in that entry, the two unfortunately conflict on one point:

XHTML 1.0 Strict doesn't allow an align attribute in an img tag, instead relying on CSS for positioning. MS Word, meanwhile, expects an align attribute and fails to recognize my CSS for image alignment.

I have been unable to find a way to solve the problem in CFMX 6.1 so far (If you do, please let me know). In ColdFusion MX 7, however, it would be pretty easy.

ColdFusion MX 7 comes with a new feature called Application Events which uses a new special file called "Application.cfc". If you use Application.cfc, then Application.cfm and onRequestEnd.cfm won't fire. Application.cfc allows you to capture errors, the start and (ta da!) end of a session, the start and end of an application, and the start and end of a request. It also allows you to supercede the request event (the page being called) as well.

OK. No time today to cover all of the things you can do with Application Events right now, so I will try to make this example as painfully simple as possible. Let's first replace (in the laziest way possible) our existing site structure with Application.cfc. Keep in mind, that this approach is for illustration only. I don't necessarily recommend you literally do what I am doing in practice.

Application.cfc:

<cfcomponent>
<cffunction name="onRequestStart"><cfinclude template="Application.cfm"></cffunction>

<cffunction name="onRequestEnd"><cfinclude template="OnRequestEnd.cfm"></cffunction>
</cfcomponent>

We have changed our code to use Application.cfc without changing the behavior of our site at all (keep in mind that you only need the onRequestEnd part if you site is using OnRequestEnd.cfm).

Now let's add an OnRequest event which will supercede the normal calling of the page. Note that any variables-scoped variables created in Application.cfc (or any file included by Application.cfc) will be available to the file being requested if-and-only-if it is included via the onRequest method.

<cfcomponent>

<cffunction name="onRequestStart"><cfinclude template="Application.cfm"></cffunction>

<cffunction name="onRequest">
<cfargument name="targetPage" type="string" required="true">
<cfinclude template="#arguments.targetPage#">
</cffunction>

<cffunction name="onRequestEnd"><cfinclude template="OnRequestEnd.cfm"></cffunction>
</cfcomponent>
Still no change in behavior. So far, so good. OK, now that we have changed the structure of our code, let's take advantage of that change. From now on, I am only going to look at the code in the "onRequest" event.

So, in the onRequest event, we have this:
<cfinclude template="#arguments.targetPage#">

Now let's check if this page is being served up in MS Word.
<cfif isDefined("url.format") AND url.format eq "word">
<cfinclude template="#arguments.targetPage#">
<cfelse>
<cfinclude template="#arguments.targetPage#">
</cfif>
All we have to do now is change our class="right" and class="left" to align="right" and align="left" when the document is being served in MS Word.
<cfif isDefined("url.format") AND url.format eq "word">
<cfsavecontent variable="contents"><cfinclude template="#arguments.targetPag#"></cfsavecontent>
<cfset contents = ReplaceNoCase(contents, 'class="right"', 'align="right"', 'ALL')>
<cfset contents = ReplaceNoCase(contents, 'class="left"', 'align="left"', 'ALL')>
<cfoutput>#contents#</cfoutput>
<cfelse>
<cfinclude template="#arguments.targetPag#">
</cfif>
That's it! Now, it should be noted that this code would replace all instances of class left or right with align in all tags (not just 'img') but won't get instances where more than one class is used on a single element. Perhaps a regular expression is needed, but that is a topic for another day. Nevertheless, the problem (at least in its simplest form) is solved.

That should provide a nice glimpse into Application Events. I will cover more on Application Events in future posts. Good luck!


Want to learn more about Application.cfc? Check out the Managing Requests in Application.cfc in Macromedia LiveDocs.

ColdFusion MX 7 is Released

The newest version of ColdFusion (ColdFusion MX 7) has been released today. It is a pretty exciting new release. Unfortunately, Macromedia chose to restrict event gateways to the enterprise edition which dramatically reduces the incentive to upgrade.

Even so, it is worth taking a look at:
http://www.macromedia.com/software/coldfusion/

ColdFusion Developer's Journal will be covering the new release pretty extensively.
http://www.sys-con.com/story/?storyid=48103

I will also try to discuss some of the new features in future entries. Application Events are pretty exciting and will likely be covered tomorrow.

Maintaining a Session

On the CF-Talk list, Richard Colman asked how he could keep a session alive for longer than the 30 minute limit imposed by Crystal Tech.

Michael Dawson provided a very good answer (quoted below):


I setup my intranet so that, even if the session times-out, it will be transparent to the end-user. I do this by keeping a separate session cookie.

When the session times-out, then the user accesses another page in the application, my scripts will reload the data in the session scope again. The end-users have not complained about this process.

In addition to that approach, I would suggest the following bit of JavaScript:
function keepAlive() {
var imgAlive = new Image();
var d = new Date();
imgAlive.src = '/alive.cfm?d=' + d;
}
setInterval("keepAlive()", 20*60*1000);

Before the script is added to your site, add a small alive.cfm file to the root of your site (name it whatever you wish, just be consistent). The script makes sure that a page is requested from your ColdFusion server by their browser every 20 minutes (safely less than the 30 minute time-out). Alive.cfm need not return an image - JavaScript doesn't check.

Keep in mind that this only works for users who have JavaScript enabled, so make sure to use this technique in conjuction with (not in place of) the approach suggested by Michael Dawson.

This technique actually has a great many uses that I will try to post in future entries. I have used it in the past to change database data without a form submit and also for JavaScript error handling.

Update!

Martin Perry added this suggestion to the discussion to get around the JavaScript issue:
Alternatively, to get around the JavaScript bit, create an invisible IFRAME which has it SRC set to the alive.cfm.. On Alive.cfm, add a HTTP redirect to redirect back to itself after 1200 seconds.

<META HTTP-EQUIV="Refresh" CONTENT="1200;URL=/alive.cfm?cachebuster=<cfoutput>#createUUID()#</cfoutput>">

I never think about IFRAME myself (trying to remain standards compliant). Nevertheless, it is an excellent suggestion. Good call Martin!

Flexible Directory Structure

In my quest to become a better programmer, I am trying to learn Object-Oriented Programming (OOP). In that vein, I have started a book on Design Patterns ("Head First Design Patterns"). The first design principle that they cover is "Identify the aspects of your application that vary and separate them from what stays the same.".

Well, I am along way yet from being a good OO (Objected-Oriented) programmer, but this is - at least - is something that I have been doing. I have actually been using the principle (or some variation thereof) to guide the directory structure that I use for web sites.

My goal for my directory structure is actually that things should be grouped together based on when they are likely to change (since all things change, after all). Let's take a look.



The "/_bak" directory is relatively straightforward. The is a temporary storage location for files that I think that I should delete. I put them in the "/_bak" directory until I am certain.

The "/f" directory is for files uploaded by the site-owner, usually via the admin interface. I have a subdirectory for each type of information - typically one directory for each database table in which a record of the file is stored (though I intentionally do not name the directory the same as the table).

The "/i" directory is for images (that are not uploaded by the site-owner in the admin interface). Like the "f" directory, I do not put any files directly in the "i" directory.

The "/i/d" directory is for images that are part of the design (as opposed to images within the content). I number the directories within the "/i/d" directory by design revision. When the site is first created (the first design revision), all of the images needed for the design are placed in "/i/d/1". This would hold the site logo and any images that are part of the design of the site.

When the site is redesigned (it will happen someday), I create "/i/d/2" and place all of the images for the new design in that directory. Eventually I will be able to delete "/i/d/1". This allows me to easily know which files I can delete and which I cannot - less risk of a major build-up of unneeded files.

The "/i/en" directory holds any images that are not part of the design that contain words (assuming that they are in English). This allows me to easily create a new directory if I need to have more than one language on the site (for example an "sp" directory for Spanish). This is not much extra trouble if I don't ever need more than one language on the site, but saves me a lot of trouble if I do. If I have words in the images for the design itself, I create a directory under the design number for those files. You can find two-letter language code here: http://www.w3.org/WAI/ER/IG/ert/iso639.htm

The "/i/photos" directory is for any image that is not part of the design and doesn't have any words in that will need to be translated if the site needs to be multi-lingual (for example, the image might have a copyright notice, but no other text).

The "/lib" directory holds any JavaScript files or files supporting JavaScript files.

What about CSS files? Well, to be honest I am not yet as consistent as I would like with CSS files. In theory, I believe that they are part of the design and should therefore be in the in the directory for the design of which they are a part. In practice I sometimes put them in the root directory instead for convenience.

This directory structure allows me to easily accommodate common types of changes that might be faced by a site. Naturally, these won't be the only directories in a given site - each site will have directories specific to the needs of that site.

One quick aside, for those of you worried about extra characters. If you usually use an "/images" directory and are worried that this approach adds too many characters, consider this: "/images/" is 8 character; "/i/d/1/" is 7 character, "/i/photos/" is 10 (you could rename it "/i/pics/" and be back at 8).

I have found this approach to be helpful, hopefully you will as well. If you have any questions or suggestions, I would love to hear them - just leave me a comment!

Good luck!

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.