6

I want a table containing a column of decimal numbers, of varying length before and after the decimal, with the decimal points all aligned.

The column width must have a "liquid" size, expanding as necessary to accomodate EITHER a very long number in ANY of the data cells, OR a very long HEADER pertaining to that column.

Cells containing integers (no decimal point) should still display the numbers with the digits aligned in the same position as if a decimal character was present. (eg. The number 512 should still have its digits aligned correctly with the cell containing only "512" instead of "512.")

The font should be irrelevant; monospaced should not be a requirement.

Finally, the numbers must also be centred in the column as best as possible, while keeping the decimals (visible and implied!) aligned. Specifically, the "left-side blank gap" of the cell with the most characters before the decimal character (or simply most characters if there is no decimal character present) must be of equal width as the "right-side blank gap" of the cell with the most characters after the first decimal character.

I specifically say "characters" instead of "numerals" for the final requirement, because the table layout should handle symbolic characters such as positive/negative signs prepending the numerals, and letters such as measurement unit acronyms appending the numerals.

The HTML 4.01 specification, "by the book", allows such a layout to be done very easily with a simple HTML table. (Split the data on its decimal character across the two inner cells of a 4-column colgroup, with the outer two col width="*" and inner two col width="0*". Right-align the cell with the integer-portion of the number, and left-align the cell with the decimal character and fractional-portion of the number. Set both those cells to nowrap, then set the table's cellpadding="0" cellspacing="0" rules="groups".)

But a number of people say this is bad, and that CSS should be used instead of tables for formatting purposes. I also understand that a table with semantically-correct data should keep these numbers intact in a single cell. But I have not found any CSS method of acheiving the desired formatting!

Simply setting a single column's text alignment to "center" doesn't keep the decimal points aligned.

Unless I am mistaken, using align="char" can't handle integer numbers that don't have an explicit decimal point, but still need to be aligned as if they did.

Appending a decimal character to integer numbers, even if hiding it, technically breaks the data integrity.

Padding the data with non-breaking spaces doesn't work with proportional (non-monospaced) fonts. And this hack too would break the data integrity.

Specifying position by fixed pixel offsets doesn't permit the column to have a truly "liquid" width, rendered as necessary to fit the contents of all cells in the column, including the header cell, which could contain data of any length at any time.

JavaScript that reads the resulting width of the table after it is rendered, then dynamically calculates pixel offsets, and then rewrites the formatting via DOM to "slide" the data into alignment is slow, and visually disrupting as the data jumps around. And it's an outright dirty hack that's even dirtier than using tables for layout purposes!

It almost seems to me like the "purist's" CSS-layout + HTML-semantic-data approach is incapable of doing this simple but often-desired layout! I'm hoping someone can please prove me wrong, and show me how to do this layout "properly".

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user1645764
  • 61
  • 1
  • 1
  • 2
  • 3
    You should first try and find how to align numbers on the decimal point (using align=char does *not* work in reality), see e.g. http://stackoverflow.com/questions/11600838/align-decimal-data-in-table-column-by-decimal-point-html5-css3 – Jukka K. Korpela Sep 04 '12 at 12:09
  • Every solution on that page either involves "corrupting" the data (eg. by adding superfluous zeros or spaces) or by inserting a character-spaced span (both of which put limits on the fonts that can be used), or splitting the data across two cells (same as what my "semantically incorrect" HTML 4.01 table solution does). And NONE of those solutions address the issue of "best-attempt centering" the data within the visual column. – user1645764 Sep 04 '12 at 17:15
  • I wrote this jQuery plugin to solve the problem. It doesn't requiring reworking the data. https://github.com/ndp/align-column – ndp Feb 11 '13 at 23:12

4 Answers4

5

There is a pure html/css solution for this, but it's not pretty. You need to separate the decimal aligned column into two columns, with no padding between them. The first column has the integer value and is right aligned, the second has the decimal and the decimal value.

<table>
 <thead>
  <th>customers</th>
  <th colspan="2">balance</th>
 </thead>
 <tbody>
  <tr><td>John</td>  <td>4</td><td>.45</td></tr>
  <tr><td>Jane</td>  <td>20</td><td></td></tr>
  <tr><td>Jim</td>   <td>2,300</td><td>.64</td></tr>
 </tbody>
</table>

<style>
    th {
        text-align: center;
    }
  td:nth-child(2) { 
      text-align: right;
      padding-right: 0;
    }
  td:nth-child(3) { 
      position: relative;
      left: -0.2em;
      text-align: left;
      padding-left: 0;
    }
</style>

You could also use classes like ".integer" and ".decimal" as opposed to :nth-child selectors. That would be more robust, but I was trying to keep the markup short.

1

There is no way in raw HTML to do this. I wrote a jQuery plugin to solve just this problem. See https://github.com/ndp/align-column

It's simple to use with your uncorrupted table:

$('table').alignColumn(3); aligns column index 3.

ndp
  • 21,546
  • 5
  • 36
  • 52
  • This is great, I've seen your example. But I couldn't work this right. Hope you can help me. Give me a reply then I will show my code. Thanks – Sam San Jun 29 '13 at 02:36
  • If I have `stuff` in one row, and right below that two `td`s that span the `th`, is there a way to have the two cells be of equal width? I'm sure one could do this with JS, but do you know of a CSS solution? – Joel DeWitt Dec 14 '18 at 03:01
0

I think the "charoff" attribute is what you need. Unfortunately, many browsers don't support it ...

http://www.w3.org/TR/1999/REC-html401-19991224/struct/tables.html#adef-charoff

Have you tried to divide each number into 2 strings? For example

"1234.567" will be "1234." and "567"

Then you can put the first string in a cell (right aligned), and the other part in the next cell (left aligned)

DanielBlazquez
  • 1,045
  • 1
  • 13
  • 22
  • Is there any browser that supports it? (Besides, if it worked, it would not center.) – Jukka K. Korpela Sep 04 '12 at 12:11
  • Dani, my original HTML 4.01 table solution (that CSS purists balk at) does pretty much exactly that, splitting the number at the decimal into two strings. (Except I put the decimal in the beginning of the right string, not the end of the left string, so integer numbers that only have the left string populated still appear aligned ;-)) – user1645764 Sep 08 '12 at 07:31
  • Another idea is to add zeros (0) at the end of the number, in order to align the dot in the same site (you need a monospaced font). – DanielBlazquez Sep 10 '12 at 20:01
  • Looks like it never made it to modern standards. https://html.spec.whatwg.org/multipage/tables.html#the-col-element – T.J. Crowder Feb 10 '23 at 16:39
0

Given your requirements, there is no solution (even to the simpler issue of aligning to the decimal point).

Jukka K. Korpela
  • 195,524
  • 37
  • 270
  • 390