Showing posts with label html. Show all posts
Showing posts with label html. Show all posts

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.

Friday, April 10, 2009

Getting an Indented List to not Indent

It seems like it should be really easy. I want a bulleted list, but with no indent. In other words, I want the bullets aligned to the left with no indent, but I still want the space between the bullet and the text.

Why would I want this? Lots of reasons. I may have a list that is contained in a table in a page column where it makes no sense to indent the list.

It seems like this should be easily controlled with CSS, but not so. All my attempts at this resulted in results other than what I wanted. Attempts to reduce the left indent usually resulted in the bullet simply vanishing or other odd stuff. I tried having the list items without the actual list tag, which worked in some browsers but not others; I encountered problems with the text wrapping under the bullet.

I thought I must be missing something so I searched a bit online. It seems there really is no good way to do this. Apparently the indented list was intended to be just that - an indented list. Thus, there is no standard reliable way to change it.

What you end up having to do is create a table where each row is a list item with two cells. One cell contains an image for your bullet, the other contains your text. It works, but it's hardly efficient.

Just one of those HTML oddities, I suppose.

Friday, December 5, 2008

Cross-Browser Testing Made Easy

One of the challenges of building a web site is ensuring that it will function the same way when viewed by many different web browsers and versions of browsers on different operating systems. Something that works fine in the latest version of IE or FireFox may not work the same way (or at all) in an older browser or on a different O/S. This is not as much of an issue if you are just using very vanilla HTML. However, if you start using JavaScript, DHTML, or some of the more exotic CSS, you may be in for a nasty surprise when you try to view the page on a different system.

What really got me thinking about this recently was my interest in weaning myself away from table-based design in favor of more CSS-driven design. I know it's supposed to be so much better, the wave of the future and all that. But my concern has always been how to be sure it would work on older browsers.

I try to keep the latest versions of IE, FireFox, NS Navigator, Opera and now Google Chrome on my local machine for some basic cross-browser testing. But I can't have the other versions or the other O/S configurations to test. I don't even own a Mac at present.

I started thinking it would be cool if there was a software tool out there that would grab a page and render it just like a specified browser, version of browser, etc.

As it happens, I found something even better. This web site (http://www.crossbrowsertesting.com/) allows you to log into any of their many and varied images to test your page. It's free, with some restrictions that I'll get to in a bit. But you can hop on to a Mac, Ubuntu or Windows (98, XP, Vista, etc.) system and try out many different browsers, versions of browsers, etc. It's brilliant. It's not some kind of program that mimics the browser. It's the actual browser. And it's fully functional so you can test all your JavaScript, DHTML, whatever.

There are a few restrictions on the "free" part. You can only stay logged into a session for 5 minutes at a time. But you can launch as many sessions as you like. So for quick tests, it is perfectly adequate. Also, paying customers get preference for access when the site gets busy. If you need to do more complex testing and need more than 5 minutes on an image, you can buy little blocks of time. It's all very well thought-out.

Now, if they could just do something similar to test wireless devices...


Monday, November 3, 2008

New Window or Same Window?

Any time you create a link on a page, you have the option to launch the target page in the same window (the default option) or in a new window. We aren't talking about those obnoxious automatic pop-ups here. We are talking about links the visitor actually clicks on. There seem to be several schools of thought on when it is appropriate to launch a new window.

Some say you should never launch a link in a new window for a couple of reasons:
  • The user can always launch in a new window by choice by holding CTRL when they click the link or by middle-clicking the link with the mouse wheel.

  • By contrast, there is no easy way to make a link coded to launch in a new window launch in the same window. So, you are essentially taking the choice away from the visitor.

I'm not sure I agree with that. For one thing, many users don't know how to launch in a new window. Also, in many cases, a user may want to check out something you are linking to without leaving your site. I like the following rule of thumb, which seems to be the consensus from what I have read:

  • Make internal links (links to stuff on your site) open in the same window.

  • Make external links (links to other sites) open in a different window.

There are some exceptions to the first point. For example, if you are displaying a short form or a Flash piece or something and you want better control over the window like size or toolbar/no toolbar, etc. But for the most part I would think these rules would work.

I'd be curious if anyone agrees/disagrees either from a designer standpoint or from a user's standpoint. Let me know...

Friday, October 31, 2008

Validating Form Entries with JavaScript PS

OK. Being new to Blogger, I didn't realize how to correctly post code samples to an entry. Hence the screen captures in my last post. Below is a copy-and-paste-friendly version of the whole page of code I used for that example.

<html>
<head>

<script type="text/JavaScript">
<!--
function check_form_data()
{
if (document.the_form.email.value == "")
{
alert("Email is a required field. Please fill it in.");
document.the_form.email.focus();
document.the_form.email.style.background = "#EEF111";
return;
}else{
document.the_form.submit();
}
}
// -->
</script>

</head>

<body>

<?php
if (isset($_POST['test_val'])){
process_form();
}else{
print_form();
}

function print_form(){
print <<< FORM_TEXT
<!--Note that the action just points back to the same page-->
<form name="the_form" method="POST" action="this_page.php">
<!--Here is our test value-->
<input type="hidden" value="1" name="test_val">
Email: <input type="text" id="email" size="20"><br>
<input type="button" onClick="check_form_data();" value="Submit">
</form>
FORM_TEXT;
}

function process_form(){
//Process the form data - send an email, write to a DB, whatever.
}
?>

</body>
</html>

Thursday, October 30, 2008

Validating Form Entries with JavaScript

I use HTML forms quite a lot on the web sites I build for a variety of purposes. Most of the ones I build these days are self-handling PHP forms. This means that the form and the PHP that handles the form are on the same page. This is easy to do. You just put a hidden value in the form that gets set when the visitor submits the form. The PHP code checks for that value. If it's set, it does the processing. If it's not set, it displays the form. The basic code layout looks something like this:



In the first part of the PHP, we check to see if the hidden value "test_val" is set. If it is, process_form(), otherwise print_form(). Nothing to it.

We can have process_form() do just about anything with the submitted data. What we don't want it doing is trying to process form data that cannot, or should not, be processed. We may have certain fields that are required. We may have fields where the input has to be in a certain format or match certain criteria. Of course, we also don't want to be processing anything that is clearly the work of a spambot. We could handle all of this on the server side and in some cases where more complex validation is needed, this might be appropriate. But why have our server waste processing cycles doing simple checks for missing or garbage data? Let the requesting browser do it by giving the data a quick once-over with client-side JavaScript first.

The first thing that we have to do is intercept the form data before it gets sent to the server. To do this, we will replace the usual HTML form SUBMIT button with a generic button that launches our JavaScript when clicked, like this:



For illustration, let's plug this into a simple form that collects an email address:



Now let's assume that we want to do a simple validation to make sure that the email field is not blank when submitted. The basic layout of our JavaScript function (placed in the HEAD) could look something like this:



We check to see if the email value is blank. If it is, we throw an alert and exit the function. Otherwise, we call the JavaScript submit function, which sends the validated form data on its merry way.

Of course, the validation we have done here is very simple. We could check to see that the value of the email field matches the proper format for an email address. We could write a loop to systematically check multiple required fields. We could check to see that multiple fields do not contain the same value - an annoying spambot symptom. We could even dynamically add additional fields to the form based on the visitor's initial inputs. There is loads more we could do.

In our simple example, we could help the visitor even more by sending their cursor directly to the email field:



We could even highlight the field in yellow to further alert the visitor to the problematic field:



This is especially useful if you are checking and flagging multiple fields. You can focus the visitor's cursor on the first problem field, but highlight them all so that they see all the problems. Just remember to reset the highlight color back to the default for all fields at the start of your function, otherwise the fields that your visitor did fix will still be highlighted.

Certainly nothing groundbreaking here, but useful stuff. There are tons of examples of this out there and the complexity of your validation is really only limited by your knowledge of JavaScript.