Scott Hanselman

Making Negative Numbers turn Red using CSS and Javascript

May 1, '06 Comments [9] Posted in ASP.NET | Javascript
Sponsored By

A common thing one wants to do in a table of financial figures is to turn negative numbers red. Given that folks would rather use CSS than <font>, there's some conflicting thinking around the right way to do it.

Some propose adding "negative" a css class like:

<TD CLASS="financial negative">-190</TD>

but others find that distasteful and say:

  • number is a data type.
  • currency is both a presentational instruction and a sub-type of the number data type.
  • negative is neither type nor presentational — it’s dependent on the data value, not the type or the author’s formatting preference. It doesn’t belong there. [Xaprb]

and go on to provide a clever CSS-only technique that works everywhere but IE6 (demo here).

In the specific situation I've got, I'd like to make the change without changing any server-side code (which precludes adding a "negative" css class) and I need it to work everywhere (which nixes clever css).

So, here's my not-so-clever Javascript solution (Warning, I'm not a Javascript guy so give Phil a few minutes and he'll no doubt include color commentary).

<html>
<head>
    <style type="text/css">
     td.negative { color : red; }
    </style>
    <script language="JavaScript" type="text/javascript">
    <!--
    function MakeNegative() {
        TDs = document.getElementsByTagName('td');
        for (var i=0; i<TDs.length; i++) {
                var temp = TDs[i];
                if (temp.firstChild.nodeValue.indexOf('-') == 0) temp.className = "negative";
            }
    }
    //-->
    </script>
</head>
<body>
 <table id="mytable">
  <caption>Some Financial Stuff</caption>
  <thead>
    <tr><th scope="col">Date</th><th scope="col">Money is good</th></tr>
  </thead>
  <tbody>
  <tr><td>2006-05-01</td><td>19.95</td></tr>
  <tr><td>2006-05-02</td><td>-54.54</td></tr>
  <tr><td>2006-05-03</td><td>34.45</td></tr>
  <tr><td>2006-05-04</td><td>88.00</td></tr>
  <tr><td>2006-05-05</td><td>22.43</td></tr>
  </tbody>
 </table>
    <script language="JavaScript" type="text/javascript">
  <!--
   MakeNegative();
  //-->
    </script>
</body>

May not be Web 2.0, and it likely doesn't please the standards wonks, but it works.

UPDATE: Similar attempt seen here.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Monday, May 01, 2006 8:59:43 PM UTC
Hmmm. Interesting way to go. That said, I'm not sure about the flexibility. If negative numbers have parens instead of a minus sign, the script would have to know. Or if the currency symbol was in there, it'd have to know (is it $-12.50 or -$12.50?). Generally speaking, you could always just attach to the OnItemCreated event, even in ASPX, and update the cell as needed.

Two things it'd be awesome for:
* Changing the look of stuff post-compile time where you want to deal with it entirely through theme (add that script to your theme).
* Letting non-C# coders update what things look like (folks who aren't allowed to play with the ASPX).

You'd have to be careful if the table changes through AJAX, too, but that wouldn't be too hard to accommodate. You'd also have to be careful about having multiple classes assigned to a cell:

[tr][td class="debitAmount"]-12.50[/td][/tr]

You wouldn't want to overwrite the debitAmount class there, you'd want multiple CSS classes attached, like this:

[tr][td class="debitAmount negative"]-12.50[/td][/tr]
Travis
Tuesday, May 02, 2006 3:25:20 AM UTC
Scott, your script will never work when displaying numbers in base -1. I thought someone of your caliber would've recognized that and have taken it into account.



;)
Tuesday, May 02, 2006 3:27:51 AM UTC
I meant to say it will never work for base -2 number systems (aka negabinary). A base -1 system is pretty useless.
Tuesday, May 02, 2006 11:21:46 AM UTC
Seems like I'm not the only one lately to notice that the CSS emperor has no clothes.
Tuesday, May 02, 2006 12:23:11 PM UTC
>> Scott, your script will never work when displaying numbers in base -1. I thought someone of your caliber would've recognized that and have taken it into account.

Is base -1 like monochromatic art? You use various sizes of -1? (Note, this is only possible on certain Pentium Processors).
Tuesday, May 02, 2006 2:45:40 PM UTC
>> You wouldn't want to overwrite the debitAmount class there, you'd want multiple CSS classes attached...

Travis,
do you know of a clever way of ensuring that any existing classes are not replaced by the new element.className assignment? It seems we need to just append the new class to the element.className attribute.
Wednesday, May 03, 2006 12:07:36 AM UTC
Less work for the browser with this:

document.body.innerHTML = document.body.innerHTML.replace(/[td]-/gi,"[td class=\"negative\"]-");

(Please replace [ and ] with < and >)
Friday, May 05, 2006 7:51:19 PM UTC
Steve's right. You'd want to check for an existing classname and append a space and the new class name.
Friday, May 12, 2006 9:00:14 PM UTC
Let's not forget about HTC :-)

td { behavior: url(numbers.htc); }

in css/htm will do the job too and will be ignored by firefox

----------------- numbers.htc:
&lt;PUBLIC:ATTACH EVENT="onreadystatechange" O`NEVENT="postInit()" />
&lt;SCRIPT LANGUAGE="JScript">
function postInit() {
if(readyState=="complete") {
if(innerText.indexOf('-') == 0) runtimeStyle.color = "red";
}
}
&lt;/SCRIPT>
D
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.