Omnibus

Advanced HTML Tables: Columns

Last week, we discussed table basics for the year 2010 (as opposed to 1995). We set up a simple semantic table with a caption, header and footer. Today, we’re going to go over two lesser-known elements: the colgroup and col elements. I had grand plans of going into some little-known attributes for other table elements, but we’ll leave that to next week.

So, my columns feel left out

In the last article, you saw how thead, tfoot and tbody allowed for groupings of rows in a table. But often times, it’s useful to group columns as well. A couple uses I can think of include highlighting a totals column or perhaps a sales option that you want to promote. Other uses include the ability to set explicit widths for individual columns without much extra markup.

So, where do these elements go? When using column and column-group elements, you place the tags after the caption but before any row-groups or rows in the table. Modern user agents will then determine which cells belong to the appropriate column or column-group.

<table>
    <caption>Elements To Use in Proper Tables</caption>
    <colgroup span="2" width="100px">
        <col width="90px" />
        <col class="attribs" />
    </colgroup>
    <colgroup span="1" width="0*"></colgroup>
    <thead>
    ... 

colgroup: grouping columns

As you may have guessed by the “group” part of the element name, colgroup designates a structural grouping of columns. Semantically, you’re saying that the columns are related somehow.

col: sharing attributes without structural grouping

Unlike colgroup, col does not specify structure, it merely allows you to share attributes across multiple columns. In fact, for purists, one might argue that col is purely layout-driven. I’ll let you judge of that on your own.

Only two attributes?

The use of colgroup and col in HTML is limited to two attributes: span and width.

Span specifies the number of columns the group encompasses for colgroup or the attribute should apply to in the case of col. When using these two elements, make sure that the number of elements and their span attributes don’t equal more than the number of cells you have per row.

Width allows you to set the width of a column or columns in a column-group. When used in colgroup elements, remember that it specifies width of each column in the group not the total width of the grouping. If a child col also has width set it will override the parent colgroup setting. General width values are accepted, but there’s also a strange format available: the zero-asterisk (0*) value, which sets each column to be the minimum width needed to display the full cell content. You can also use an asterisk with a numerical value to designate proportional widths. For instance, if you want three columns to be set up proportionally, you could designate them as such:

<colgroup span="2" width="100px"></colgroup>
    <colgroup span="3">
        <colgroup width="1*" />
        <colgroup width="4*" />
        <colgroup width="2*" />
    </colgroup>
    <thead>
    ... 

That structure would take the total remaining width after assigning 100px to the first two columns, divide it into seven portions (1+4+2 = 7), and then apply the correct width based on portion width multiplied by number of designated portions.

Beyond these two attributes, you can use most common attributes such as id, class, align, etc.

Tell me about styling.

Here’s the drawback: colgroup and col have limited styling. You can only use four CSS attributes, and even they are limited:

  • background: you can set a background, but it is only honored if both the row and cell backgrounds are transparent.
  • border: borders work if the table has borders set to collapse (border-collapse: collapse;), at which point the borders appear based on the border conflict algorithm. If the table is set to have separated borders, no dice.
  • width: works as expected, no explicit limitations.
  • visibility: will only work with the collapse value.

But despite the limitations, these two elements can come in handy for informative tables. Let’s put it together with our table code from last time:

<table id="elements-for-tables">
    <caption>Elements To Use in Proper Tables</caption>
    <colgroup span="2" width="100px">
        <col width="90px" />
        <col class="attribs" />
    </colgroup>
    <colgroup span="1"></colgroup>
    <thead>
         <tr>
             <th>Tag </th>     <th>Attributes</th>     <th>Description</th>
         </tr>
     </thead>
     <tfoot>
         <tr>
             <td colspan="3">* denotes optional child elements</td>
         </tr>
     </tfoot>
     <tbody>
         <tr>
            <th>caption*</th>
            <td>common attributes</td>
            <td>A succinct description or title for the table.</td>
         </tr>
         ...
     </tbody>
</table>

table {
    margin: 1em auto;
    border-collapse: collapse;  /* note that this is required for using border on columns */
    }
caption { font-size: 1.2em; }
th, td {
    padding: .25em;
    border: 1px solid #000;
    font-family: sans-serif;
    }
caption, th {
    color: #004900;
    font-weight: bold;
    text-align: left;
    }
thead tr, tfoot tr { background-color: #aaa; }
thead th {
    border-bottom: 3px double #000;
    background-color: #ccc;
    text-align: center;
    }
tfoot td {
    border-top: 3px double #000;
    color: #333;
    font-style: italic;
    font-size: .8em;
    text-align: right;
    }
tbody th { color: #000; }
col.attribs {
    background-color: #B6FFBD;
    border: 2px dotted #004900;
}

The result:

Elements To Use in Proper Tables
Tag Attributes‡ Description
* denotes optional child elements
† denotes tags to be discussed in part two, next week.
‡ only tag-specific attributes are included. In general common attributes are also allowed. See the W3C HTML 4.01 Attribute Table for a complete list.
caption* A succinct description or title for the table.
colgroup* span, width A way to group columns for semantic accessibility, progressive enhancement and styling.
col* span, width A child element of colgroup, used to share attributes amongst multiple columns.
thead* A group of rows comprising a header for the table.
tfoot* A group of rows comprising a footer for the table.
tbody* A group of rows comprising the body of the table. There can be multiple tbody elements.
tr A table row. If thead, tfoot, and tbody are not used, this will be a child element of the table, otherwise it is a child element of the rowgrouping elements.
th* †abbr, axis, colspan, headers, rowspan, scope A table heading. A child element of tr. Most commonly used to signify column headings when used in a thead element, but can be used as a row heading as well.
td †abbr, axis, colspan, headers, rowspan, scope, Table data. A child element of tr. The most numerous element in a table, it contains data.

Notice the funky border collapsing in the footer and that the heading background color overrides the column background color. But don’t let that limit you: be creative, and you can accomplish great feats.

Just think of how that could be useful in extremely large data sets, accounting tables, or product tables. The possibilities are endless. Next week, we’ll discuss attributes galore for semantic, accessible table creation.

Great Time to Start an IRA

“You’re in your early 20s. That’s too early to start thinking about retirement.” Wrong. So completely wrong. Now is the best time to think about retirement. Sure, it’s a long way off, but even a small percent of your salary can mean a nice bit of savings in the long run thanks to the power of compounding interest.

Start an IRA

I was inspired to write this post because ING/Sharebuilder is offering FREE automatic investments for the year when you start a new IRA with them before 15 Apr 2010. I already have a Roth IRA with them, but I decided to start another one. Those normal $4 commissions really add up and put a dent in returns, especially when saving as little as I am, and if I can get all of those transfers for free for a year, well, I’m gosh darn gonna try! The promotion applies to both Roth and Traditional IRAs as well as Rollover Roths.

If you’re not interested but are considering opening up a non-IRA account with them, leave a comment to that affect and I’ll pass along a referral that nets me five free investment trades and you $25 to invest.

Why?

As I said, compounding interest is amazing for growing money. I started my Roth IRA just a few months before my 23rd birthday. There’s not a lot of money in there, because I only put in $50/month right now while I pay off debt. At $4/trade, that’s a lot of fees in relation to the investment, so I started doing the investment every other month at $100 for now, until I can bump up my monthly contribution. But let’s run some numbers about what I’m gaining by even my paltry investment.

In my calculations I’m considering a really low return: 5%. Historically, smartly invested funds will net about 10% in the market over the time we’re talking about before retirement. At 5%, we should barely beat inflation. But, this requires investing in the market or things like bonds, not letting it sit in your local bank savings account or CD.

Effect of Compound Interest
Starting age Monthly investment Money invested Interest earned Total value at age 65 Monthly to match age 23 Increased investment Interest earned
I’m rounding. Numbers aren’t precise, but close.
23 $50.00 $25,200 $60,724 $85,500
33 $50.00 $19,200 $28,236 $47,436 $ 90.00 $34,560 $50,940
43 $50.00 $13,200 $10,867 $24,067 $178.00 $46,992 $38,508
53 $50.00 $ 7,200 $ 2,679 $ 9,879 $433.00 $62,352 $23,148

I’m using simple math here. Compounding annually, ignoring inflation, conservative return, ignoring commissions.

What does this show us? By saving $50 a month in an investment vehicle that is only returning 5%, starting at age 23, you get over $60,000 interest on top of your principal. If you wait 10 years, starting at age 33, that free money shrinks to only a little over $28k. Meanwhile, if you plan to have $85,500 in the bank at 65 like you would had you started at 23, you’ll have to bump up your monthly contribution to $90, and you’re still losing out on $10k in interest. And that return shrinks exponentially the longer you wait.

If you don’t believe me, play around with this calculator. It’s simple, but simplicity at it’s best: it’s very clear about the differences between starting now and starting later, with nothing fancy to confuse the fact.

N.B. The savings I’m talking about here is on top of any employer-based retirement plan if one with matching is available. If you’re not already contributing enough to get the employer match if you have one, you’re doing things wrong. Obviously, saving $50/month for retirement isn’t going to secure you a nest egg. Even my full retirement savings, currently around 7.6% of my income including a 3% employer match won’t set me up for retirement. I know I have to step it up once I pay down debt. But based on these numbers, the money I’m saving now is miles beyond better than saving nothing, don’t you think? So, why not start now?

But, I’m in debt!

I argue that even being in debt is no excuse not to start saving. With a caveat: If you’re so in debt that you’re paying minimum balances, pause retirement savings. You need to set up a budget, forgo some luxuries and pay off debt so that you can start saving. But I’m not a financial adviser. If you really are struggling that much, you need to go see one.

How to Use the Table Element Correctly

First, how not to use the table element: as a layout tool. Repeat after me: “Tables are for tabular data. Tables are for tabular data. I will not use tables for laying out a Web page. Tables are for tabular data.” So, now that we’ve gotten that bit out the way, let’s talk about what comprises a semantic, valid table. This is basic table creation 101. Next week, we’ll talk about advanced table features.

Forget the old paradigm

Remember back in the day when this was a complete table? Perhaps one you used as a layout tool? Or one you’ve seen recently in live code and then cried a little inside?

<table>
     <tr>
        <td>
            Hi! I’m some table content. In poorly-developed sites, this might actually be where all of the site content is!
        </td>
    </tr>
</table>

Great. Enough nostalgia. That is not an OK table for 2010.

The new paradigm: semantic, accessible, complete

What was that mantra? “Tables are for tabular data.” When presenting tabular data, we need some more information about that data. Modern HTML tags help us out there. First, let’s talk about what information we need for a good data table.

Distinction between headings (<th>) and data (<td>)

When you’re looking at a table, some cells are heading information. They don’t describe actual data, they describe what the data is. Those cells are table headings (th).

Of course, the bulk of the table cells are table data (td).

You should use the correct cell element for the right type of information.

A title (<caption>)

Your users need to be able to look at the table and know what it’s about. A descriptive, succinct title helps with that.

Important notes:

  • <caption> must be the first child element of the table.
  • There can only be one <caption> element inside of a table.
<table>
    <caption>Elements To Use in Proper Tables</caption>
    ...

Headings (<thead>)

We talked about using <th> element above, now let’s talk about where to use them. Short answer: mostly in the <thead> element.

The <thead> element is one of three rowgroup elements (the others are <tfoot> and <tbody>—more on them later). It gives semantic meaning to a grouping of rows, saying “these rows are the heading of the table.” Combining it with <th> elements allows you to create a semantic section to describe columns.

Important notes:

  • The <thead> element isn’t required, however any data that deserves to be in a table deserves to have headings, right? So semantically, you should use it. And again, don’t forget about its use in selectors for progressive enhancement and CSS.
  • An empty <thead> is invalid. It must contain a <tr> and the same number of header or data cells as the body of the table.
  • You can use <td> elements in it, but again, remember the distinction between those and <th>. Chances are, you’re definining a heading in the <thead>.
<table>
    <caption>Elements To Use in Proper Tables</caption>
     <thead>
         <tr>
             <th>Tag </th>     <th>Attributes</th>     <th>Description</th>
         </tr>
     </thead>
    ... 

Table Footer (<tfoot>)

The second of three rowgroup elements, the <tfoot> element designates a group of table row elements as the footer. I can’t harp on about how you should use the <tfoot> element in every. Single. Table. Because, I admit, you don’t always need a footer for data. Semantically, it can have a few different uses. I use it for things like a total line, footnotes for data, etc. Like <thead>, it’s not a required child element.

Important notes:

  • An empty <tfoot> is invalid. It must contain a <tr> and the same number of header or data cells as the body of the table.
  • It must come before the <tbody> element(s). Straight from the W3C:

    <tfoot> must appear before <tbody> within a <table> definition so that user agents can render the foot before receiving all of the (potentially numerous) rows of data.

    In other words, if you have a lot of data, the <tfoot> should be rendered before all of the data.

  • The <tfoot> should be displayed after all <tbody> elements, despite the fact that it appears before them in the code. However, this is sadly untrue for some older user agents and most HTML as PDF rendering vehicles. It sucks, but those older clients’ use is decreasing, at least.
<table>
    <caption>Elements To Use in Proper Tables</caption>
     <thead>
         <tr>
             <th>Tag </th>     <th>Attributes</th>     <th>Description</th>
         </tr>
     </thead>
     <tfoot>
         <tr>
             <td colspan="3">* denotes optional child elements</td>
         </tr>
     </tfoot>
    ...  

Table Body (<tbody>)

The final rowgroup element, <tbody> defines the body of your table—the section that contains all of your data. There can be multiple <tbody> elements in the table, if such a grouping makes sense for your data.

Important notes:

  • In any table that uses <thead> and <tfoot> elements, <tbody> is required. Otherwise, it is implicit. You should include it anyway.
  • For the most part, <tbody> will contain a bunch of <td> elements nested inside of <tr> elements. <th> elements are also appropriate if you want to add a heading for that row.
  • Using multiple <tbody> elements is not appropriate for zebra-striping. That should be a progressive enhancement with Javascript.

So, to wrap it up, code for a complete simple, semantic table will look something like this:

<table id="elements-for-tables">
    <caption>Elements To Use in Proper Tables</caption>
     <thead>
         <tr>
             <th>Tag </th>     <th>Attributes</th>     <th>Description</th>
         </tr>
     </thead>
     <tfoot>
         <tr>
             <td colspan="3">* denotes optional child elements</td>
         </tr>
     </tfoot>
     <tbody>
         <tr>
            <th>caption*</th>
            <td>common attributes</td>
            <td>A succinct description or title for the table.</td>
         </tr>
         ...
     </tbody>
</table>

Using Progressive Enhancement and Styling

The best argument for using complete semantic tables is for progressive enhancement and styling selectors. In the old paradigm, you’d need to add classes everywhere to style things; a class for the headings, a class for the footer, a class for row groups, etc. Instead, view this simple example of styling without any classes using only the elements:


table {
    margin: 1em auto;
    border-collapse: collapse;
    }
caption { font-size: 1.2em; }
th, td {
    padding: .25em;
    border: 1px solid #000;
    font-family: sans-serif;
    }
caption, th {
    color: #004900;
    font-weight: bold;
    text-align: left;
    }
thead tr, tfoot tr { background-color: #aaa; }
thead th {
    border-bottom: 3px double #000;
    background-color: #ccc;
    text-align: center;
    }
tfoot td {
    border-top: 3px double #000;
    color: #333;
    font-style: italic;
    font-size: .8em;
    text-align: right;
    }
tbody th { color: #000; }
Elements To Use in Proper Tables
Tag Attributes‡ Description
* denotes optional child elements
† denotes tags to be discussed in part two, next week.
‡ only tag-specific attributes are included. In general common attributes are also allowed. See the W3C HTML 4.01 Attribute Table for a complete list.
caption* A succinct description or title for the table.
colgroup*† span, width A way to group columns for semantic accessibility, progressive enhancement and styling.
col*† span, width A child element of colgroup, used to share attributes amongst multiple columns.
thead* A group of rows comprising a header for the table.
tfoot* A group of rows comprising a footer for the table.
tbody* A group of rows comprising the body of the table. There can be multiple tbody elements.
tr A table row. If thead, tfoot, and tbody are not used, this will be a child element of the table, otherwise it is a child element of the rowgrouping elements.
th* †abbr, axis, colspan, headers, rowspan, scope A table heading. A child element of tr. Most commonly used to signify column headings when used in a thead element, but can be used as a row heading as well.
td †abbr, axis, colspan, headers, rowspan, scope, Table data. A child element of tr. The most numerous element in a table, it contains data.

Hey, we have some different stuff going on, and not a single styling class to be found! Now, that, my dear readers, is good, modern (X)HTML.

As for progressive enhancement, I’m not going to cover anything here, but things like zebra striping, column sorting, scrolling, etc. are possible with the addition of semantic elements. In fact, in the W3C documentation on HTML tables, they give the following reasons for having <thead> and <tfoot> elements:

This division enables user agents to support scrolling of table bodies independently of the table head and foot. When long tables are printed, the table head and foot information may be repeated on each page that contains table data.

Sounds like a good reason to use semantic tables to me!

Why?

Because it’s good development.

More importantly, having a solid semantic framework for your table makes it better for accessibility, progressive enhancement and styling. It’s the same argument for any semantic, valid code. It’s better. It makes your life easier in the long run. It’s the right thing to do.

Stay tuned for next week, when I expand on the topics we discussed today and show you how to use little-known attributes and a few more elements to really make your tables “pop.” Okay, they won’t pop, per se, but they’ll provide very important instructions for non-visual browser clients and provide a few more hooks for progressive enhancement and CSS styling.

On the Subject of (Not) Learning From Past Mistakes

If past mistakes had taught me anything, I would know this: Back up your data. Often. And make sure it finishes transfer. Having worked in IT for 4 years, and being a Web Developer, I’ve counseled at least high tens, if not hundreds about “Save Early, Save Often,” backing up data, etc. But it seems I can’t take my own advice.

So, I own a Mac. Newer Macs (ones running Leopard or Snow Leopard) have this awesome Time Machine function that backs up your Mac on a daily or hourly basis whenever the external drive is connected the computer. Even cooler is that you can buy a Time Capsule that does it over WiFi. Now, I don’t have anything that fancy, but I do have an external for Time Machine to use, yet, I still just lost about 6 months of data. Why? Because I’m lazy and don’t take my own advice.

The First Time

Two and a half years ago, right after I graduated college, my hard drive died. In some ways, I was happy it wasn’t while I was finishing my last semester, but then again, while I was in college I had anything important for school backed up on the server space they provided. Fresh out of college, working for barely over $9/hr, I had been putting off buying an external in favor of things like food, and paying rent. So, when my hard drive failed as that generation of MacBook’s were wont to do (search the ’net. It was a big to do), I ended up losing about 4 months of data: pictures, final projects, the yearbook (I was editor and essentially only member. Somehow the work had gotten pushed to the summer, rather than during my senior year), etc. See, some old stuff was backed up on an older, full drive, but the newer stuff just wasn’t transferred.

And boy, did it fail miserably, with really bad platter scratching noises. No hope of recovery.

The next night, after I partially recovered from being stunned, I ordered a new external and a replacement drive for the laptop.

This Time

But evidently, I didn’t learn from my mistake. I haven’t been diligent about backing up my data. I did it once a month or so at most. But I was also sharing the new external with Carl, so we maxed out the space pretty quickly. When it came time to reimage my laptop in hopes of solving some issues, and to upgrade to Snow Leopard, I was forced to delete most of my backups, save the very last one, which was a few months old, and then transfer over everything for safe keeping while I restored the machine.

Once the new install was up and running, I transferred everything back, and had to delete most of it from the external to make room for the new backups. Then, I set up Time Machine and let it backup the new system. Or so I thought.

My drive failed last week. I had a bit of a breakdown. Not because I lost data, because here I was thinking that I had a two week old backup of everything (and nothing new really in the mean time). Mostly just because it was the icing on the cake of computer problems recently, and I’m on this new “no more debt, pay for everything in cash” kick, and initially thought the whole computer had died, or that this was fate saying I needed a new computer anyway, and that just wasn’t happening while I’m funneling most of my disposable income paying for past stupid spending mistakes (*take a breath* see, sometimes I do learn). But I got over it, priced out some new drives (a replacement with more space seems to be in the budget, as prices have dropped. I couldn’t even find a 160GB in brick-and-mortar stores), and looked into the warranty on the dead one1, and am using Carl’s personal laptop while I wait for a new drive.

So, while I wait, I have been working on getting some stuff done, like printing photos from Christmas, etc. I plugged in the external to grab those photos, and it was like my own personal horror show: my last backup of my complete new system didn’t actually backup!!!!!!!!!!! (Yes, those exclamation points are needed. For my sanity. Just humor me here.) Luckily, I hadn’t gotten around to deleting everything from my reboot backup, just the folder containing 80% of my personal data and projects. Somehow, the photos and personal Web projects survived, but everything else is gone. Again. The last full backup I have was from August. Thank every deity ever worshiped that I’ve been taking a bit of a break from freelancing and didn’t lose any recent client data. All of that survived in the last backups/on my thumb drive. (Potential clients: I do back up your data in multiple places).

So, the moral of my story is: it’s great to give good advice to other people who need it, but remember to stop for a second and take your own advice. Really, if it’s good enough to give, it’s good enough to practice, right? I really need to remember that in the future.

As for a resolution to my issue, I’m working on that. The drive was under warranty, so I’m doing an RMA there. However Hitachi, the manufacturer, claims that the order will be processed within 14 working days of receiving the defective drive, if the replacement is in stock. So, if the replacement drive is in stock, worst case scenario it could take more than three weeks with processing and shipping times to get a new drive, best case is at least a week and a half. I’m thinking of reworking my budget just a bit and ordering a new drive in the mean time, and selling the RMAed drive once I get it to recoup some of the cost. Still trying to decide what I want to do there. Back to article

Why printf Isn’t Working: PHP String Handling

At one point in time, I spent hours troubleshooting why my argument swapping/repeated placeholders in sprintf/printf statements weren’t working properly. I referred to the PHP docs, the internet, cursed the fact that I was doing back-end coding again, etc., and finally gave up and just repeated my variables using normal, un-numbered conversion specifications. Not once did I see anything that answered my question: “Why am I getting a ‘Too few arguments’ warning when using numbered placeholders?”

So, why am I getting a ‘Too few arguments’ warning when using numbered placeholders?

I (and probably you) was/were/are using a double-quoted string.

The issue here is with how PHP handles the String type. PHP is pretty forgiving about a lot of things, and in many cases single-quoted strings and double-quoted strings work just as well as the other. But there are some very important differences, especially when it comes to special characters, conversion specifications and variables.

If you’re having this same problem, change to using single quotes. Voilà, your problem is probably fixed, as long as you didn’t forget to escape any single quotes within your string.

A little more information on strings

The number one thing to remember when working with single-quoted strings in PHP: the only parsed character is the escaped single quote [\'].

Double-quoted strings will parse many escape sequences, and most importantly will expand variables.

If you’re a visual learner, refer to this example:

print '\nHello $username';
print "\nHello $username";

The above code will produce the following (assuming $username has been set to “World”):

\nHello $username
Hello World

So why is this an issue with printf?

I haven’t actually found a source to explain this or verify my postulate. But, I’d bet money on it, and I’m not a betting woman.

Double-quoted strings expand the conversion specification as a variable before printf even gets a chance to evaluate the code. Visually speaking:

$s = "shoes";
$numchucks = "a";
$noun = "wood";
$verb = "chuck";
printf("How much %1$s would %2$s %1$s-%3$s %3$s...",$noun,$numchucks,$verb);

The above code results in a “Too few variables” warning, and nothing prints because printf is actually getting a string that looks like: “How much %1shoes would %2shoes %1shoes-%3shoes %3shoes... In other words, you’re passing it five valid conversion specifications but only four arguments. If you added in the proper number of arguments, like this:

printf("How much %1$s would %2$s %1$s-%3$s %3$s...",$noun,$numchucks,$verb,$noun,$verb);

The resulting output would be:

How much woodhoes would    ahoes chuckhoes-woodhoes chuckoes…

For those readers who are familiar with only the most basic of conversion specs, %2s is perfectly valid. It reads like: “format as a string [s] at least two characters long [2], using the default padding character [a space] and default alignment [left].” So, as you see with ‘a’, it pads the left of the value with a space (exaggerated in above example with three spaces).

In the above examples, we end up with a (somewhat) sensibly formatted string because our interpreted variable $s started with the letter ‘s’, a valid conversion specification character. You will end up with even weirder results if $s begins with an invalid conversion spec character. Take $s="random"; for example. printf tries to use ‘r’ but as it’s not a valid spec character it just leaves out the conversion specifications

How much andom would andom andom-andom andom…

Even more descriptive is if $s doesn’t exist:

How much would…

So, for future reference, if you want to use numbered conversion specifications, here’s the proper way:

printf('How much %1$s would %2$s %1$s-%3$s %3$s...',$noun,$numchucks,$verb);

And you know, I’ve really always wondered—

How much wood would a wood-chuck chuck…

…if a wood-chuck could chuck wood.

Semantic, Accessible (Good) Forms: the Label Element

One of the most common issues I see with forms is the improper (or lack of) use of label elements. Admittedly, I too am guilty of misuse, but even after becoming aware of them, I was very confused about how to do radio and checkbox elements. Why? I learned incorrectly that the for attribute of the label referred to the name attribute of the input. Wipe that from your memory this instant. The label’s for attribute is a reference to the input’s id.

Wait, back up. What is the label element?

The label element in HTML provides a way to give semantic meaning to the text describing or labeling form control elements. Using the element not only gives you an element to style around your labels, but also provides accessibility and functional advantages.

By using a properly constructed label element along with your input, textarea, or select element, you give

  • screen readers information on which form control the label belongs to,
  • manually maladroit visitors an increased click area (clicking on the label focuses on the element), and
  • yourself a semantic element to target with CSS and Javascript to use in design and enhancement.

Add this element and its use to your list of best practices for forms.

How do I use the label element?

The label element is simple to use and shouldn’t cause any additional headaches while setting up forms. Its usage is simple:

<label for="visitor-email">E-mail address</label>
      <input type="text" name="email" id="visitor-email" size="32" />

It can go either before or after your element. In a real form, you would most likely have the entire line wrapped in a list item or paragraph element, but I left those off for purposes of demonstration.

For checkboxes and radio buttons, the usage is very similar. You provide a label for each individual element, keyed to that element’s id attribute:

<label for="contact-by-email">e-mail</label>
      <input type="radio" name="contact-how" id="contact-by-email"  checked="checked" />
<label for="contact-by-phone">phone</label>
      <input type="radio" name="contact-how" id="contact-by-phone"  />

Incorrect use, a demonstration

The following are improper uses of the label element:

<label>E-mail address</label> <input type="text" name="email" id="visitor-email" size="32" />
In this example, the label does not have a for attribute declared, so its semantic value and aid in accessibility is lost.
<label for="contact-how">Contact by</label>
       phone <input type="radio" name="contact-how" id="contact-by-phone"  checked="checked" />
       e-mail <input type="radio" name="contact-how" id="contact-by-email"  />
Here, the for attribute is referring to the name attribute of the inputs. This is incorrect. The for attribute is a reference to the id attribute of the input.
<label>Phone <input type="radio" name="contact-how" id="contact-by-phone" checked="checked" /></label>
While technically correct according to W3C recommendations, this method should not be used. The reason being, certain browsers, particularly mobile browsers, handle this code incorrectly and will often cause the element to be un-clickable. You are better off using the method of labeling checkboxes/radio buttons I described above.

For detailed information on the label element and other form information, check out the W3C Recommendations on Forms.

Don’t Let TurboTax Free Edition Fool You—You Probably Want FREEDOM Edition

TurboTax touts their Free Edition’s free-ness. Free to use, free to file. Free for Federal, that is (1040EZ only). Then, they try to up-sell you on filing State for $27.95. What they probably don’t want you to notice is that the Free Edition has nothing to do with the Free File program offered by the IRS, which TurboTax does participate in. But I noticed. Especially one year in while in college when I had to file in three different states, all of which allowed Free E-Filing.

Some of the numbers have changed. View the 2010 update.

Do You Meet One These Criteria?

  • AGI of 31k or less, or
  • Active Military with AGI of 57k or less, or
  • you qualify for the Earned Income Credit

Congratulations, you should probably use Freedom edition if you are planning on using TurboTax.

The IRS Free File program has its limits, as does TurboTax Freedom edition. For the former, you’re only eligible if you had an AGI of $57k or less in 2009. For TurboTax, it’s even more stringent: $31k AGI (for single filers). Additionally, if you own a house, own a business, have a lot of investments/capital gains/losses or donate a lot to charity and you don’t pay attn. to tax laws on your own or don’t care to, neither of TurboTax’s free editions are right for you. There are other companies that offer robust solutions through the Free File program that don’t have the same income limits (Freedom) or restrictions to 1040EZ (Free).

Why should I care?

I don’t know about you, but I don’t want to pay $30 to file my state taxes. Freedom edition allows you to do it for free in states that allow for free e-filing.

Additionally, while 1040EZ will suffice for some people, many others have more difficult tax needs and thus need access to the 1040, which is provided by the Freedom edition, but not Free edition.

But, I don’t see that option on TurboTax’s Web Site!

Yes, they’re rather sneaky like that. In order to access the Freedom edition, you have to go through the IRS Free File Portal. The IRS provides a nice tool to help you choose a preparer, but you can also choose to go to TurboTax directly. The link to TurboTax will allow you to use the Freedom Edition, where things really are free.

I can’t speak with any amount of authority, but I believe the same process is true for some of the other tax companies as well. So, if you do have an AGI under $57k, it’d be smart to head over to the IRS Free-File page and access the online tax applications from there. They provide a list of participating companies, the limitations of each, and a link to the correct free edition.

Our Holiday Journey from NY to MO and Back

We had the week between Christmas and New Year’s Day off this year, so we made a trek back to my home state to visit family and friends. It was a long journey; we drove over 3500 mi. when all was said and done. Some of it was roundabout, as the Midwest was being hit by a huge storm system that was moving its way up to NY directly along the path we normally drive. So, it was an adventure containing new sights, possible future plans, and the realization that we’re getting too old to drive straight through from KCMO to Utica these days.

The Way There

A Google Maps depiction of our route from Utica to Kansas City

See, like I said, roundabout. But all that pink stuff is snow, so you can see why we took it.

To circumvent the storm coming in from the Midwest, we decided to include visiting relatives in NJ in our plans, as well as trying to find somewhere warmer along the way. Originally, we’d wanted to take a day or two to spend in a new city, but couldn’t find anywhere interesting within a days drive of Utica and KC that wasn’t in the middle of the storm system.

A. Utica, NY (Home Frigid Home)

Saturday, Dec 26, 2009. 11am.

Ill prepared as always, we finally get on the road around 11am after a last minute Guinea Pig litter run, cage cleaning, laundry, packing and dropping off the Pigs at Carl’s parents’ house.

I demand brunch in the form of Dunkin’ Donuts. Always a good choice, imho, aside from their icky coffee.

B. Hillsdale, NJ (Extended-family Time)

Saturday, Dec 26, 2009. 3pm.

Roads aren’t bad, but they’re also not great. I’ve decided that drivers get exponentially stupider the closer you get to NYC on the Thruway. Add in bad weather and a wreck on the Tappanzee Bridge, and you end up going 20mph on 87 just a mile before our exit onto the Garden State Pkwy. 2.75 hours into the drive, we realize Carl’s license is sitting in his car, not his back pocket. At this point, we decide to make a decision on going back to Utica for when we get to NJ. We arrive safely in Hillsdale and visit with Carl’s Grandma, Aunt, and cousins. After being fed, overloaded with cookies and candy for the drive, we are on the road again around 5:30-ish…

C. Hancock, MD (Exhausted, it’s Hotel Time)

Saturday, Dec 26, 2009. 11pm.

We stop for the night in Hancock, Carl’s iPhone having been handy when we got off an exit too early for the hotels. I dislike Maryland’s sign placement. It’s late, dark, and winter, so we can’t get a good sense of our surroundings along the Potomac, and choose the cheaper of the town’s two hotels, which happens to sit up on a hill. Come morning, we find it’s actually quite a pretty area. There are a lot of bike trails about, especially along the river.

View of hills and fog in Maryland coming off of a mountain

My phone camera doesn’t do this view justice, but it was very pretty. We were coming down off of a mountain in western MD.

In daylight, the hotel isn’t nearly as sketchy as it seemed the night before. The room could have benefited from a lot less wooden paneling though. It was rather cave-like. Well, if cave walls were made of wood.

We may plan a return trip sometime in the future to bike some of the trails.

D. Charleston, WV (Where We Decided to Maybe Move)

Sunday, Dec 27, 2009. 12pm.

Driving through West Virginia, we encounter 50°F weather, sunny skies, beautiful views, and seemingly perfect cycling terrain for Carl. I spend a fair bit of time learning what Wikipedia has to say about West Virginia. Things we learn:

  • Middle of nowhere WV has better 3G access than Utica. Unfair.
  • Although it was created by succeeding from Virginia to join the North in the Civil War, it’s considered a Southern state by the Census Bureau.
  • Humid Subtropical Climates, of which the largest population centers of the state happen to be, are not nearly as warm and nice as the name of the climate type makes it sound. It’s still better than the Humid Continental Climate of Utica, however.
  • It has one of lowest ranking economies in the US (based on median income and per capita income). However, as it also has the lowest percentage of population with a Bachelor’s degree, Carl and I, with our fancy Yankee college degrees might be a hot commodity.
  • Utica is too small for my tastes. The largest city in WV, Charleston, the capital, is smaller than Utica. However, both its and the Huntington metropolitan areas are slightly more populated than Utica-Rome is.

We stop for lunch in what seems to border on the wrong side of the river, so to speak. However, we drive around and find downtown, the State Capitol building, and a few other landmarks. And man, do West Virginians seem to love their Shoneys restaurants.

Final thoughts: it may be nicer to live than Utica, if we could find jobs.

E. Huntington, WV (Which We Like Better Than Charleston)

Sunday, Dec 27, 2009. 4pm.

Although slightly smaller, Huntington seems quite a bit stronger economy-wise. There seems to be a lot of rejuvenation in the downtown area. It is my choice for relocation if we were to do so.

We don’t stay long, however, as we’re still very far from our destination.

F. Glasgow, KY (Not as Far West as We’d Hoped)

Sunday, Dec 27, 2009. 10:30pm.

As this frozen plane attests, it’s very cold.

Ceci n’est pas un lake. No, really, I’m serious. In addition to the freezing cold, there’s been so much precipitation that rivers in southern IN/IL have overflowed, leaving fields under frozen planes of water.

About an hour from Bowling Green, KY, where I’d hoped to stay for the night, we run into snow. It’s not horrible, but it is 10pm and we’re on a crazy hilly small highway in southern KY, so we decide to stop a little early. The iPhone helps again, as we see no sign of the hotels the highway signs claimed exist. We find one, check in, and collapse for the night.

G. St. Louis, MO (Luckily, No Snow)

Monday, Dec 28, 2009. 2pm.

View of the Arch from I-55

Carl accused me of being a New Yorker on vacation when I took a picture of the Arch (insinuating that I’m no longer a Missourian). I just did it to share with y’all.

Despite the winter weather warnings, St. Louis is no longer getting pelted with snow, thankfully. In fact, we haven’t yet seen precipitation today. It lunch time for us and the car (MO has the cheapest gas of any state in our trip). We head to White Castle. I don’t know why, but it seemed like a good idea at the time. We also stop into a T-Mobile store. Carl’s broken iPhone home button is making him lean toward a new phone, and I figure I can get Mom a Christmas present in the form of a QWERTY keypad so maybe she’ll stop using all of our minutes. She does have unlimited texting, afterall. Alas, T-Mobile has instituted a $18 upgrade fee. I am not in a contract at present, so I’ll take my chances with customer retention via a phone call at some later date. I’m not giving them my hard earned $18 to upgrade after being a customer for 8 years. Carl doesn’t like their phones, so plans to stick with the broken iPhone.

I. Sunrise Beach, MO (It’s Family Time)

Monday, Dec 28, 2009. 4:20pm.

Arrival at Mom’s. Somehow driving through Bowling Green made me want to go bowling, so we go out as a family. Bowling is fun. A country music overload and extended period of time surrounded by true Missourah-ins is not so much.

I forgot how uncomfortable sharing a twin bed is until now. I would prefer never to repeat the experience.

H. Jefferson City, MO (Netbooks, Laptops, Shopping)

Tuesday, Dec 29, 2009. Afternoon.

The girls have a little money from our grandparents for laptops, so we head to Jeff City, which has the closest mall, Best Buy, etc. I learn a lot about Netbooks. We find one for Kaite, and Courtney gets her early HS graduation gift in the form of a bit extra to purchase a real laptop for college next year. We eat Chipotle! Yummy. I miss Chilpotle. Why can’t Utica have one?

I. Sunrise Beach, MO (Again)

Tuesday, Dec 29, 2009. Rest of Day.

We spend more time getting everything set up on the girls’ computers. I upgrade their Mac Mini with Snow Leopard. We spend time together as a family watching Better Off Ted.

J. Grandview, MO (Better known as “Spend as Much Time in KC as Possible” Time)

Wednesday, Dec 30, 2009.

We arrive at Garry and Debby’s. Hellos are said, we settle in, etc.

Dinner time approaches and we head to Westport to try out Korma Sutra, a new-ish Indian place. After arriving in the Plaza/Westport area, I remember how badly Kansas City manages to handle plowing the roads after a snowfall. It’s quite an adventure despite the snow having stopped a day or two prior. Korma Sutra is tasty. We make the intelligent decision to brave the alley next to the Dark Horse Tavern to get back to the car in World Market’s parking lot. No broken bones, thankfully. We also stop in World Market for some champagne and to look at the odds and ends. The night ends at Ben’s where we watch Zombie Land. Not a bad film. Maybe not the best of the year though.


Thursday, Dec 31, 2009.

A whirlwind of meeting for lunch with Heather, seeing my oldest sister, husband, kids, etc. Later, dinner with Rebekah, Maria, Margaret at Domo, a sushi place in Brookside. Finally, Ben’s annual New Year’s Eve party. There could be worse ways to ring in the new year.


Friday, Jan 1, 2010.

We start the day off with some laundry, eating left over Indian, and general catching up with the world online. Later, we stop by to visit my friend Jessica, whom I hadn’t seen in maybe 5 years. We were thick as thieves back in middle school. Then, we head to see my niece and nephew at their grandparents, as I haven’t gotten in touch with my sister. Sadly, I’m unable to see my youngest niece because she’s with Nikki. Afterwards, we head back to Garry and Debby’s, and decide we’re going to head out that night. Having all day Sunday to recoup sounds better than getting in exhausted Sun late afternoon. One last stop to see the last sister, husband and niece, then we get on our way.

The Way Home

A Google Maps depiction of our route from Kansas City to Utica

This is the fastest route, and the one we normally take. We just wanted to get home.

Starting Friday, Jan 1, 2010, 10pm. Ending Saturday, Jan 2, 2010, 7:30pm.

It’s long. It’s freezing. I have a killer headache (not hungover!) and so Carl drives the bulk of the time. In Cleveland, we hit snow. And it snows, and snows, and snows the rest of the way back to Utica.

We finally arrive home, in once piece. Food. Shower. Sleep. And more sleep. Thus ends the journey.

New York State: I Love Unhappiness

The research is in: New York really is the unhappiest state in the nation. Two researchers, including a Professor of Economics from my alma mater, Hamilton College, combined two sets of data—one objective and one subjective—and found a correlation that allowed them to rank the 50 states and DC by happiness. So, not only do we NYers have a low standard of living by one data set, but we know we do according to the other. Ouch. From the NYT.

My Opinion of 1st Financial Bank, USA: Steer Clear

In honor of paying off my oldest/highest-interest credit card balance (woohoo, halfway through my CC debt!), I thought I’d share some thoughts on the card issuer—1st Financial Bank, USA. Particularly, why I think it is an exceptionally shady lender that preys on financially-uneducated students. Sure, most credit card lenders are shady, but few target students to the extent of 1FB.

Is there any good?

Before I bash them, I will admit to a couple of good things: they allowed me to found a credit history at age 18 and raised my limit like clockwork every 6 months, allowing me to maintain a decent debt/credit ratio. Except, maybe that latter bit wasn’t that “good.” I mean, do they really expect a college student to have the means to pay back ~12k? No, definitely not, but 1FB can make a decent chunk of fees if one were to charge up that amount. For the record, I never hit anywhere near that limit.

The Bad

They make it hard to pay and hard to know when to pay by providing jumping due dates, outdated Web access, no option for e-statements, no financial education tools, and limited telephone customer service hours. Maybe some research firm told them that it was good business sense for Generation Y to have access to account information via text message, but to lack a robust online portal, who knows, but if they did, they were told wrong. Regardless of my critique of their technological presence, the real issue is that they exhibited about every bad practice outlawed by the recently-passed CARD act, and are retaliating with painful rate increases and feature removal.

Preemptive CARD Act Changes

Two words: 24.99% APR. Yes, in anticipation of the CARD act coming into effect, they raised my interest rate by 10%! in October. 14.99% wasn’t great to begin with, but 25% is usury in most states (but not SD, where 1FB is based). Also, in addition to the general overdraft/late fee raising that most banks are doing, they also removed the one “reward” type feature of the card: 0% on balances below $250 (or $500 for other cards of theirs).

A good thing? They did remove double-cycle billing. Of course, it wasn’t out of the kindness of their blackened hearts; ceasing double-cycle billing is one of the major dictates of the CARD act.

When Is My Bill Due?

On the nth of the month, give or take a week. My due date constantly bounces around. It is generally somewhere early in the month, but has ranged from the 5th to the 16th. It’s a great way to trap the inattentive (or busy!) student into a late fee.

And a newer development: The online FAQ provides the following about information available online:

1FBUSA Online Services provides easy access to the following information about your credit card account: your credit limit, current account balance, amount of your last payment, date last payment received, your available credit, last statement balance and date, minimum payment due, payment due date, next billing statement date, and next billing statement payment due date. Transactions posted since the date of your last statement are also available, …

[Emphasis Mine]

However, after recent site updates, they no longer provide either a next billing statement date or the next due date. It may seem like unimportant information, but I would like to know the exact date I can see the final finance charges due on my account. Not to mention I prefer to pay the account as close as possible to the statement date, rather than the due date.

How do I pay my bill?

Oh, sorry, we’re still in the 20th century. Mail us a check with your statement stub, please. Your bank does online payments? Well, that’s some newfangled thing they’ve never heard of (ok, a little exagerated, they do provide an ACH program you can enroll in), but the bank can send them a paper check instead of an electronic payment. That’s what ING Direct does for me. The downside there is that despite it being free for me (one of the great ING features), it takes about a week to post, depending on the date 1FB receives it, since it doesn’t have the remittance stub with it, just the acct # on the check..

What about paying online or by phone, like most any decent credit card? Sure, for a $9 charge. I guess it’s the lesser of two evils: forget to send your payment and tomorrow is the due date? No problem, just pay $9 to make a payment on their Web site. Think that’s ridiculous? NP, you can just pay the higher late fee.

Want some human compassion/courtesy? Fuggetaboutit.

Don’t get me wrong, I don’t think it’s the bank’s responsibility to forgive fees right and left or for every sob story, but pretty much anywhere will give you one late payment fee pass, especially if you pay on time consistently. Does that include 1FB? Not in my experience, and I didn’t even hit the dreaded 30-day past, report to the Credit Bureaus point, just 15 days or so.

A few years ago, my grandmother passed away during December finals, right before the payment due date. The following two weeks were a mess—flying home for the funeral, flying back to school to finish my finals, driving home for the month break between semesters (and you had to be out, out, out! of the dorms within 24 hrs. of your last final). True, it’s my responsibility to pay my bill, but obviously, I was a little distracted. I forgot to send in payments for both of my cards. Two weeks go by and I realize my mistake, and send in the payments, then make the dreaded call to request forgiveness of the late fee with my story. Chase: “Sorry for your loss, miss. I see you’ve paid on time in the past. We’ll remove that fee right away as a one-time courtesy. Thank you for calling.” 1FB: “Errr, you paid late. That means a fee. You need to pay it. Yeah, you’ve always paid on time before, but it doesn’t matter. Have a nice day.”

Maybe they decided to take the tough-love approach to creating dependable borrowers. Sure.

What Can You Do About It?

If you have a 1FB card, get it paid off (consider transferring the balance to a new company’s card), find a different card to use every day, and consider closing your account. But don’t close it if it is your oldest account—that will likely hurt your credit score. If you don’t already have a 1FB card, don’t get one!

Update: closing the account might not hurt your score as much as they try to make you think it will. Read about how (not) bad it hurt my credit score to close this account in June 2010.

If you’re a just-entering-college student, verse yourself in financial literacy. Don’t use the card except for small things that you pay off monthly. And that advice applies to any card, not just 1FB-issued ones.

If you’re a parent of a young-adult, please educate them on how to handle their finances, and if possible find a way to get them a card with a company that has some sort of conscience, no matter how small it is. Any other bank seems a little better than 1FB USA.

Of course, in a dream world, we wouldn’t need to worry about getting a credit card at 18, but unfortunately, credit history is important once you graduate and enter the real world, and that’s about the only place to start.