If a character is entered in a text field and the currently applied font does not support that character, a backup font is used for that character. Is it possible to tell via Javascript or some other means when this is happening? Trying to create a script which alerts the user if a certain character is not supported by the font. Thanks for your help!
Asked
Active
Viewed 2,630 times
19
-
So just to be really clear: The browser has the font (as opposed to when you specify `font-face: wanglebrat, sans-serif` and the browser doesn't have `wanglebrat` and so it uses `sans-serif`), but you want to know when *specific characters* are missing, right? – T.J. Crowder Feb 24 '16 at 18:10
-
@T.J.Crowder Yes, that's correct – Hendeca Feb 24 '16 at 18:11
-
1Does the browser really use a different font if a character is entered into an input that the current font doesn't support? – adeneo Feb 24 '16 at 18:20
-
1@adeneo Yes, can confirm that in Chrome 48.0.2564.116 if you are typing into a text field and the font currently applied via CSS does not support the character. When a character that is supported is typed, the primary css font is used again. – Hendeca Feb 24 '16 at 18:26
-
I don't think I've ever seen that, can you set up a minimal example we can play with, and try to figure out how to know when the browser is using a different font. – adeneo Feb 24 '16 at 18:30
-
@adeneo Here is a fiddle https://jsfiddle.net/Hendeca/tjksf6fs/ however you may have to adjust the font family if you do not have Didot. I chose this one because it is fairly common and is serif so it's easy to see that the character is from a different font. – Hendeca Feb 24 '16 at 18:45
-
I do have that font, but how about a web-safe font instead, that makes it more obvious -> https://jsfiddle.net/tjksf6fs/2/ – adeneo Feb 24 '16 at 18:48
-
@adeneo Good idea. I tried a couple of websafe fonts but they had very wide character support. Impact is a good one though and works with this example. Thanks! – Hendeca Feb 24 '16 at 18:56
-
Doesn't seem possible? `getComputedStyle` won't work, and it doesn't look like there are any properties that are useful. I did find a [font-guessing library](https://github.com/JulienCabanes/Font-Guess), but that doesn't seem to work either, and here's a related [question](http://stackoverflow.com/questions/7444451/how-to-get-the-actual-rendered-font-when-its-not-defined-in-css). The Chrome console does show what font is rendered, but there doesn't seem like there's any way to get that value with javascript. – adeneo Feb 24 '16 at 19:23
-
Interesting to see that when you remove the sans-serif fallback font in the fiddle the character is still visible. – Kwebble Feb 24 '16 at 22:04
2 Answers
3
This sounds like a job for something like fontkit.js or opentype.js, or even Font.js, all of which can test fonts for glyph support. System fonts are not covered this way (Font.js might work, it'll probably report a width 0 for the tested glyph) but then these are typically the "web safe" fonts, of which we already know exactly which glyphs are supported because everyone uses the same ones. For testing "holes" in a custom font, though, any of the previously mentioned three should already do what you intended to implement.

Mike 'Pomax' Kamermans
- 49,297
- 16
- 112
- 153
-
I'm intrigued by Font.js as it seems to be the simplest and isn't a node module, but when reading the documentation I couldn't quite figure out how I would test for the presence of a specific glyph. Can you point me to the proper methods to achieve that? – Hendeca Feb 25 '16 at 18:51
-
You're looking for `font.measureText(textString, fontSize));`, probably as a `forEach` loop for all glyphs that need rendering. Any `measureText` that yields a metrics object with width 0 is very much not supported by the font in question. – Mike 'Pomax' Kamermans Feb 25 '16 at 18:55
-
1also note that we're no longer living in a world with "only for node" or "only for browser" libraries. It's all JS, so most of the time, things will work fine in both, as long as (just as for pure browser solutions) you have the right shims in place. OpenType.js works in both for instance. FontKit.js can be trivially bundled for the browser (with `browserify --standalone` or something), and Font.js will happily work in Node provided you can shim a canvas for it. – Mike 'Pomax' Kamermans Feb 25 '16 at 18:57
-
Thank you! Yes, it's more a question of how lightweight the solution would be for my purposes. I think if I needed more features of the other libraries I'd be more inclined to use them – Hendeca Feb 25 '16 at 19:02
-
I accepted this answer since it seems to me to be the most reliable way to do this. I ended up taking an altogether different approach to this problem (basically restricting input only to certain ranges of ascii characters) but I can see this being something that might benefit someone else. Both of the answers submitted seem valid, but in my experience, the other was less reliable and therefore I'm considering this "more correct" since I have to pick one. – Hendeca May 23 '16 at 22:06
3
Checking the width of the character in the font, and comparing it with the fallback, you can infer if it is using the fallback font. This test is probably not 100% reliable, but you can do something like:
var text = $(".main-text").html();
var chars = text.split("");
for(var i = 0, len = chars.length; i < len; i++){
var str = chars[i]; str+=str;str+=str;str+=str;
$("#test1, #test2").html(str);
var w1 = $("#test1").width();
var w2 = $("#test2").width();
if(w1 == w2 && w1 != 0){
alert("char not supported " + chars[i]);
}
}
.main-text {
width: 50%;
height: 300px;
font-family: Impact, sans-serif;
font-size: 16px;
}
#test1, #test2 {
position: fixed;
top: -100px;
font-size: 16px;
}
#test1 {
font-family: Impact, sans-serif;
}
#test2 {
font-family: sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="main-text">
Serif Font
This E is not supported: ể
</textarea>
<span id="test1"></span>
<span id="test2"></span>

jvilhena
- 1,131
- 8
- 21
-
1Perhaps it's not clear you need to define the `test1` and `test2` elements here with the different font-families. And if you set a large font-size on them then smaller differences will be detected. – Kwebble Feb 24 '16 at 22:18
-
1This is a clever solution, though I'm finding that it doesn't work with all fonts. I tried changing the font back to Didot as a test and found that every character was matching as invalid. I added an event listener that listens for changes to the textarea and pulls the content via val() instead of html() so that I could change the text and see live results for convenience. https://jsfiddle.net/Hendeca/2xpLzuyk/ – Hendeca Feb 24 '16 at 23:36
-
that's literally what I wrote https://github.com/Pomax/Font.js for, 2 years ago =) In order to be 100% reliable, it uses canvas, not an html element, and then does a line scan to check painted pixels. – Mike 'Pomax' Kamermans Feb 25 '16 at 06:23
-
1@Hendeca I don't have the font, so I can't test it, but you can try to add extra tests with a different fall-back font, like https://jsfiddle.net/tjksf6fs/5/ – jvilhena Feb 25 '16 at 15:07
-
@jvilhena That seems to work much better! I'm trying to decide between this solution and using a library at the moment. Thanks for providing this. – Hendeca Feb 25 '16 at 18:37