Monthly Archives: April 2007

Link Boxes

I was looking over the shoulder of another designer who wanted a box with a headline and copy, and wanted the entire thing to be clickable. Here are some thoughts on marking this up.

As a brief aside, I started looking for this effect on other web sites so I can see how others mark it up, but wouldn’t you know it, I couldn’t find any examples. (Never there when you need them…) If you know of any, leave a comment with a link so we can peak under the hood. I’m confident there is a better way, or at least some solid alternatives out there, to achieve this effect – let me know what they are.

The Idea

A box contains a headline and some copy, and we want the entire box to act as a link to another page. Let’s pretend for now it’s an “About Us” type of box that we want to look like this:

Forgetting about the link for now, here’s some code that would make sense to start with.

<h2>About Us</h2>
<p>How my life story became a Hallmark movie.</p>

I realize that perhaps using <dt> and <dd> could establish more a relationship between the headline and copy, but I’m not sure how I would achieve the end result that way, so stick with me.

To get the box effect, and link effect, a temptation is to do this:

<a href="#">
  <h2>About Us</h2>
  <p>How my life story became a Hallmark movie.</p>
</a>

but that’s a no-no. <a> is an inline element, and block-level elements (like <h2> and <p>) cannot be nested inside inline elements.

However, inline elements can be nested within other inline elements, so one way to work around the validation hurdle is to use <span> tags within the encompassing <a>, like so:

<a href="#">
  <span class="h2">About Us</span>
  <span class="paragraph">How my life story became a Hallmark movie.</span>
</a>

Then the span elements could be styled as display:block; and be presented like one would want them to be.

This could work. If styles are turned off, the spans may all run together, but that could be easily fixed with a <br /> following the first <span>. Still, it doesn’t really seem like an ideal way to mark this up.

I am guilty of using spanitis to achieve this kind of thing, and that’s partly why I’m doing this post – to find a good way out of it. I want to keep some semantic meaning with my tags, not just with my classes. I want to keep the <h2> and the <p> because they mean more than <span>, but how do I get the clickable encompassing box? For that, I’m guessing I need more than what can currently be provided by HTML tags. I need DOM Scripting.

A DOM Scripting approach

I envisioned wrapping the headline and paragraph in a <div>, and attach the link to the <div>’s onclick event using JavaScript. Also, if JavaScript is off, we should still provide a link, so I ended up with this:

<div class="linkbox">
  <h2>About Us</h2>
  <p>How my life story became a Hallmark movie.</p>
  <p class="readmore"><a href="#">Read more...</a></p>
</div>

Before writing the JavaScript, it sometimes helps to put the desired behavior in plain English.

  1. When the page laods, the find all <div> tags with a class of “linkbox”.
  2. Within a linkbox div, find the “readmore” paragraph, which should contain an anchor link.
  3. Take the href attribute’s value of the anchor link, and attach it to the encompassing div’s onclick event.
  4. Since the “readmore” paragraph is no longer needed, hide it.
  5. To give an indication that the <div> is clickable, add a hover effect by adding and removing a hover class to the <div> based on mouse placement.

To help achieve all this, I borrowed functions from Robert Nyman’s EJ – The only JavaScript library you’ll ever need, which contains some homegrown scripting for getting elements by their class name, adding a class name, and removing a class name.

Working Example

Showing you the code in this post would be pointless. Instead, go to the working example, where you can view source and modify to your pleasure. Note that instead of using <div>, I used an unordered list to organize the page differently. Turn off CSS, JavaScript, or both, and all needed elements should still be present.


This post was ported from an old host and CMS, so many comments were lost. Below are the comments that I found were most helpful regarding this post that I salvaged. Some links or attributions may not be working correctly.


@Marc:
Thanks for the link.
Veerle is using all inline elements, including <em> tags, wth <br /> tags to break them up.
<a href=””>Headline<br />
<em>copy copy copy</em><br />
<span>date posted</span>
</a>
Now that I think about it, using <strong> to emulate headlines makes sense, too.

Kate Bolin said:
Couldn’t you just use
<a href=”#”>
<strong>Headline</strong>
Text text text
</a>
?
It just seems to me to be a bit over the top to use all that javascript…

Alan asks the CSS Guy what I use for CSS editing

Alan asks:

What software do you use for CSS editing?

I use BBEdit. When I was on a PC, I used Homesite. At the root of it, I just need some color coding and line numbers to keep me sane, but the extra features of BBEdit, like the grep search, can come in handy.

I use those not just for CSS, but for HTML as well. I have found that it fits my work flow best.

I remember when Dreamweaver started supported CSS in preview mode, and quickly requested that my employer purchase it. After a few weeks, I realized that it wasn’t getting the job done. I like to see how my changes affect different browsers, and Dreamweaver’s preview pane can’t do that. Plus, I find it’s just as easy to switch from text editor to browser as it is to switch from coding view to preview mode on Dreamweaver. (Split view? No thanks.)

For a while I used TopStyle as well, and for the same reasons that I stopped using Dreamweaver, I eventually abandoned it.

On the rare occasions I need to make a complicated table, I use Dreamweaver.

I see new things come out, like TextMate, and more recently, Coda, and wonder if it would be worth the jump. I intend to try TextMate soon, but will probably not use Coda for the same reasons mentioned above. (I like playing with their web page, though.)

So, to add to my answer, I use BBEdit and various browsers.

I had a tough time getting IE7 to browse local files, so I enabled the Mac’s apache web server and keep most of my projects within browsable directories. That way all browsers can get to it. The webserver also comes in handy when playing with AJAX, as you can’t just browse a local file and have the the xmlhttprequest object work (found that out the hard way – rookie mistake).

So, to be even more complete, I use BBEdit, various browsers, Parallels, and Apache. Hope that helps.


This post was ported from an old host and CMS, so many comments were lost. Below are the comments that I found were most helpful regarding this post that I salvaged. Some links or attributions may not be working correctly.


@Lasse and Simon:
It sounds like I should give CSSEdit a look.

How to choose your hotel room with CSS and JavaScript

I work for Hilton Hotels, which operates Homewood Suites. Homewood Suites has just rolled out a way to choose your hotel room (or in this case, “suite”) by selecting the room on a diagram of a floorplan. It’s driven by CSS and JavaScript, and this post will explain how the interface works.

Homewood Suites eCheck-in Process
Homewood Suites eCheck-in Process

The Demo

You can interact with the demo, which includes one floor and some sample rooms. You can choose and switch rooms using either the left side, which shows the traditional radio input choice list, or the right side, by selecting an available room on the map and clicking the “Switch to this suite now” link in the popup.

You may also download the demo in zip format, which includes all html, CSS, images, and JavaScript. (I’m posting this with the blessing of my employer, who is allowing me to share my code with professionals in my field for fun and education. You cannot use the images for your own purposes other than for educational ones, as this doesn’t really belong to me, but to Homewood Suites.)

A note about accessibility

This is the part where you would read that users who have JS and CSS disabled were my highest consideration, but they weren’t. My priority was to get this thing working. However, just by the nature of separating structure, presentation, and behavior, graceful degradation can sometimes just happen. Turn off CSS and/or JavaScript, and you’ll see that guests can still complete the form. Frankly, that was enough for my part. In the case of no CSS, there is a bit of a mess following the submit button, but it’s an acceptable mess, and much of it will likely not make it to the production version (since most of it is unselectable rooms, which our database will likely not return). Also, the idea is that, on the page before this, there is a javascript check, and the guests is sent to a non-floorplan version to choose their room if JavaScript is disabled.

Let’s begin

You know those “escape route” plans that are taped to the back of a hotel door? If you create one of those in digital format without the arrows that point to the exit, you’ll have our starting point: a single hotel floor.

Floor 2

Note that room numbers, exits, compass direction, and locations of elevators/vending etc. are all part of the image, since they are static. Since available rooms are dynamic, those will be layered on top of the floorplan using CSS positioning.

First, we create a div where the plan will sit.

<div id="plan">
  <!-- no content yet --> 
</div>

…and style it to hold the floorplan image:

#plan {
  width:231px; /* background image width */
  height:700px; /* background image height */
  background:#fff url(../images/floorplan.gif) no-repeat 50% 50%;
  border:1px solid #666;
  position:relative; /* this is key! */
  float:left;
}

The rooms will be represented with <a> tags, and will be absolutely positioned on the map. For this reason, the #plan div is set to “position:relative;”, so that once the rooms’ <a> tags are positioned, they will be in relation to the #plan div instead of the top left corner of the browser window.

Add Some Rooms

As stated, rooms are represented with the <a> tag. The href value leads nowhere, the id pinpoints the room itself (I couldn’t use the room number here because id has to start with a letter), and I used the rel attribute to contain the actual room number.

<div id="plan">
  <a href="#" id="a01" rel="201"></a>
  <a href="#" id="a02" rel="202"></a>
  <a href="#" id="a03" rel="203"></a>
  ...
  <a href="#" id="a22" rel="222"></a>
</div>
#plan a {
  display:none;
  width:20px;
  height:20px;
  background:transparent;
  position:absolute;
  text-decoration:none;
}

By default, every room on the floor is listed in the html, and set to display:none; in the CSS. The idea was that only selectable rooms would have a class that set them to display:block;. In the final version, I believe any room that wouldn’t have been selectable wouldn’t be in the html.

The rooms are positioned in the CSS.

#plan a#a01	{top:126px;left:148px;}
#plan a#a03	{top:167px;left:148px;}
#plan a#a05	{top:208px;left:148px;}
#plan a#a07	{top:250px;left:148px;}
#plan a#a09	{top:289px;left:148px;}
#plan a#a11	{top:331px;left:148px;}
...

For rooms that are available, they are set with class=”avail”. If room 204 was available for a guest to choose, the html would appear like so:

<div id="plan">
  ...
  <a href="#" id="a03" rel="203"></a>
  <a href="#" id="a04" rel="204" class="avail"></a>
  <a href="#" id="a05" rel="205"></a>
  ...
</div>

And if JavaScript is enabled on the browser, a function runs that attaches display:block; to that room. (If JavaScript is not enabled, guests can still refer to the map while choosing their room with a radio choice.)

function makeAvailableRoomsViewable() {
  var plan = document.getElementById("plan");
  var rooms = plan.getElementsByTagName("a");
  for (var i=0;i<rooms.length;i++) {
    if (rooms[i].className == "avail") {
      rooms[i].style.display = "block";
    }
  }
}

I’m using a little orange icon to indicate the room is selectable. So I make sure to style it accordingly.

#plan a.avail {
  background:transparent (../images/ico_avail.gif) no-repeat 50% 50%;
}

Available rooms are now indicated on the map with an yellow-orange rounded square.

Viewing Room Details

At this point, we could’ve set it up so that you just click this square to select that particular room, like a highly stylized radio input, but one of the requirements of the floorplan was to also be able to view more details about the room. So selecting the square enables a CSS popup. It’s coded similar to how Eric Meyer describes CSS popups, with a <span> within an <a>.

<a href="#" id="a04" rel="204" class="avail">
  <span class="pop">
  <!-- details about the room go here -->
  </span>
</a>

In Meyer’s popups, the span is set to display:none; in the normal state, and switch to display:block; on hover of the parent <a>. Because we wanted guests to be able to read and select options within the popup, we opted for the popup to appear on mouse click instead of mouse hover. This way, the popup would not require the user to keep the mouse within certain dimensions in order to view it. However, whereas :hover-driven popup would’ve only required CSS, we needed to create some JavaScript to handle the onclick event.

Our JavaScript will, on mouse click, change the class of the <a> tag from “avail” to “availPop”. The “availPop” class is defined in CSS to assign display:block; to the interior span element.

function preparePops() {
  var plan = document.getElementById("plan");
  var rooms = plan.getElementsByTagName("a");
  for (i = 0; i < rooms.length; i++) {
    rooms[i].onclick = function() {
      if (this.className == "avail") {
        clearPops();
        this.className = "availPop";
        return false;
      }
    }
  }
}

Note the "clearPops()" function that runs before the class name is changed. That function cycles through all other rooms, and if any one of them already has its popup showing, the class name is changed and the popup is closed. (It checks to see if any other room already has a class of "availPop", and changes it to just "avail".) This way you're only viewing one popup at a time.

The CSS Popup

The main purpose of introducing this floorplan option when checking into the hotel was to allow guests to be able to choose a precise location of their room. An additional feature was the inclusion of the popup, which is the span that contains the room description, images, and a trigger to select the room.

The popup is just made up of many <span>s and a couple of <img> tags, which are styled and anchored for DOM manipulation.

<a href="#" id="a04" rel="204" class="avail">
  <span class="pop">
    <span class="roomNumber">Suite 204</span>
    <img class="closePop" src="images/ico_close.gif" alt="close" />
    <span class="status">Status: Available</span>
    <span class="statusYours">Status: Selected Suite</span>
    <span class="switchRoom">Change to this suite now</span>
    <span class="roomtypeimage"><img class="roomImg" src="images/roomtype01.jpg" alt="" />
    <span class="imgTypeDisclaim">Photo of Room Type: Not Actual Suite</span></span>
    <span class="imgCycle"><span class="imgprev"><img src="images/ico_imgPrev.gif" alt="Back" /></span><span class="roomImgCurrentNum">1</span> of <span class="totalImages">1</span><span class="imgnext"><img src="images/ico_imgNext.gif" alt="Next" /></span></span>
    <span class="details">This is a non-smoking suite.<br />Beds: King</span>
  </span>
</a>

Depending on the class of the parent <a>, some items are set to display:none, while others, display:block.

Notice that the "Photo of Room Type: Not Actual Suite" is actually text, not part of the image itself. The text is just positioned over the image and given some opacity using CSS. Doing it this way allowed us to save space by including the message on the image itself, but we didn't have to edit all the images we already have on file for each room type. Since the wording changed a few times during the development process, keeping it as text (vs an image) made it an incalculably valuable time saver for updating.

Our databases already had more than one picture for some room types, and very basic slideshow was set up to accomodate it. I used very rudimentary JavaScript for this, which updates the src attribute of the image as the arrows below are clicked.

The "Selected" Room

Once a guest has chosen a room, it is differentiated from the other available rooms by the use of a blue rounded square as the background image.

I call that the "on" state. So how is that room chosen? There is a span within the CSS popup that I've styled to look like a link, which says "Change to this suite now".

If that span is clicked, the desired room's <a> tag's class name is switched to "on".

function changeRooms() {
  var plan = document.getElementById("plan");
  var rooms = plan.getElementsByTagName("a");
  for (i = 0; i < rooms.length; i++) {
    var spans = rooms[i].getElementsByTagName("span");
    for (j = 0; j < spans.length; j++) {
      if (spans[j].className == "switchRoom") {
        spans[j].onclick = function() {
          turnOtherOnRoomsToAvail();
          selectTheRoomRadio(this);
          this.parentNode.parentNode.className = "on";
        }
      }
    }
  }
}

The CSS file has different styles for the "on" room so that it is obvious it is the guest's chosen selection.

In the JavaScript, note that before the class name for the desired room is switched to "on", a function called "turnOtherOnRoomsToAvail()" runs, which does exactly what it's title says. It goes through the rooms and changes whichever one is currently selected (class="on") back to available (or class="avail").

Radio button and floorplan room selection dependency

You'll also notice that another function called "selectTheRoomRadio()". As stated earlier, guests may choose their rooms using either the left-side radio input list, or the right-side floorplan. We want the left side to know what the right side is doing, and vice versa. For example, if I choose room 204 in the radio input list, then room 204 should switch to the "on" state in the floorplan (as indicated by the blue rounded square in the chosen room). Also, if I select "Change to this suite now" from the CSS popup on the floorplan for room 208, I want the radio input for room 208 to have a selected state.

Why is Homewood Suites doing this?

Hotels want to offer guests as much control over the room selection process as they can. Selection criteria that have already existed for Homewood Suites were traits like high/low floor, handicap accessibility, smoking preference, proximity to the elevator, etc. With this floorplan diagram, guests can now visualize exactly how close a room is to the elevators, exits, ice machine, etc., and even can see what direction their room is facing (in case they want to wake up to the sunrise versus enjoying a view of the sunset).

Conclusion and Notes of Interest

There is a little more to the code than what I described above - too much more for me to discuss in detail. If you view source of the demo, it should all be decipherable.

This floorplan application is not used for the reservation process, but instead for "eCheck-in", which allows guests to check in online a certain number of hours before their actual scheduled arrival to the hotel. Being new to the hotel industry, and not a frequent traveler, part of this project for me was an education on hotel reservation process. For example, making a reservation doesn't mean that a particular room number is assigned to the guest. The room number doesn't get assigned until closer to check-in time, if not during check-in itself. For this reason, the visual floorplan does not lend itself well to the reservation process, as choosing a room number at reservation time is not something the hotels are set up to do. So for now, this application would only be viewable for those guests choosing to check in online.

I was one of many hands that touched this project. If anything on the floorplan doesn't make sense (for instance, that statement about "Upgraded Suite", or the "Push to Talk" button), I understand, but know that there are reasons for their existence that fall beyond my purview.

It's also worth noting that the version that went into production is functionally better than the demo on this site, particularly when it comes to changing floors, which the demo doesn't show at all.