简体   繁体   中英

detect bold and italic support

Some fonts do not support CSS italic or bold (eg 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?

To detect bold and italic support, you can convert text into image and compare them.

The way to do it is:

  1. create a canvas See below (no need to append it to the DOM)
  2. draw text in the canvas
  3. convert the canvas into an image (here I use png )
  4. compare the base64 string of the image

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"]));

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).

JS fiddle of your script

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.

Using Font.js you might have more reliable access to font metrics for your calculation. http://pomax.nihongoresources.com/pages/Font.js

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM