Thursday, June 18, 2009

Behavior of Image ALT Attribute in IE/Fire Fox

When browsing the web, you will often notice that a tool tip displays when you mouse over certain images as shown in the image below:

Being mostly a Microsoft IE user, I assumed that the text for this tool tip was specified in the image's alt attribute, as below:

<img src="name.gif" alt="Modeling Article">
I had noticed that the tool tips didn't work in Fire Fox, but didn't pay too much attention. As I had a case where it actually mattered recently, I did some research and learned something interesting. The alt attribute is not supposed to work that way according to the official specs. IE just made it do that. Fire Fox followed the spec and did not.

The official purpose of the alt attribute is to provide alternate text in case the image doesn't load or cannot be viewed, as shown below:

The correct way to provide a tool tip, according to the specs, is with the title attribute:

<img src="name.gif" alt="Modeling Article" title="Modeling Article">
That works as expected in Fire Fox.

Of course, you want both attributes in there because search engine's make a lot of use of the alt attribute and apparently they are meant to serve two different purposes.


Always more interesting stuff to learn...

Tuesday, May 26, 2009

CSS-Only Rollover Buttons

I have done rollover buttons the same way for a long time now:
  • Create 2 images - one "active" and one "inactive"
  • Use a JavaScript function, launched onLoad, to preload the "active" image
  • Use another JavaScript function, fired onMouseOver and onMouseOut, to change the source of the image object when the user mouses over it.

It always worked before. On a recent project, however, IE was giving me fits because it kept trying to reload the "active" image on every mouse over. This caused a very annoying flicker effect.

I assumed that it was some problem with my preload function and in a search for a solution I discovered a whole new way to do rollovers without a preload - without any JavaScript at all in fact. Here is the basic idea:
  • Create 1 image that has both the "active" and "inactive" parts side by side
  • Code a DIV tag that contains a link (A tag)
  • Use CSS settings to change the offset of the background for the DIV and A tags
Since only one image is used, there is no need for a preload function. This method also works faster than the old way.

Here is an illustration of an example I put together with Home and Contact Us buttons:

To start, we need an image that contains both the "active" (yellow) and "inactive" (blue) parts for each button. Here is the home button:

The image is 300 pixels wide, which is important to know since we are going to offset this to only display half the image at any one time. It is 35 pixels high.

Now let's look at the HTML:

<div id="nav-container">
<div id="home-button" class="nav-button">
<a href="../index.htm"></a>
</div>
<div id="contact-button" class="nav-button">
<a href="../contact-us.php"></a>
</div>
</div>
First, we have an outside container DIV for the whole set of buttons (nav-container) that we can use to position the entire set of buttons on the page. Inside that, we have two DIV's - one for each button - that use the CSS class "nav-button". Each of those contain an empty A tag.

Now the CSS. First, we set the position of the outer container from the top left corner of the page:

#nav-container{
position:absolute;
top:25px;
left:25px;
}

Next, we will define the nav-button class:

.nav-button{
width:150px;
height:35px;
position:absolute;
top:0px;
}

Note the height and width settings: the width is half the width of the image. We set the top position from the top of the outer container, but not left as that will be different for each button.

Now we specify the settings for the anchor tags contained in the button DIV's:

#home-button a, #contact-button a{
display:block;
margin:0;
padding:0;
width:100%;
height:100%;
overflow:hidden;
background-image:none;
}

These define the link as a block that is the exact same size as the DIV that contains it. Notice that the background image is set to none. Notice also that I set this for each button's DIV. I tried doing it as a class, which would have made more sense, but that seemed to cause problems in IE8.

Now we have to specify two settings for each button: the background and left position of the DIV tag and the background of the hover state of the A tag, which is actually the same image with a different offset:

#home-button{
left:0px;
background:url('home_button.gif') top left no-repeat;
}
#home-button a:hover{
background:url('home_button.gif') -150px 0 no-repeat;
}

For the Home button DIV, we set the left position to 0, since it is the first button. We set the background image with no offset, so it will display the left 150 pixels of our image (the blue "inactive" button). Then for the Home button's anchor, we set a background for the hover state. It is the same image but it has a 150 pixel offset so that you see the right part of the image (the yellow "active" button). I don't really know why the offset is specified like that. It threw me at first, but play with it and you will figure it out.

So, when you mouse over the link you trigger the hover state, which causes the background image for the link to change from none to the offset background, which covers up the background being used for the DIV tag beneath. When you mouse off the link, the background reverts to none and the background of the DIV shows through again.

All that's left is to specify similar settings for the Contact Us button:

#contact-button{
left:160px;
background:url('contact_button.gif') top left no-repeat;
}
#contact-button a:hover{
background:url('contact_button.gif') -150px 0 no-repeat;
}

Same as the Home button except for the image name and the left position (the width of the home button plus a 10 pixel space).

Voila. No preload, no JavaScript, fewer images, better all around.

Obviously, I didn't come up with this on my own. I got the idea from Petr Stanicek's tutorial and made some adaptations. If you like, check out the demo page on my site where you can view the source and the entire CSS for this neat trick.

Wednesday, May 13, 2009

Pre-Packaged PHP User Login System

I have a project I am working on that requires a user sign-in/registration system. All of the user data needs to be tracked and there are requirements for limiting access to certain content based on login status, etc. It's not terribly complicated and my first inclination was to go with a WMS like DotNetNuke, which has a very robust user management system built into it. But this project will require some special modifications that would be difficult (at least for me) to accomplish with DNN.

So, my next thought was a custom PHP application with a MySQL backend. But I was concerned about the time involved in doing all the legwork just to duplicate the user account functionality that comes with DNN out of the box.

Luckily a bit of Google-ing found me a real gold mine. As is so often the case with PHP, it turns out that somebody has already done all the legwork and is willing to share. (Three cheers for Open Source!!!) Here is the URL:

http://www.evolt.org/node/60384

The download consists of about a dozen very well commented PHP pages that handle just about all the basic aspects of a web site user login system, including:
  • Session-based User Login/Registration with a "Remember Me" option
  • The ability to set different access levels for members (user, admin, etc.)
  • An Admin page where you can view user info, upgrade/demote user levels, delete users, delete inactive users, and ban users
  • Users can view and edit their own account information
  • Visitor tracking that tracks both Guests and Registered Users in real time
  • "Forgot Password" features
  • Optional welcome email to new users
  • Nice error handling features

He gives you the SQL you need to create the required database tables as well as some sample pages to see how the features can be integrated into your site.

It's very easy to use. I had this up and running in a test environment in about 20 minutes. The code is very well structured and commented, so I have already been able to make a number of modifications (like adding more data fields to the account profile) very quickly.

Highly recommended.