12

I need to parse the CSS font shorthand format into the separate components (font-family, font-size, font-weight, ...). This shorthand format looks pretty complicated. Here are two examples:

10px sans-serif
bold italic small-caps 1em/1.5em verdana,sans-serif

Before I start writing a parser for it, is there an already existing parser out there I could use (Preferably written in JavaScript)?

5
  • 2
    Why do you need to do this? The browser has a parser built in that does this - would it not be easier to apply your font property string to a temporary element and read off the separate properties? Commented Apr 11, 2011 at 8:33
  • I agree with thirtydot, you can even copy parsed css from developer tools or firebug. Commented Apr 11, 2011 at 8:48
  • 1
    I thought about that but it doesn't work. When setting "font" then other properties like fontSize and fontFamily are still empty. maybe it works in your browser, my Chrome doesn't support it. Commented Apr 11, 2011 at 8:53
  • Do you need the exact values? For example, instead of 1.5em line-height, would 24px (or whatever exact px value it happens to work out as) be acceptable? Would you mind using a JavaScript library such as jQuery? Commented Apr 11, 2011 at 9:05
  • My question is generic enough so using a temporary DOM element and using jquery's css() function might be accepted as an answer, but I prefer a solution which doesn't need a temporary DOM element. Commented Apr 11, 2011 at 9:30

4 Answers 4

11

Here's a "temporary DOM element and using jquery's css() function" solution:

http://jsfiddle.net/thirtydot/tpSsE/2/

var $test = $('<span />');
$test.css('font', 'bold italic small-caps 1em/1.5em verdana,sans-serif');

alert($test.css('fontWeight'));
alert($test.css('fontStyle'));
alert($test.css('fontVariant'));
alert($test.css('fontSize'));
alert($test.css('lineHeight'));
alert($test.css('fontFamily'));

Sign up to request clarification or add additional context in comments.

3 Comments

I think you'll find $test points to the body element (your example removes the body element). You want var $test = $('<span />').appendTo('body'). :)
Fyi, it is not necessary to insert the $test element into the DOM (the .appendTo('body') part of the first line) in order for this to work. And therefore you no longer need the $test.remove() statement either. Not a big deal, just a bit cleaner and probably a very small performance gain.
Straightforward and efficient answer. +1
9

Pure free-range Javascript version:

var parsedStyleForCSS = function(cssString){
    var el = document.createElement("span");
    el.setAttribute("style", cssString);

    return el.style; // CSSStyleDeclaration object
};

var parsedStyle = parsedStyleForCSS("font: bold italic small-caps 1em/1.5em verdana,sans-serif");

console.log(parsedStyle["fontWeight"]); // bold
console.log(parsedStyle["fontStyle"]); // italic
console.log(parsedStyle["fontVariant"]); // small-caps
console.log(parsedStyle["fontSize"]); // 1em
console.log(parsedStyle["lineHeight"]); // 1.5em
console.log(parsedStyle["fontFamily"]); // verdana, sans-serif

If you're looking to do something similar with complete stylesheets, see this answer: Parsing CSS in JavaScript / jQuery

Comments

8

Here is my own humble try of a font parser function I just created. But I'm not sure if it works with all specialities of the font short hand format.

function parseFont(font)
{
    var fontFamily = null,
        fontSize = null,
        fontStyle = "normal",
        fontWeight = "normal",
        fontVariant = "normal",
        lineHeight = "normal";

    var elements = font.split(/\s+/);
    outer: while (element = elements.shift())
    {
        switch (element)
        {
            case "normal":
                break;

            case "italic":
            case "oblique":
                fontStyle = element;
                break;

            case "small-caps":
                fontVariant = element;
                break;

            case "bold":
            case "bolder":
            case "lighter":
            case "100":
            case "200":
            case "300":
            case "400":
            case "500":
            case "600":
            case "700":
            case "800":
            case "900":
                fontWeight = element;
                break;

            default:
                if (!fontSize)
                {
                    var parts = element.split("/");
                    fontSize = parts[0];
                    if (parts.length > 1) lineHeight = parts[1];
                    break;
                }

                fontFamily = element;
                if (elements.length)
                    fontFamily += " " + elements.join(" ");
                break outer;
        }
    }

    return {
        "fontStyle": fontStyle,
        "fontVariant": fontVariant,
        "fontWeight": fontWeight,
        "fontSize": fontSize,
        "lineHeight": lineHeight,
        "fontFamily": fontFamily
    }
}

1 Comment

+1, seems fine with a couple of quick tests, given valid input.
3

The parse rules are described in the spec which also has a guide to reading the language used to express the value rules.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.