11

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

kayahr
  • 20,913
  • 29
  • 99
  • 147
  • 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? – thirtydot Apr 11 '11 at 08:33
  • I agree with thirtydot, you can even copy parsed css from developer tools or firebug. – Ivan Ivanic Apr 11 '11 at 08: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. – kayahr Apr 11 '11 at 08: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? – thirtydot Apr 11 '11 at 09: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. – kayahr Apr 11 '11 at 09:30

4 Answers4

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'));

thirtydot
  • 224,678
  • 48
  • 389
  • 349
  • 1
    [I think you'll find](http://jsfiddle.net/Mzrmd/) `$test` points to the `body` element (your example removes the `body` element). You want `var $test = $('').appendTo('body')`. :) – alex Apr 11 '11 at 10:08
  • 1
    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. – Bill Dami Jan 03 '13 at 19:35
  • Straightforward and efficient answer. +1 – Brice Coustillas Oct 12 '17 at 06:43
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

Community
  • 1
  • 1
mattsven
  • 22,305
  • 11
  • 68
  • 104
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
    }
}
kayahr
  • 20,913
  • 29
  • 99
  • 147
3

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

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335