Align Shadows on Repeating Backgrounds

By Nick Little on December 16, 2008 at 6:30 am in css

One thing web designers do a lot is add fancy shadows and rounded corners to content boxes. This would all be great, except for the fact that they like to use repeating backgrounds as well. As a web programmer, one might end up trying to write HTML and CSS code for a design that looks very similar to the image on the right. You may ask, “How is the image used for the background of the footer going to be aligned properly with the background used for the content section?” Here is a nifty javascript routine that can be used in this situation:

function addEvent(elm, evType, fn, useCapture) {
  if (elm.addEventListener) {
    elm.addEventListener(evType, fn, useCapture);
    return true;
  }
  else if (elm.attachEvent) {
    var r = elm.attachEvent('on' + evType, fn);
    return r;
  }
  else {
    elm['on' + evType] = fn;
  }
}

function fixHeight() {
  var resizeElement = document.getElementById('divPreFooter');
  var containerElement = document.getElementById('divWrapper');
  var divisibleBy = 10;
  var resizeOffset = 0;

  if (containerElement.clientHeight % divisibleBy != resizeOffset)
    resizeElement.style.height = ((divisibleBy - ((containerElement.clientHeight - resizeElement.clientHeight) % divisibleBy) + resizeOffset) % divisibleBy).toString() + 'px';
}

addEvent(window, 'resize', fixHeight, true);
addEvent(window, 'load', fixHeight, true);

This routine will adjust the height of an element (In the example above, ‘divPreFooter’) so that a different element (‘divWrapper’) will have a height that is a multiple of a number (divisibleBy). This will align the repeating background on the content section with the background image behind the footer. The corresponding HTML and some sample inline CSS that work with the above routine is listed below.

<div id="divWrapper" style="background: url(images/contentbg.gif) top left repeat-y; overflow: auto; position: relative; width: 100%;">
  <div id="divContent">
    <!-- Here is where the content goes. -->
  </div>
  <div id="divPreFooter" style="height: 1px; overflow: hidden; position: relative;"> </div>
</div>
<div id="divFooter" style="background: url(images/footer.gif) top left no-repeat; height: 80px; overflow: auto; position: relative; width: 100%;">
  <!-- Footer Content goes here -->
</div>

It works not only with shadows on repeating backgrounds, but also rounded corners or any type of alpha transparency on repeating backgrounds. It is much easier than trying to use images with alpha transparency in IE6, and it doesn’t use very many DIVs. This has been tested in the following browsers:

  • IE6
  • IE7
  • Firefox
  • Opera
  • Safari

EDIT (12/22/2008): I have added a complete example that is listed below. I have also tweaked some of the above code, so that it matches the specific example below.

<html>
<head>
<title>Test</title>
<script type="text/javascript" language="javascript">
function addEvent(elm, evType, fn, useCapture) {
  if (elm.addEventListener) {
    elm.addEventListener(evType, fn, useCapture);
    return true;
  }
  else if (elm.attachEvent) {
    var r = elm.attachEvent('on' + evType, fn);
    return r;
  }
  else {
    elm['on' + evType] = fn;
  }
}

function fixHeight() {
  var resizeElement = document.getElementById('divPreFooter');
  var containerElement = document.getElementById('divWrapper');
  var divisibleBy = 10;
  var resizeOffset = 0;

  if (containerElement.clientHeight % divisibleBy != resizeOffset)
    resizeElement.style.height = ((divisibleBy - ((containerElement.clientHeight - resizeElement.clientHeight) % divisibleBy) + resizeOffset) % divisibleBy).toString() + 'px';
}

addEvent(window, 'resize', fixHeight, true);
addEvent(window, 'load', fixHeight, true);</script>
</head>
<body>
<div id="divWrapper" style="background: url(images/contentbg.gif) top left repeat-y; overflow: auto; position: relative; width: 100%;">
  <div id="divContent">
    <p style="color: #FFF; padding-left: 50px;">Here is the content.</p>
    <!-- Here is where the content goes. -->
  </div>
  <div id="divPreFooter" style="height: 1px; overflow: hidden; position: relative;"> </div>
</div>
<div id="divFooter" style="background: url(images/footer.gif) top left no-repeat; height: 80px; overflow: auto; position: relative; width: 100%;">
  <p style="color: #FFF; padding: 30px 50px 0px;">Here is the footer.</p>
  <!-- Footer Content goes here -->
</div>
</body>
</html>

A zip file of the above sample code with the background images can be downloaded here.

CSS Reset

By Nick Little on November 25, 2008 at 6:30 am in css

A good CSS reset is a must-have in terms of website design. A CSS reset file sets basic styles so that they will be consistant amongst all the major browsers. For example, most browsers display headings (h1, h2, h3…) at slightly different sizes. A reset file can make them the same size across major browsers, using h3 { font-size: 150%; } or h3 { font-size: 20px; } or something similar.

Using a reset helps a lot with consistent display. Since all the styles have been reset, there are fewer browser inconsistencies that can plague websites. I have found this to be especially true when dealing with headings, lists, and tables. These seem to be the most inconsistent amongst browsers.

Here are several good websites that offer good resets. They offer everything from just the basic resets that cover all major browsers to a complete reset that removes almost every style from almost every browser one can think of.

Easy Guide To CSS Drop Down Menus

By Nick Little on November 4, 2008 at 2:31 pm in css,html

Drop down menus are one of the most useful tools in a website. They can make a big site very easy to navigate through. However, for the web developer they can seem like such a daunting task. This short tutorial can help anyone get started with a simple drop down. The drop down will work in all current browsers (Opera, Safari, Firefox, Chrome, and Internet Explorer 6+) if done correctly. IE will need a little bit of help using javascript.

The first thing to do when creating a CSS drop down is to write the corresponding HTML or XHTML. I have seen many people use DIV tags to code drop down menus. However, I would argue that the best menu, including drop down menus, is always a list. Here is how we should start our list:

<ul id="mainmenu">
  <li><a href="#">First Link</a></li>
  <li><a href="#">Second Link</a>
    <ul>
      <li><a href="#">Drop Down One</a>
      <li><a href="#">Drop Down Two</a>
    </ul></li>
  <li><a href="#">Third Link</a></li>
</ul>

Next, we need to add a little bit of javascript to the head tag to make sure that IE7 and below will work correctly. Note that since we are adding javascript for the drop down and the CSS for the drop down may not work in all older browsers, it is highly recommended that you still include all the subitem links on the item page. (ie. Include links to “Drop Down One” and “Drop Down Two” on the “Second Link” page.) The javascript tells IE and below to add “hover” to class attribute when mouse hovers over a list item, since it doesn’t support the :hover modifier for list items inherently.

<!--[if lte IE 7]>
<script language="javascript" type="text/javascript">
function makeDropDownMenu(ul) {
  var lis = ul.getElementsByTagName('li');

  for (var i = lis.length - 1; i >= 0; i--) {
    lis[i].onmouseover = function() { this.className += ' hover'; };
    lis[i].onmouseout = function() { this.className = this.className.replace(new RegExp('\\bhover\\b'), ''); };
  }
}

function loadIEHover() { makeDropDownMenu(document.getElementById('mainmenu')); }
window.attachEvent("onload", loadIEHover);
</script>
<![endif]-->

And now for the fun part! Styling the drop down with CSS can be a tricky process at first. Here are a few basic suggestions for troubleshooting your CSS if it does not work:

  • Know the cascading rules for cascading style sheets and make sure that one of your previous rules for the drop down is not overriding the rule that is not working.
  • Make sure that everything is positioned absolutely and that overflow is set to visible.
  • Make sure that you have overridden any default browser styles and/or styles used by the rest of the site (especially margin and padding).

If your drop down is not working the way you think then one of the above suggestions will probably be the answer. At least those were the issues that I regularly ran into the first few times I designed drop down menus. Below is some sample CSS that can at least help get you started. Note that many times IE6 and sometimes IE7 will need different styles than more standards compliant browsers.

<style type="text/css">
body { background: #A9DEEF; }
#mainmenu { margin: 0px; padding: 0px; overflow: visible; position: relative; }
#mainmenu li { background-image: none; display: inline-block; min-height: 15px; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; }
#mainmenu li a { color: #444; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; font-weight: bold; text-decoration: none; text-transform: uppercase; }
#mainmenu li a:hover { color: #000; }

#mainmenu ul { background: #000; left: -9999px; margin: 0px 0px 0px -63px; opacity: 0.8; padding: 0px; position: absolute; top: 15px; width: 127px; z-index: 1; }
#mainmenu ul li { border-top: 1px solid #FFF; display: block; margin: 0px; padding: 0px; }
#mainmenu ul li.First, #mainmenu ul li:first-child { border-top: none; }
#mainmenu ul li a { color: #CCC; display: block; font-size: 10px; font-weight: normal; padding: 5px 15px; text-decoration: none; text-transform: none; }
#mainmenu ul li a:hover { color: #FFF; text-decoration: underline; }
#mainmenu li:hover ul, #mainmenu li.hover ul { left: 50%; }
</style>
<!--[if lte IE 7]>
<style type="text/css">
#mainmenu li { display: inline; }
#mainmenu ul { filter: alpha(opacity=80); }
#mainmenu ul li a { display: block; }
</style>
<![endif]-->

Putting it all together, we have:

<html>
<head>
<title>Drop Downs are Awesome!</title>
<style type="text/css">
body { background: #A9DEEF; }
#mainmenu { margin: 0px; padding: 0px; overflow: visible; position: relative; }
#mainmenu li { background-image: none; display: inline-block; min-height: 15px; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; }
#mainmenu li a { color: #444; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; font-weight: bold; text-decoration: none; text-transform: uppercase; }
#mainmenu li a:hover { color: #000; }

#mainmenu ul { background: #000; left: -9999px; margin: 0px 0px 0px -63px; opacity: 0.8; padding: 0px; position: absolute; top: 15px; width: 127px; z-index: 1; }
#mainmenu ul li { border-top: 1px solid #FFF; display: block; margin: 0px; padding: 0px; }
#mainmenu ul li.First, #mainmenu ul li:first-child { border-top: none; }
#mainmenu ul li a { color: #CCC; display: block; font-size: 10px; font-weight: normal; padding: 5px 15px; text-decoration: none; text-transform: none; }
#mainmenu ul li a:hover { color: #FFF; text-decoration: underline; }
#mainmenu li:hover ul, #mainmenu li.hover ul { left: 50%; }
</style>
<!--[if lte IE 7]>
<script language="javascript" type="text/javascript">
function makeDropDownMenu(ul) {
  var lis = ul.getElementsByTagName('li');

  for (var i = lis.length - 1; i >= 0; i--) {
    lis[i].onmouseover = function() { this.className += ' hover'; };
    lis[i].onmouseout = function() { this.className = this.className.replace(new RegExp('\\bhover\\b'), ''); };
  }
}

function loadIEHover() { makeDropDownMenu(document.getElementById('mainmenu')); }
window.attachEvent("onload", loadIEHover);
</script>
<style type="text/css">
#mainmenu li { display: inline; }
#mainmenu ul { filter: alpha(opacity=80); }
#mainmenu ul li a { display: block; }
</style>
<![endif]-->
</head>
<body>
<ul id="mainmenu">
  <li><a href="#">First Link</a></li>
  <li><a href="#">Second Link</a>
    <ul>
      <li><a href="#">Drop Down One</a>
      <li><a href="#">Drop Down Two</a>
    </ul></li>
  <li><a href="#">Third Link</a></li>
</ul>
<p>This is a test paragraph below the menu.</p>
<p> </p>
</body>
</html>

Each drop down is different, but the underlying principles and most of the base code is the same. As you deesign more and more drop downs you will come across more and more oddities in browsers that do not work the way you think. Thankfully, with more experience also comes the ability to troubleshoot the problems a lot quicker.

My Favorite Web Development Tools

By Nick Little on October 14, 2008 at 6:30 am in Development

There are several tools that I don’t think I could do web development without. They give me the power to find out valuable information about the pages I’m viewing. They even let me edit the HTML and CSS directly, without having to refresh the browser window! I can debug JavaScript, test the page with different viewport sizes, view the size of every file loaded by the browser, and much more. All these tools are plugins for the Firefox web browser. Let’s take a closer look at these invaluable tools.

  • Web Developer Toolbar – This toolbar gives me options for disabling everything from css to browser cache to images to cookies. It also has very nice options for filling out forms and viewing just about anything I could possibly want to know about certain elements on the page. I can resize the viewport and make sure I have no CSS or JavaScript errors with a simple glance at the toolbar.
  • Firebug – This nifty little plugin is extremely useful. I can highlight any element on the page with a single click of the mouse. I can then view and change all the CSS related to the element. I can also view the DOM properties and functions of an element. I can debug javascript by setting breakpoints in the code. Firebug even lets me edit the HTML of the page and also tells me how much bandwidth is used in retrieving each file. (My favorite thing to do is edit pages so they make fun of Tim!)
  • Google Toolbar – Lastly, Google Toolbar, although it’s not technically a web development tool, is very useful. I use it to manage all my bookmarks, so when I find something web development related at home I add it to my google bookmarks and I have it the next day at work. I can also search anywhere on google.com (Google Images, Google Maps, etc) or even the current page very quickly.

These are all excellent tools that I use on a daily basis, but by no means are they the only tools. I have tinkered with several excellent widgets for Opera that do almost the same things. There are many tools out there no matter what browser you use for development.

Min-height, Min-width, & IE6

By Nick Little on September 17, 2008 at 6:30 am in css,General,Technical

There is a way to get elements in IE6 to have a min-height and a min-width. However, both require hacks that isolate IE6 from other browsers. We’ll start with the easy one.

Min-height can be achieved in IE6 by using a conditional HTML comment and the height CSS property. It turns out that Microsoft decided that the height CSS property in IE6 and below should actually be the minimum height. We can put this inside a style tag in the HTML comment after the initial CSS. This way all other browsers will not see the CSS.

<style type="text/css">
  .minheightclass { min-height: 100px; }
</style>
<!--[if lte IE 6]>
<style type="text/css">
  .minheightclass { height: 100px; }
</style>
<![endif]-->

Make sure that the element with the min-height does not have overflow: auto. It will not work in that case. You will need to override the overflow in the IE6 conditional comment in order for it to work.

Min-width in IE6 is a little bit trickier and it requires javascript to be enabled. We will still use the conditional HTML comment, but we will have to add a Microsoft proprietary CSS expression. A CSS expression allows some javascript code to dynamically determine the value of a CSS property. We will apply the expression to the width property.

<style type="text/css">
  .minwidthclass { min-width: 350px; }
</style>
<!--[if lte IE 6]>
<style type="text/css">
  .minwidthclass { width: expression(this.clientWidth > 350 ? "100%" : "350px"); }
</style>
<![endif]-->

Be careful when using this hack as it can cause the browser to lock up if you get the values wrong.

Keeping N’sync with Apple Mail

By Nick Little on September 3, 2008 at 6:30 am in Email,Mac,Technical

One of the most difficult and annoying things to set up in a small business is email. There are so many different options that it can be frustrating to even attempt to configure email. What’s the difference between IMAP and POP3 anyways? I’ve seen people just type in their email address and it works. Why doesn’t mine work like that? I will attempt to answer some of those questions in this post.

There are three main email retrieval protocols in use:

  • Exchange – This is a proprietary mail protocol used by Microsoft to receive email from an Exchange Server. Support for this protocol is heavily integrated into Outlook. It is the easiest to set up. Simply enter your email address and password and Outlook takes care of almost everything else for you. In addition to easy set up, the Exchange protocol allows an Outlook client to be connected constantly to the Exchange Server, so any email received by the server when almost instantly be sent to the user. This means that you will know you have an email the instant it has been received.
  • IMAP – IMAP stands for “Internet Message Access Protocol.” It is very similar to the Exchange protocol, with the exception of the set up. It, like the Exchange protocol, allows messages to be retrieved the instant they are received, but it is harder to set up. In addition to email and password, you will need to know the mail server, your username to connect to the server, and whether or not the server uses SSL.
  • POP3 – POP3 stands for “Post Office Protocol version 3.” It is very different from the other two. It requires just as much information to set up as IMAP, but it does not maintain an active connection to the server. Meaning that it only checks every few minutes to see if any new mail has been received. Another limitation of POP3 is that it doesn’t allow messages to be marked as read on the server. Meaning that if you check your email with an email client on one computer, read, and delete some email messages and then you check it using a different computer, you will have to go through the same messages you went through before. This is extremely annoying, even more so the more computers you check the email with. The one advantage to this is that every computer will always have every email you received.

The one problem with IMAP is that it every email that you delete is deleted from the server. Most people want to have one copy of every email they have received for reference. The problem is that many mailboxes limit the size of the mailbox so that once it is full they can no longer receive new messages (POP3 doesn’t have to worry about this, since most email clients are set to remove the message from the server after a few days). To get around this we need to have a way to move old email off the server and into a different folder. This can be done in almost every email client using offline folders. I will show you how to do it in Apple Mail.

The first thing you will need to do is create a folder to store the old messages. Click Mailbox -> New Mailbox… and add the mailbox to On My Mac. Once the mailbox has been added, create a rule (Preferences -> Rules -> Add Rule) that will move old mail into it when it was received or sent a certain number of days ago. Under “Perform the following actions” select that you want to move the message to your new folder.

This archiving method allows you to get all the advantages that come with IMAP (not having to delete every junk email from your work computer, home computer, and iPhone, individually) along with the advantages of POP3 (being able to keep all your email messages in case you need to reference them later). It also keeps the number of emails in your inbox way down, depending on how many days you choose to wait before archiving your messages.

Open Source Web Design

By Nick Little on August 25, 2008 at 6:30 am in General,Link Roundup

I have always wondered what open source tools are out there for web design just in case I decide to boycott Adobe or Adobe goes bankrupt or something. It turns out there are some pretty good options for web design. None of them are quite as good as Fireworks or Dreamweaver, but they do get pretty close at least for the classic Apache, MySQL, PHP setup.

The best PHP editor actually turned out to be the best CSS and Javascript editor I could find as well. They are actually plugins to one of the best open source IDEs (Integrated Development Environments) available, Eclipse. Eclipse can be downloaded from www.eclipse.org.The plug-ins for PHP, CSS, and Javascript are PHP Development Tools, CSS Eclipse Plug-in, and JavaScript Editor Eclipse Plug-in, respectively. The PHP Plug-in was designed to work with XAMPP, a cross-platform Apache, MySQL, PHP, Perl distribution.

Last, but not least we have the GIMP. It is by far the most popular open source image editing application. It lacks many of the features of Photoshop, but most can be accomplished using either plug-ins or a combination of steps. Exporting images using slicing is much more difficult than using Fireworks, but it can still be done.

Using open source software would not be my first choice, but if something happened where I did not have access to Adobe products I would still be able to be productive.

Rounded Corners with Alpha Transparency, Dynamic Height, & Dynamic Width

By Nick Little on August 15, 2008 at 6:30 am in css,General,html

Have you ever wanted to create rounded corners with alpha transparency, but didn’t think you could get it to work in IE6? Believe it or not, it can be done. It requires quite a bit of HTML, but this is a sacrifice that must be made in order for the alpha transparency to work.

First, we must separate the box into three sections: top, middle, and bottom. The top and bottom must be separate from the middle if you plan on having a full background behind all the content in the box. This way the transparency on the corners will not show the background from the middle section. I divided this into three separate DIVs:

<div class="ContentTop"></div>
<div class="ContentMiddle"></div>
<div class="ContentBottom"></div>

Next, we need to add several DIVs inside the top and bottom sections that will act as the corners and center section(s). (We may need more than one center section if there is a repeating background with a shadow as shown in the image on the right.) We also need to apply styles to these corners and sections. For starters, we know that the left and right corners must be the same size as the background images, since this is the only way to get IE6 to properly display alpha transparency. We will use absolutely positioned DIVs to achieve this. Listed below is the code for all browsers except IE6. The code for IE6 will be shown last. However, we still need to consider the shortcomings of IE6 when designing the rounded corners.

<div class="ContentTop"><div class="ContentTopLeft"></div><div class="ContentTopRight"></div><div class="ContentTopCenter"></div></div>
<div class="ContentMiddle"></div>
<div class="ContentBottom"><div class="ContentBottomLeft"></div><div class="ContentBottomRight"></div><div class="ContentBottomCenter1"></div><div class="ContentBottomCenter2"></div></div>

<style>
  .ContentTop, .ContentTopLeft, .ContentTopRight, .ContentTopCenter { height: 47px; }
  .ContentTop { position: relative; padding: 0px 42px 0px 38px; }
  .ContentTopLeft { background: url(images/contenttopleft.png) bottom left no-repeat; left: 0px; position: absolute; top: 0px; width: 38px; }
  .ContentTopRight { background: url(images/contenttopright.png) bottom right no-repeat; position: absolute; right: 0px; top: 0px; width: 42px; }
  .ContentTopCenter { background: url(images/contenttop.png) bottom left repeat-x; }
  .ContentBottom, .ContentBottomLeft, .ContentBottomRight, { height: 52px; }
  .ContentBottom { position: relative; padding: 0px 42px 0px 38px; }
  .ContentBottomLeft { background: url(images/contentbottomleft.png) top left no-repeat; left: 0px; position: absolute; top: 0px; width: 38px; }
  .ContentBottomRight { background: url(images/contentbottomright.png) top right no-repeat; position: absolute; right: 0px; top: 0px; width: 42px; }
  .ContentBottomCenter1 { background: url(images/contentbottom.png) top left repeat-x; height: 47px; }
  .ContentBottomCenter2 { background: url(images/contentshadow.png) top left repeat-x; height: 5px; }
</style>

Optionally, there may be a shadow on the right or left of the content. This can be pretty tricky, especially when trying to get it to work in IE6. In fact, it won’t work completely in IE6 when javascript is disabled. I used a shadow on the right. Here is the code:

<div class="ContentMiddle">
  <div class="Content"><!-- Content Goes Here --></div>
  <div class="ContentRight"></div>
</div>

<style>
  .ContentMiddle { height: 1%; overflow: auto; position: relative; padding-right: 5px; }
  .Content { background: url(images/contentbg.jpg) top center no-repeat; padding: 30px; }
  .ContentRight { background: url(images/contentright.png) top right repeat-y; height: 100%; position: absolute; right: 0px; top: 0px; width: 6px; }
</style>

Now, to add in all the IE6 code. We basically replace all the transparent background images with the filter property. We also add in some javascript code to make the right shadow the full height of its container.

<!--[if lt IE 7]>
<style>
  .ContentTopLeft { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contenttopleft.png', sizingMethod='scale'); }
  .ContentTopRight { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contenttopright.png', sizingMethod='scale'); }
  .ContentRight { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentright.png', sizingMethod='scale'); height: expression(this.parentNode.clientHeight + 'px'); }
  .ContentBottomLeft { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentbottomleft.png', sizingMethod='scale'); }
  .ContentBottomRight { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentbottomright.png', sizingMethod='scale'); }
  .ContentBottomCenter2 { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentshadow.png', sizingMethod='scale'); overflow: hidden; }
</style>
<![endif]-->

Finally, putting it all together we have:

<div class="ContentTop"><div class="ContentTopLeft"></div><div class="ContentTopRight"></div><div class="ContentTopCenter"></div></div>
<div class="ContentMiddle">
  <div class="Content"><!-- Content Goes Here --></div>
  <div class="ContentRight"></div>
</div>
<div class="ContentBottom"><div class="ContentBottomLeft"></div><div class="ContentBottomRight"></div><div class="ContentBottomCenter1"></div><div class="ContentBottomCenter2"></div></div>

<style>
  .ContentTop, .ContentTopLeft, .ContentTopRight, .ContentTopCenter { height: 47px; }
  .ContentTop { position: relative; padding: 0px 42px 0px 38px; }
  .ContentTopLeft { background: url(images/contenttopleft.png) bottom left no-repeat; left: 0px; position: absolute; top: 0px; width: 38px; }
  .ContentTopRight { background: url(images/contenttopright.png) bottom right no-repeat; position: absolute; right: 0px; top: 0px; width: 42px; }
  .ContentTopCenter { background: url(images/contenttop.png) bottom left repeat-x; }
  .ContentMiddle { height: 1%; overflow: auto; position: relative; padding-right: 4px; }
  .Content { background: url(images/contentbg.jpg) top center no-repeat; padding: 30px; }
  .ContentRight { background: url(images/contentright.png) top right repeat-y; height: 100%; position: absolute; right: 0px; top: 0px; width: 4px; }
  .ContentBottom, .ContentBottomLeft, .ContentBottomRight, { height: 52px; }
  .ContentBottom { position: relative; padding: 0px 42px 0px 38px; }
  .ContentBottomLeft { background: url(images/contentbottomleft.png) top left no-repeat; left: 0px; position: absolute; top: 0px; width: 38px; }
  .ContentBottomRight { background: url(images/contentbottomright.png) top right no-repeat; position: absolute; right: 0px; top: 0px; width: 42px; }
  .ContentBottomCenter1 { background: url(images/contentbottom.png) top left repeat-x; height: 47px; }
  .ContentBottomCenter2 { background: url(images/contentshadow.png) top left repeat-x; height: 5px; }
</style>

<!--[if lt IE 7]>
<style>
  .ContentTopLeft { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contenttopleft.png', sizingMethod='scale'); }
  .ContentTopRight { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contenttopright.png', sizingMethod='scale'); }
  .ContentRight { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentright.png', sizingMethod='scale'); height: expression(this.parentNode.clientHeight + 'px'); }
  .ContentBottomLeft { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentbottomleft.png', sizingMethod='scale'); }
  .ContentBottomRight { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentbottomright.png', sizingMethod='scale'); }
  .ContentBottomCenter2 { background-image: none; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/contentshadow.png', sizingMethod='scale'); overflow: hidden; }
</style>
<![endif]-->

Happy Coding!

Replacing Querystring Values in URLs

By Nick Little on August 6, 2008 at 6:30 am in General,Technical

There are many times in a programmer’s career when regular expressions are extremely useful. Sadly, many programmers do not know regular expressions well enough to use them when the situation requires it. This post shows how easy it is to replace the contents of querystring variables in a URL using regular expressions.

function replaceQueryString($url, $key, $value = NULL)
{
  $url = ereg_replace('[\?&]'.$key.'=[^&#]*(#?)', '\\1', ereg_replace('([\?&])'.$key.'=[^&#]*&', '\\1', $url));

  if ($value === NULL)
    return $url;
  else if (($pound = strpos($url, '#')) === false)
    return $url.(strpos($url, '?') === false ? '?' : '&').$key.'='.urlencode($value);
  else
    return substr($url, 0, $pound).(($question = strpos($url, '?')) === false || $question > $pound ? '?' : '&').$key.'='.urlencode($value).substr($url, $pound);
}

The first line of the function uses regular expressions to remove the existing query string value from the url. Next, the correct point of entry is found for the new value to be inserted. Finally, the new value is inserted into the url. All that in under ten lines of code.

SQL Many-to-Many Relationships

By Nick Little on July 28, 2008 at 10:47 am in General,sql,Technical

Occasionally when working with database relationships one will come across an instance of a many-to-many relationship. This type of relationship can occur, for example, when multiple users can be assigned to multiple tasks with users being assigned multiple times. This type of relationship should be implemented as three separate tables as shown below.

Users

userid username phone
1 me 867-5309
2 you 555-5555

Tasks

taskid name description
1 Blog Write a blog entry and post it on the T&S Blog.
2 Create a new website. One person design the site. The other person write the html/css for the site.

Taskassignments

assignmentid taskid userid
1 1 1
2 2 1
3 2 2

Now, it is possible to join these tables in a single SQL statement. However, the resulting set would most likely contain many duplicate entries. There is a way in mysql to get the entries in two SQL statements without duplicating even a single entry. This is done using mysql’s GROUP_CONCAT function. This function is used to return many entries that relate to one entry on a single row. For example:

SELECT userid, GROUP_CONCAT(taskid) tasks FROM Taskassignments GROUP BY userid

would return

userid tasks
1 1,2
2 1

The next step from here would be to change the SQL statement so that it joins with the “Users” table.

SELECT userinfo.userid, tasks, username FROM Users userinfo INNER JOIN (SELECT userid, GROUP_CONCAT(taskid) tasks FROM Taskassignments GROUP BY userid) tasksassigned ON userinfo.userid = tasksassigned.userid

This retrieves the username instead of just the userid. (Now the user can be referred to as “Bob” rather than “User 12″.)

Now that the users have been retrieved from the database, all the associated tasks must be retrieved without duplicating entries. How can this be achieved? All the task ids must be parsed and stored so they can be retrieved from the database. In php this is simply a few lines of code:

$ids = array();
while ($row = mysql_fetch_assoc($result1)) {
  foreach (explode(',', $row['tasks']) as $id) {
    if (!in_array($id, $ids))
      $ids[] = $id;
  }
}

Lastly, all the tasks are retrieved from the “Tasks” table.

if (count($ids) > 0)
  $result2 = mysql_query('SELECT * FROM Tasks WHERE taskid = '.implode(' OR taskid = ', $ids);

And the tasks are correlated to the proper users, so the results can be displayed.

$tasks = array();
if (isset($result2))
  while ($row = mysql_fetch_assoc($result2))
    $tasks[$row['taskid']] = $row['name'];

mysql_data_seek($result1, 0);
while ($row = mysql_fetch_assoc($result1)) {
  echo htmlspecialchars($row['username']).' has the following tasks:
<ul>';
  foreach (explode(',', $row['tasks']) as $taskid)
    echo '<li>'.htmlspecialchars($tasks[$taskid]).'</li>';
  echo '</ul>';
}
Older Posts »