Tuesday, October 21, 2008

Sliding Doors for MY a:hover Craft

Lately, I've been experimenting with different cascading style sheet designs for websites. One of the problems I've come across is how to create custom link buttons or tabs and add my own images on their background. Bear in mind that such links have to have a variable width depending on the length of the link anchor or on the different browser settings a visitor might have previously applied. This is all fine when the backgound picture is simply a small .gif which generates a texture. But what do you do when you want to use an image such as this?...

button skin

Note that both the left and right edges of the picture are relevant for my button. The picture is 400px wide and if the anchor text exceedes that width, the backgound is repeated spoiling the design. On the other hand, if the anchor text is shorter, the right edge isn't showing. As a pre-requisite, we're not allowed to fix this using HTML tables, but only CSS. The proper solution is a technique called "sliding doors" and I found it on Douglas Bowman's webdesign blog. Basically, you use two overlapping pictures and calculate their width so that the resulting button can contain both short and long strings. I'm not going to insist too much on this technique, but just to illustrate it clearly, I've drawn a diagram based on Bowman's explanation:

explanation of sliding doors technique

Another common CSS technique is to use the a:link, a:hover etc. pseudo-classes to create different effects when visitors hold their mouse over a link button. A good tutorial for doing this is Stu Nicholls' article on ":hover crafts". Here's my own basic example:

Button 1 Button 2 Button 3

However, when you want to apply this a:hover technique to a button that has to have an image background during the "hover" state, you run into a problem. I haven't found any articles which explain how this should be done, so after a few trials, I came up with the following procedure:

  1. I'm going to use a navigation bar to demonstrate the technique. It's good practice to place the navbar links in an unordered list, so start I'll by writing the HTML code necessary for this button list:
    <ul>
       <li><a href="#"><span>Button 1</span></a></li>
       <li><a href="#"><span>Link</span></a></li>
       <li><a href="#"><span>Button 2</span></a></li>
    </ul>
    I haven't declared any style properties yet, so at this point, the list looks like this:


    Each list item obviously contains a "<a>" tag for the link anchors. In addition to that, the link text is contained within "<span>" tags which I'm going to use as my top layers for the sliding doors - you'll understand this later.

  2. Keeping the same HTML code, I'm now going to start editing CSS properties for the list: first, remove bullets and adjust margin + padding:
    ul{
       list-style-type: none;
       margin: 0;
       padding: 0;
       }

    li{
       margin: 0;
       padding: 0;
       }
    Result:



  3. I want this to be a horizontal navbar, so next I'm going to display the list items inline (changes are highlighted in bold):
    ul{
       float: left;
       list-style-type: none;
       margin: 0;
       padding: 0;
       }

    li{
       float: left;
       margin: 0;
       padding: 0;
       }
    Result:



  4. I'm now going to set a fixed height for the navbar, plus a red background in order to point out its shape:
    ul{
       float: left;
       list-style-type: none;
       margin: 0;
       padding: 0;
       background-color: Red;
       height: 30px;
       overflow: hidden;
       }

    li{
       float: left;
       margin: 0;
       padding: 0;
       }
    Result:



  5. By now, there's a need to adjust the padding of these buttons. So I start off by adding some padding on the left side of the anchor:
    ul{
       float: left;
       list-style-type: none;
       margin: 0;
       padding: 0;
       background-color: Red;
       height: 30px;
       overflow: hidden;
       }

    li{
       float: left;
       margin: 0;
       padding: 0;
       }

    li a{
       display: block; /*display the achor as a block*/
       margin: 0;
       padding: 0 0 0 10px;
       }
    Result:



  6. The remaining padding can be adjusted by editing the properties of the "<span>" tag. I'm also going to set a green backgound for it in order to display its shape clearly:
    ul{
       float: left;
       list-style-type: none;
       margin: 0;
       padding: 0;
       background-color: Red;
       height: 30px;
       overflow: hidden;
       }

    li{
       float: left;
       margin: 0;
       padding: 0;
       }

    li a{
       display: block; /*display the achor as a block*/
       margin: 0;
       padding: 0 0 0 10px;
       }

    li a span{
       display: block;
       margin: 0;
       padding: 4px 10px 10px 0;
       background-color: Green;
       }
    Result:



  7. Setting the "a:hover" behavior - this is the part where I can actually apply the "skin" for my buttons. Since the "<span>" entity is the top-most layer, I'll use it to dislay the main part of the button and its right edge. The "<a>" tag will be used to render the left edge only:
    ul{
       float: left;
       list-style-type: none;
       margin: 0;
       padding: 0;
       background-color: Red;
       height: 30px;
       overflow: hidden;
       }

    li{
       float: left;
       margin: 0;
       padding: 0;
       }

    li a{
       float: left; /*this ensures the entire button is clickable*/
       display: block; /*display the achor as a block*/
       margin: 0;
       padding: 0 0 0 10px;
       }

    li a span{
       display: block;
       margin: 0;
       padding: 7px 10px 10px 0;
       background-color: Green;
       }

    li a:hover{
       background: url(button-bg-gradient.gif) left top;
       }

    li a:hover span{
       background: url(button-bg-gradient.gif) right top;
       }
    Result (hover your mouse over it to see the changes):



  8. OK, we're nearly there. All the navbar needs now is a proper background and some finishing text-formatting touches:
    ul{
       float: left;
       list-style-type: none;
       margin: 0;
       padding: 0;
       background: url(bg-gradient.gif);
       height: 30px;
       overflow: hidden;
       }

    li{
       float: left;
       margin: 0;
       padding: 0;
       }

    li a{
       float: left; /*this ensures the entire button is clickable*/
       display: block; /*display the achor as a block*/
       margin: 0;
       padding: 0 0 0 10px;
       cursor: pointer;
       text-decoration: none;
       color: White;
       font-family: Tahoma;
       font-weight: bold;
       text-transform: uppercase;
       font-size: small;

       }

    li a span{
       display: block;
       margin: 0;
       padding: 7px 10px 10px 0;
       cursor: pointer;
       }

    li a:hover{
       background: url(button-bg+gradient.gif) left top;
       }

    li a:hover span{
       background: url(button-bg+gradient.gif) right top;
       }
    Result:




That's about all there is to it. You can use this technique to also create skins for the inactive state of your buttons.

Note that the text above is already formatted, so you may encounter problems if you copy that code into the source code of your website. Instead, I recommend you copy the final code from the text boxes below:

HTML:

CSS:


There are plenty of examples of such navbars on Stu Nicholls' site (see above). Furthermore, one can deduce the technique by simply looking at the source code of a site that uses it. However, I felt a clear explanation was needed and I hope I've accomplished that with my article. Please share any better tutorials you may find and let me know how this works out for your site.

1 comment:

  1. foarte interesant....Cand imi umbli la butoane?

    ReplyDelete

Note: Only a member of this blog may post a comment.