Thursday, December 20, 2007

CSS Inadequacies x Poor Browser Support = Hell

I don't spend as much time as most web designers probably do, creating CSS and XHTML layout from scratch. As a "corporate" designer, most of my time is spent maintaining an existing site. I only have to do substantial CSS and markup work when I redesign the site or add a substantial portion of content to it. So when I am tasked with creating a new CSS layout, I am always reminded of how I hate so many of the problems that exist with CSS and the browser support for it; especially in contrast with Flex (which I've been working with a lot lately). Although Flex has its own set of CSS and layout issues none are as severe as those with XHTML/CSS.

This post sums up a lot of the problems:
http://blog.iconara.net/2007/09/21/the-failure-of-css/

I'm not a n00b to CSS. I've been working with it since Netscape 4 barely supported CSS text formatting, and I was doing CSS-P well before most of my designer / developer peers were. But I still struggle with it for many reasons.

It's nearly impossible to create a complex layout without resigning to at least one of the following: employing hacks, giving in to div-itis, compromising your design, or breaking in anything but the most bleeding edge, standards-supporting browsers.

How often does separating content from presentation really work so well that you don't have to change your markup? I know, CSS Zen Garden does it. But that's ONE PAGE. If I have a site of 100+ pages, and maybe 5 or so different layouts (and possibly a mobile version) with umpteen variations in content, and I have to redesign, I have a lot more work cut out for me than just rewriting a style sheet and slicing some new images. Let the DRY approach belong to the programming, and use the "include" and layout rendering features of dynamic development languages. I'm going to be putting all my presentational markup in a couple CF templates anyhow. Semantic and clean markup is still good, and will prevent too much markup rewriting, but the bottom line is that you will still have to rework it.

The C in CSS should stand for Crap. The Cascade does not work. Oh, I know it "works." But more often than not, it gets in the way because it's not supported well enough to rely on it, but it works just enough to create random trickle-down issues. Dreamweaver actually created the "Relevant CSS" panel just to demystify the Cascade. If you can't get better control of where you're inheriting from, and what's relevant, then it just creates inheritance headaches.

I want to create a code-clean, reliably cross-browser compatible hack-free elastic layout without compromising my design or missing my deadline. Is that too much to ask? Apparently so.

End this war, impeach CSS.

Monday, December 17, 2007

Extending the Flex Currency Formatter

I was faced with a puzzling challenge this week on a Flex app I've been working on. I have a Flex DataGrid that is showing financial metrics - projected vs actual and the variance...a very common sales type of report. It breaks these metrics down by year, quarter and month.


Imagine it's September. Now you'll see in the grid above that October through December show 0's for the actual column, and a negative variance, but they are just months that haven't happened yet. One requirement we had for how these metrics display was that for time periods that haven't happened yet this year (IE next month, next quarter), we show a dash in the grid instead of a 0. It's all about the psychology of not making the report look overly negative :)

The challenge was that the way these numbers are displaying within the grid is via an ItemRenderer with a CurrencyFormatter. From within that item renderer, I don't have any access to data columns outside the immediate column. For instance, I could not refer to the Month column. Moreover, if I ever returned a value for that column that was a string and not numeric (I'm using a CFC on the back end), I couldn't use the CurrencyFormatter to nicely format my numbers with dollar signs and thousands separators.

I mulled over several evil sounding ways to make this work, and as I went to implement one of them, a much simpler solution struck me.

1. Within the CFC where I'm creating a collection of objects, I have access to other columns of data within the grid. Thus I can evaluate if the time period is in the future with a just a line of code.
2. Rather than returning the actual character I want to display (which won't work with the formatter), I replace the actual value of the "future" data with -1. This way, the data is still numeric, but it's not a number that will ever happen naturally. This seems to be a common programming trick - using negative numbers for "non-real" values. But because it's numeric, I can still use the currency formatter on the front end.
3. I create a custom ActionScript formatter on the front end which extends the CurrencyFormatter class. This formatter has two extra properties: replaceValue and replaceChar. replaceValue is the "fake" value I'm looking to replace, replaceChar is the character I want to replace it with . That way I can customize it at any time if say, we decide we want an x instead of a dash. Then within the formatter, I just compare the actual value with the replaceValue, and if they're equal, I return the replaceChar instead of the formatted string. Otherwise, I return the normal formatted string.

Here's the completed code for my ForecastCurrencyFormatter solution.

ColdFusion/Back End

<cfif dateOfMetric GT month(now())>

<cfset actualAmount = -1>

<cfset varianceAmount = -1>

</cfif>


Flex Formatter



//ForecastCurrencyFormatter.as

package com.myFormatters {

import mx.formatters.CurrencyFormatter;
public class ForecastCurrencyFormatter extends CurrencyFormatter {

/*value to replace - defaults to -1*/

public var replaceValue:Number = -1;

/*character to replace with - defaults to a dash*/

public var replaceChar:String = '-';



public function ForecastCurrencyFormatter() {

super();

}



//override the format method with my custom formatting

override public function format(value:Object):String {

/*if the number value is the value to replace, return the replacement character instead*/

if (value == replaceValue) {

return replaceChar;

}

/*otherwise just format according to the standard currency formatter*/

else {

return super.format(value);

}

}



}

}


Using the Formatter


<!-- at the root, declare a namespace for the formatter components -->

<?xml version="1.0" encoding="utf-8"?>

<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:fm="com.myFormatters.*">
<!-- this is just one column within my datagrid, showing use of the formatter -->

<mx:DataGridColumn textAlign="right" headerText="Actual" sortable="false" dataField="actual">

<mx:itemRenderer>

<mx:Component>

<mx:VBox clipContent="false">

<fm:ForecastCurrencyFormatter replaceValue="-1" replaceChar="-" id="fcf" precision="0" thousandsSeparatorTo="," currencySymbol="$" alignSymbol="left" />

<mx:Text width="100%" text="{fcf.format(data.actual)}" />

</mx:VBox>

</mx:Component>

</mx:itemRenderer>

</mx:DataGridColumn>

That's about it. We now have a formatter that behaves just like the standard currency formatter, but with an additional formatting option.

Monday, December 3, 2007

People Who Inspire Action

In my day to day work, I deal with a variety of people of varying personalities and "working styles." I can be a real procrastinator when it comes to making and returning phone calls from these people because it requires putting down my work to make a call to someone who may not be there, to play phone tag, to end up on the phone with them for longer than necessary while they whine about a list of things they need from me resulting in hours of work on my part. Not necessarily something I'm motivated to do. Ok, not every exchange is like this, but in a support role such as that I'm in, it's very often the case.

However there are a few people I will always call back right away, and it's not because they never ask for anything (in fact many of them ask for a lot). The reason I'm motivated to call these people back? They have a positive attitude (it's not going to be a complainy conversation). They are willing to work together to get things done, and not try to shove all the work onto me. They keep it short and sweet. They are usually there when I call, or return my call within a few minutes. And when I give them what they ask for, they are appreciative and make me feel like the work I do is valuable. Working with - and calling these people is always a pleasure.

So...just a word of advice from my experience. If you want to inspire immediate action, develop a rapport with people such that they know you won't waste their time, and have an attitude that makes you pleasant to work with. It makes all the difference in your ability to get what you need from other people.