178

Is it possible to format numbers with CSS? That is: decimal places, decimal separator, thousands separator, etc.

Mir-Ismaili
  • 13,974
  • 8
  • 82
  • 100
Don
  • 16,928
  • 12
  • 63
  • 101
  • 81
    You can't but you really should be able to. After all, 50,000 or 50000 or 50,000.00 are all the same 'data' they're just presented differently which is what CSS is for. – punkrockbuddyholly Dec 30 '11 at 09:57
  • 4
    @MrMisterMan: There are some ideas being tossed around here: http://wiki.csswg.org/ideas/content-formatting#numbers I'm probably going to be harassed and accused of citing "specifications" and getting everyone's hopes up though. And for me, I'm curious to know how non-numeric text would be handled here. – BoltClock Dec 30 '11 at 10:52
  • 3
    While I do agree that this would be nice to have, the number is embedded inside an otherwise localized page. I.e., the rest of the page is English, Chinese or whatever other language, and the numbers should IMO conform to that localization. Why should they be localized separately from the rest of the page...? – deceze Feb 07 '12 at 09:33
  • @deceze: You are right. It should be possible to have "localization CSS"s – Don Feb 07 '12 at 10:54
  • 1
    adding JS option using Intl.NumberFormat [mdn-ref:](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) – Joshua Baboo May 31 '17 at 07:25
  • 1
    @punkrockbuddyholly; Also localizations are needed. For example, `۵۰٬۰۰۰` (Persian) and `٥٠٬٠٠٠` (Arabic) are the same data (`50,000`). – Mir-Ismaili May 05 '22 at 14:00
  • You could handle it in the font, if you wanted to go that deep. [Numderline](https://blog.janestreet.com/commas-in-big-numbers-everywhere/) provides a proof of concept, and there's enough communication between CSS and font rendering that you could selectively switch this behaviour on and off as needed and the display style can vary by language. – sh1 Jul 31 '23 at 05:44
  • (also, doing it in the font means cut-and-paste won't introduce spurious characters which vary depending on the user) – sh1 Jul 31 '23 at 06:02

16 Answers16

42

Unfortunately, it's not possible with CSS currently, but you can use Number.prototype.toLocaleString(). It can also format for other number formats, e.g. latin, arabic, etc.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString

CascadiaJS
  • 2,320
  • 2
  • 26
  • 46
  • 2
    The most modern and elegant approach, and since it is still impossible to achieve with CSS as of now, should be the number 1 answer! – FMA Jan 12 '19 at 12:40
  • It is being broken on RTL layouts. I format numbers serverside and put them to markup, so they get delivered to browser as (for example, two thousands five hundreds) `2 500`. And at Arabic versions (with `body.rtl_ { direction: rtl; }`) this example all of a sudden turns to `500 2`. – Alex Naidovich Dec 15 '21 at 12:55
  • @AlexNaidovich Thanks for the info. This seems like a bug. You should report it. If you're using Chrome, it is based on the Chromium project and you can [report bugs here](https://www.chromium.org/for-testers/bug-reporting-guidelines) – CascadiaJS Jan 06 '22 at 20:23
  • @CascadiaJS Thanks for reply, but I found out that this is actually not a bug. RTL layout by nature changes word order, so it treats whitespaces respectively. So there are minor cases (like my example above) when I need to explicitly set `direction: ltr;`. To conclude - the answer we are commenting on is totally OK. – Alex Naidovich Jan 18 '22 at 15:22
39

The CSS working group has publish a Draft on Content Formatting in 2008. But nothing new right now.

Yoann
  • 4,937
  • 1
  • 29
  • 47
24

Well, for any numbers in Javascript I use next one:

var a = "1222333444555666777888999";
a = a.replace(new RegExp("^(\\d{" + (a.length%3?a.length%3:0) + "})(\\d{3})", "g"), "$1 $2").replace(/(\d{3})+?/gi, "$1 ").trim();

and if you need to use any other separator as comma for example:

var sep = ",";
a = a.replace(/\s/g, sep);

or as a function:

function numberFormat(_number, _sep) {
    _number = typeof _number != "undefined" && _number > 0 ? _number : "";
    _number = _number.replace(new RegExp("^(\\d{" + (_number.length%3? _number.length%3:0) + "})(\\d{3})", "g"), "$1 $2").replace(/(\d{3})+?/gi, "$1 ").trim();
    if(typeof _sep != "undefined" && _sep != " ") {
        _number = _number.replace(/\s/g, _sep);
    }
    return _number;
}
  • 1
    Thanks. Not a pure CSS solution, but does the task! – Don Feb 25 '15 at 04:13
  • 1
    I like it. But I needed to also convert the number to a string before the replace. You can not do a replace on a number. – Mardok May 27 '16 at 18:47
  • before calling `_number.replace` we have to make sure it is a string like this `_number = typeof _number != "undefined" && _number > 0 ? String(_number) : "";` or else you will get an error `_number.replace` is not defined or not a function – Shalkam Jul 01 '17 at 15:28
  • 6
    why not simply use: (123456789).toLocaleString('en-GB') or the like? – Joehannes Nov 22 '17 at 22:50
15

Probably the best way to do so is combo of setting a span with a class denoting your formatting then use Jquery .each to do formatting on the spans when the DOM is loaded...

Ross
  • 1,639
  • 1
  • 18
  • 22
10

Not an answer, but perhpas of interest. I did send a proposal to the CSS WG a few years ago. However, nothing has happened. If indeed they (and browser vendors) would see this as a genuine developer concern, perhaps the ball could start rolling?

itpastorn
  • 2,935
  • 1
  • 22
  • 24
9

No, you have to use javascript once it's in the DOM or format it via your language server-side (PHP/ruby/python etc.)

mreq
  • 6,414
  • 4
  • 37
  • 57
  • 8
    The format of numbers is a content matter, like the text of the content or other notational issues (e.g., date notations, which are language-dependent). So formatting numbers is localization and should be handled when content is generated. Doing it in JavaScript makes sense for the part of content that is JavaScript-generated. – Jukka K. Korpela Dec 30 '11 at 10:01
  • I fully agree with that. That's why I wrote it in my answer. Should've probably put more stress on it. – mreq Dec 30 '11 at 20:28
  • It can be either content or presentation. Take CSS `rtl`, that shows the same content in a different way: should it also be treated server-side? – Don Feb 01 '18 at 08:29
7

If it helps...

I use the PHP function number_format() and the Narrow No-break Space ( ). It is often used as an unambiguous thousands separator.

echo number_format(200000, 0, "", " ");

Because IE8 has some problems to render the Narrow No-break Space, I changed it for a SPAN

echo "<span class='number'>".number_format(200000, 0, "", "<span></span>")."</span>";
.number SPAN{
    padding: 0 1px; 
}
DanielBlazquez
  • 1,045
  • 1
  • 13
  • 22
  • Unfortunately this is server side, there is a slight CPU hit, we need an html/css edit mask ability. Dressing and rendering should be client side unless we are serving a pdf ? – mckenzm Dec 30 '16 at 02:09
6

Another solution with pure CSS+HTML and the pseudo-class :lang().

Use some HTML to mark up the number with the classes thousands-separator and decimal-separator:

<html lang="es">
  Spanish: 1<span class="thousands-separator">200</span><span class="thousands-separator">000</span><span class="decimal-separator">.</span>50
</html>

Use the lang pseudo-class to format the number.

/* Spanish */
.thousands-separator:lang(es):before{
  content: ".";
}
.decimal-separator:lang(es){
  visibility: hidden;
  position: relative;
}
.decimal-separator:lang(es):before{
  position: absolute;
  visibility: visible;
  content: ",";
}

/* English and Mexican Spanish */
.thousands-separator:lang(en):before, .thousands-separator:lang(es-MX):before{
  content: ",";
}

Codepen: https://codepen.io/danielblazquez/pen/qBqVjGy

DanielBlazquez
  • 1,045
  • 1
  • 13
  • 22
3

I don't think you can. You could use number_format() if you're coding in PHP. And other programing languages have a function for formatting numbers too.

Florin Frătică
  • 587
  • 4
  • 7
  • 13
  • BAD practice to alter data for display purposes in the "backend". – Buffalo Jan 28 '19 at 05:35
  • What is the problem with serving a page in Spanish (or another language) with the numbers formatted in that language? I don't think it's a bad practice at all. – DanielBlazquez May 07 '21 at 18:59
2

You could use Jstl tag Library for formatting for JSP Pages

JSP Page
//import the jstl lib
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

<c:set var="balance" value="120000.2309" />
<p>Formatted Number (1): <fmt:formatNumber value="${balance}" 
        type="currency"/></p>
<p>Formatted Number (2): <fmt:formatNumber type="number" 
        maxIntegerDigits="3" value="${balance}" /></p>
<p>Formatted Number (3): <fmt:formatNumber type="number" 
        maxFractionDigits="3" value="${balance}" /></p>
<p>Formatted Number (4): <fmt:formatNumber type="number" 
        groupingUsed="false" value="${balance}" /></p>
<p>Formatted Number (5): <fmt:formatNumber type="percent" 
        maxIntegerDigits="3" value="${balance}" /></p>
<p>Formatted Number (6): <fmt:formatNumber type="percent" 
        minFractionDigits="10" value="${balance}" /></p>
<p>Formatted Number (7): <fmt:formatNumber type="percent" 
        maxIntegerDigits="3" value="${balance}" /></p>
<p>Formatted Number (8): <fmt:formatNumber type="number" 
        pattern="###.###E0" value="${balance}" /></p>

Result

Formatted Number (1): £120,000.23

Formatted Number (2): 000.231

Formatted Number (3): 120,000.231

Formatted Number (4): 120000.231

Formatted Number (5): 023%

Formatted Number (6): 12,000,023.0900000000%

Formatted Number (7): 023%

Formatted Number (8): 120E3

Mohammad Javed
  • 328
  • 3
  • 13
2

You cannot use CSS for this purpose. I recommend using JavaScript if it's applicable. Take a look at this for more information: JavaScript equivalent to printf/string.format

Also As Petr mentioned you can handle it on server-side but it's totally depends on your scenario.

Community
  • 1
  • 1
Qorbani
  • 5,825
  • 2
  • 39
  • 47
1

Another js solution to improve the work of Skeeve:

<input type="text" onkeyup="this.value=this.value.toString().replaceAll(/[^\d]/g, '').replaceAll(/(\d)(?=(?:\d\d\d)+$)/g, '$1\u202f')" pattern="[0-9\s]*">
vacsati
  • 528
  • 6
  • 7
1

Example as inline-JavaScript in an input[type=number]-Html field, using Intl vanilla JS:

<input class="form-number" 
       type="number"
       id="bar"
       name="foo"
       value=""
       step="any"
       min="0"
       size="20"
       onfocusout="this.value = (new Intl.NumberFormat('de-DE').format(this.value));">

kaiser
  • 21,817
  • 17
  • 90
  • 110
1

Formatting numbers can go pretty deep and down all sorts of wrong paths. For example, you can end up with tools which will change the output between $ and £ depending on who's reading it, even though at least one of those outputs must be false.

However, if the only thing you're worried about is the readability of a number with thousand separators without the confusion over which thousand separators to use, it might be best to just follow international standards and ignore user preference. Insert thin spaces every three digits, and don't fuss over whether your decimal separator is . or ,.

If that's all you want to do, then one approach is to patch the font that you're using, and to use CSS to activate specific font features to format the font in a more friendly way.

I wanted to try this out, so using the Numderline font patcher as a kicking-off point, I made a tool to enable this.

You simply mark numbers with a CSS font feature setting indicating that you want it formatted with digit grouping:

font-feature-settings: "dgsp";

Now, in theory the font should be able to automatically adapt its behaviour according to the current language setting, inserting dots or commas or whatever as appropriate. That was my original intent, but while I was learning how I to do it found discussion explaining that this is discouraged, and the design philosophy is to make the feature available but let the application pass in additional settings to use according to user preference and/or locale.

Consequently, the tool offers alternative feature names dgco to use commas instead of spaces, and dgdo to use dots instead of spaces (with an ugly side effect that I also have to change decimal dots into decimal commas -- so be very cautious with this).

sh1
  • 4,324
  • 17
  • 30
0

The closest thing I could find is the <input type="number" /> tag, which does do formatting in plain HTML but is also an input field. To make it look like plain text, you could use a bit of CSS.

Unfortunately I don't know how to fix the right margin without JavaScript or using a monospace font and set the width attribute server side.

HTML:

<p>In <input type="number" value="1.223" readonly="readonly" size="1" /> line</p>

CSS:

p {font-family: verdana;}
input {
  font-family: verdana;
  font-size: 16px;
}
input[readonly] {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 3em;
  font-size: 16px; 
}
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
/* Firefox */
input[type=number] {
  -moz-appearance: textfield;
}
Code4R7
  • 2,600
  • 1
  • 19
  • 42
-3

as for thousand separators this is what I found on Wikipedia, in the code of this page. Below is the number 149597870700 with .15em margins as thousand separators:

<span style="white-space:nowrap">
    149
    <span style="margin-left:.15em;">597</span>
    <span style="margin-left:.15em;">870</span>
    <span style="margin-left:.15em;">700</span>
</span>
robotik
  • 1,837
  • 1
  • 20
  • 26