I'm using (Windows) TrueType fonts on my Ubuntu workstation (details), and am mostly happy with how fonts look, both in desktop apps and on the web (using Firefox).

However, on some web pages, like this one, fonts completely suck:


I found the reason to be Helvetica in the CSS for that site:

font-family: Helvetica,Arial,Tahoma,sans-serif;

When, using Firebug, I remove Helvetica from that list, it uses Arial and looks all spiffy again:

alt text

My question is, how to make web pages that use Helvetica (or Times, or other such fonts) look nice automatically? In other words, how to map Times and Helvetica font families to the serif and sans-serif defaults (which in my case would be Times New Roman and Arial, respectively)?

I'm interested in any solution that makes Firefox use the MS TrueType fonts in this scenario, no matter if it's based on tweaking Ubuntu font configs or custom CSS rules in Firefox (or something else that I currently have no clue about).

Update: I've now got the problem fully solved - this answer describes what I needed to do.

  • Wait, there's an improvement? – Josh Hunt Oct 12 '09 at 12:51
  • Yes, definitely. But I guess what kind of fonts people prefer varies from one person to another. Compare e.g. the two screenshots in superuser.com/questions/19824/better-ubuntu-fonts – Jonik Oct 12 '09 at 14:14
  • Sorry, I was just being a smug mac user, yet again. imgur.com/dYFBQ.png – Josh Hunt Oct 14 '09 at 11:58
  • Wow, with both screen captures I couldn't tell for sure if it actually is Helvetica or Arial, though the lower-case A seems to confirm it... I read in the referenced details that you don't like antialiasing for small font sizes, so I won't get started. ;-) – Arjan Oct 16 '09 at 9:26
  • Just so you know, that's the postscript font "Nimbus Sans L" being poorly rasterized there. – sgm Feb 11 '10 at 16:23

Edit: I completely updated this answer after getting some breakthrough advice from a colleague.

Here's what I inserted in /etc/fonts/local.conf (inside the <fontconfig> element):

<!-- Replace Helvetica with Arial -->
<match target="pattern">
    <test qual="any" name="family">
    <edit name="family" mode="assign" binding="strong">

Similarly for Times -> Times New Roman. (See my full local.conf here.) The key was to use binding="strong" for the <edit> element. (Also, using "assign_replace" mode instead of "assign" causes something similar, except that then it's too aggressive: also Verdana gets replaced with Arial).

Changes in font configurations are effective immediately. Besides testing in Firefox, you can check that it works like this:

$ fc-match helvetica
Arial.ttf: "Arial" "Normal"

If you run into problems, the best help is near: man fonts-conf. (Although even with the documentation, the workings of the font system seemed somewhat complicated or unwieldy to me.) You can also try to "debug" what's really going on using a command like:

FC_DEBUG=4 fc-match helvetica

In addition, FC_DEBUG=1024 fc-match helvetica shows the list of config files that affect the font matching.


I had a similar problem in Opera, the solution to which was to disable "Core X Fonts" in the config. I'd suggest seeing if there is a similar option in Firefox.

Other options:

  • Check that you definitely don't have a font called "Helvetica" installed, similar things happened to me a few times. IIRC the problem fonts were in folders called 100dpi and 75dpi in the system font folder (/usr/local/share/fonts I think). I just moved those folders out of there entirely.
  • Check the defaults under System > Preferences > Appearance > Fonts.
  • Check Firefox's defaults under Preferences > Content.

If you make changes to the core folders you will need to rebuild the font cache with:

sudo fc-cache -f -v
  • Ah, I didn't notice this before. What do you mean by disabling Core X fonts in the config - where exactly? Also, what's System > Preferences > Font? The Gnome font config tool? I'm using KDE on my Ubuntu but have Gnome stuff installed too. If you could give the command names for launching these that would be the most useful. – Jonik Oct 16 '09 at 9:03
  • In Opera it is opera:config but in Firefox it is about:config. Type that into the address bar, you may get a warning about dragons ;D but continue. There is a filter box - I suggest searching for "font" and seeing what options you get. – DisgruntledGoat Oct 20 '09 at 19:05
  • Corrected my answer, it is System > Preferences > Appearance > Fonts on Ubuntu. Make sure each of the fonts listed (Application/Document/etc) is appropriate. I'd also recommend choosing "Subpixel smoothing" for the best look. – DisgruntledGoat Oct 20 '09 at 19:08
  • +1 for the font cache rebuild and the subpixel smoothing. – Swoogan Apr 9 '11 at 17:31

Greasemonkey will be one of solution for your question. Install this addon and you can customize the web pages and change the fonts.

and one example script which changes the font to Helvita

// ==UserScript==
// @name           Google Reader Font in Helvetica and enlarged
// @version        1.0
// @creator        Joe
// @description    Changes the font family and size from Google Reader page
// @namespace      userscripts.org
// @include        https://www.google.com/reader/*
// @include        http://www.google.com/reader/*

// ==/UserScript==

function addGlobalStyle(css) {
    var head, style;
    head = document.getElementsByTagName('head')[0];
    if (!head) { return; }
    style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = css;

addGlobalStyle('A.entry-title-link {font-family:Helvetica;font-size: 20px;}');
  • Hmm, I think you got it the wrong way: I want to strip away any Helvetica or Times definitions (or replace them with sans-serif and serif) – Jonik Oct 12 '09 at 9:48
  • That is an example he is showing you how to change the font so you just need to change the script to match your needs – admintech Oct 12 '09 at 9:57
  • Right... well, luckily I found a simpler way - no CSS hackery needed: superuser.com/questions/54216/… – Jonik Oct 12 '09 at 10:01

Just wondering, could you use local fonts and @font face css?

  • Hmm, not sure what exactly you mean, but I already found what I needed: superuser.com/questions/54216/… That's a very simple, system-wide solution. – Jonik Feb 12 '10 at 7:54
  • @font face CSS. It was just an idea that popped into my head, i might toy around with it. you can use @font-face to have FF use fonts from your own website, and maybe even local by modifing the standard FF css (google @font-face to learn more) – alpha1 Feb 14 '10 at 3:49

You need to add a "Grant" to that script any way...

Greasemonkey 1.0 adds a special Metadata Block imperative: @grant.

If a script does not specify any @grant values, Greasemonkey 1.0-1.9 will attempt to auto-detect the right settings. From GreaseMonkey 2.0, @grant none is assumed by default, if no other values are specified.[1]
If a script specifies any values (or they were auto detected), then it will be provided with only those API methods that it declares.
    The valid values are unsafeWindow, and the names of those GM_ prefixed values that you wish your script to be granted access to.
Otherwise the script will be granted no special API privileges, and thus run without the security constraints Greasemonkey scripts have traditionally had. If you want your script to operate in this mode, you should explicitly declare @grant none.


It's common for scripts (over half when last counted) not to use any special APIs at all. For such scripts, explicitly asking to be granted no special privileges means that the script will execute directly in the content page. This means no security sandbox, and none of its limitations, so accessing variables in the page just works, calling functions and reading their results also just works. To do so, simply:

// ==UserScript==
// @name        Grant None Example (can be omitted since GM 2.0)
// @include     http*
// @grant       none
// ==/UserScript==
console.log('This script grants no special privileges, so it runs without security limitations.');

If you do use one of Greasemonkey's APIs, you should explicitly ask for it to be granted to your script:

// ==UserScript==
// @name        Grant Some Example
// @include     http*
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==

var counter = GM_getValue('counter', 0);
console.log('This script has been run ' + counter + ' times.');
GM_setValue('counter', ++counter);

In this case, the script is asking to be granted access to both GM_getValue and GM_setValue, one on each @grant line. Specify the name of any Greasemonkey API to be granted access to it. (All scripts always get GM_info without specifically requesting it.) Temporarily, this would also work:

// ==UserScript==
// @name        Grant Legacy Example
// @include     http*
// ==/UserScript==

var counter = GM_getValue('counter', 0);
console.log('This script has been run ' + counter + ' times.');
GM_setValue('counter', ++counter);

This example will work in Greasemonkey version 1.0. When there are no @grant lines, Greasemonkey tries to detect which APIs are being used, and act as if those @grant lines had been specified. This detection may fail in certain cases, especially when eval() is used.

All scripts written before @grant should continue to work because of this, but you should change your scripts to specify @grant at your earliest convenience, so they don't break in the future. Compatibility Layer

Many of the Greasemonkey APIs have been duplicated by web standards like DOM Storage. If you only ever expect your script to operate on a single domain, you can use @grant none and its increased compatibility without any drawbacks immediately. Simply use an @require library to emulate Greasemonkey APIs with now-standard browser features:

// ==UserScript==
// @name        Grant None Example, With Shim
// @include     http://www.example.com/*
// @grant       none
// @require     https://gist.githubusercontent.com/arantius/3123124/raw/grant-none-shim.js
// ==/UserScript==

var counter = GM_getValue('counter', 0);
console.log('This script has been run ' + counter + ' times.');
GM_setValue('counter', ++counter);

This script will work the same as the example above, except that the grant none shim is providing API emulation with standard browser features. When the shim compatibility layer works well enough for your script, this is the best of both worlds. Scope

In the grant none case, the user script still has its own global scope, distinct from the content page's global scope. This means that a top-level var x = 1; will not be visible to the content scope, and thus will not break the page (i.e. if it depends on a variable x having a different value.) To write values to the content scope, do window.x = 1;.

If you @require a version of jQuery, it will implicitly assign to window.$ and window.jQuery. If the page you run on depends on a different version of jQuery, then this may break the page. To work around this problem, anywhere at the top level of your script do:

this.$ = this.jQuery = jQuery.noConflict(true);

This code will save a jQuery reference (into this, the script's global scope when running in the grant none mode), while removing it from window (the content global scope) and restoring anything originally stored there.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.