Reputation: 13109
Some fonts do not support CSS italic or bold (e.g. Zapfino does not support italic, as it is already pretty scripty-looking). I want to detect when a font style is not supported so I can disable styling buttons in an editor.
I tried something like this:
that.checkFontData = function( fontList )
{ var test = $("<span style='font-size:24px;absolute;visibility:hidden;height:auto;width:auto;white-space:nowrap;'>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678910</span>");
$('body').append( test );
for (var i= 0, iMax = fontList.length; i < iMax; ++i)
{ test.css( 'fontFamily', fontList[i] );
var normalWidth = test.outerWidth( true );
var normalHeight = test.outerHeight( true );
test.css( 'fontStyle', 'italic' );
var italicWidth = test.outerWidth( true );
var italicHeight = test.outerHeight( true );
test.css( 'fontStyle', 'normal' );
test.css( 'fontWeight', 'bold' );
var boldWidth = test.outerWidth( true );
var boldHeight = test.outerHeight( true );
console.log( fontList[i] + ", normal: " + normalWidth + ", bold: " + boldWidth + ", italic: " + italicWidth );
}
test.remove( );
};
but it does not work... many fonts which provide italic or bold report the same widths.
Next, I thought to detect this with a canvas element, but, alas, firefox does not even render italic text in the canvas, so that botches that idea.
What would you suggest?
Upvotes: 13
Views: 2601
Reputation: 16069
I've tested your code in jsFiddle, and it does give different sizes for natural webfonts like Georgia
and Arial
, but not for an externally loaded font like Snowburst One
(Googlefont).
After some research I've found out that for @font-face
loaded fonts no css font-transformations apply. People load the @font-face
variations and apply them like so:
body { font-family:"DroidSerifRegular", Georgia, serif; }
h1 {
font-family:"DroidSerifBold", Georgia, serif;
font-weight:normal;
}
em {
font-family:"DroidSerifItalic", Georgia, serif;
font-weight:normal;
font-style:normal;
}
strong em {
font-family:"DroidSerifBoldItalic", Georgia, serif;
font-weight:normal;
font-style:normal;
}
If you are using @font-face
fonts that have variations like in the example above, you might be able to come up with some sort of naming convention. Then you can check if these fonts exist by checking the width compared to the fallback font.
test.css('fontFamily', 'sans-serif');
var defaultWidth = test.outerWidth( true );
for (var i= 0, iMax = fontList.length; i < iMax; ++i)
{ test.css( 'fontFamily', fontList[i] + ', sans-serif' );
var normalWidth = test.outerWidth( true );
var normalHeight = test.outerHeight( true );
test.css( 'fontFamily', fontList[i] + 'Italic, sans-serif' );
var italicWidth = test.outerWidth( true );
var italicHeight = test.outerHeight( true );
test.css( 'fontFamily', fontList[i] + 'Bold, sans-serif' );
var boldWidth = test.outerWidth( true );
var boldHeight = test.outerHeight( true );
console.log( "default: "+ defaultWidth + ", " fontList[i] + ", normal: " + normalWidth + ", bold: " + boldWidth + ", italic: " + italicWidth );
}
If the styled versions have an altered width compared to the default, then it's a "Bingo"!
Note: this won't work for monospace fonts, as the width of all characters is always the same.
Upvotes: 1
Reputation: 15106
To detect bold and italic support, you can convert text into image and compare them.
The way to do it is:
canvas
See below (no need to append it to the DOM)canvas
png
)Regarding canvas
:
Next, I thought to detect this with a canvas element, but, alas, firefox does not even render italic text in the canvas, so that botches that idea.
Certain fonts are not italicize in a canvas in Firefox because the native italic font does not exist. Other browsers would try to psuedo-italicize (tilt) the font.
View on jsFiddle (this demo also tests for the Google font Snowburst One
)
function detectBoldItalic(fonts) {
// Create canvas
var canvas = document.createElement('canvas');
canvas.width = 1000;
canvas.height = 30;
var context = canvas.getContext("2d");
var test = {}, results = {};
// Default
context.font = "normal 16px a base case font";
context.fillText("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678910", 10, 20);
var standard = canvas.toDataURL("image/png");
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
// Start test
for (var i = 0; i < fonts.length; i++) {
var styles = ["normal", "bold", "italic"];
test[fonts[i]] = {};
results[fonts[i]] = {};
for (var j = 0; j < styles.length; j++) {
// Draw text in canvas
context.font = styles[j] + " 16px " + fonts[i];
context.fillText("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678910", 10, 20);
// Convert canvas to png
test[fonts[i]][styles[j]] = canvas.toDataURL("image/png");
// Clear canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
}
if (test[fonts[i]]["normal"] !== standard) {
results[fonts[i]]["bold"] = test[fonts[i]]["normal"] !== test[fonts[i]]["bold"] ? true:false; // Support bold
results[fonts[i]]["italic"] = test[fonts[i]]["normal"] !== test[fonts[i]]["italic"] ? true:false; // Support italic
} else {
results[fonts[i]] = false; // Font does not exist
}
}
return results;
}
console.log(detectBoldItalic(["Arial","Zapfino"]));
Upvotes: 4
Reputation: 756
Using Font.js you might have more reliable access to font metrics for your calculation. http://pomax.nihongoresources.com/pages/Font.js
Upvotes: 0