Skip to content Skip to sidebar Skip to footer

Css Font-size And Line-height Not Matching The Baseline

I'm trying to do something that should be very simple but I've spent my day between failures and forums.. I would like to adjust my font in order to match my baseline. On indesign

Solution 1:

It is a bit complicated - you have to measure the fonts first (as InDesign does) and calculate "line-height", the thing you called "bottom_gap" and some other stuff

I'm pretty sure we can do something in JavaScript..

You are right – but for Typography JS is used to calculate the CSS (depending on the font metrics)

Did demo the first step (measuring a font) here https://codepen.io/sebilasse/pen/gPBQqm It is just showing graphically what is measured [for the technical background]

This measuring is needed because every font behaves totally different in a "line".

Here is a generator which could generate such a Typo CSS:

https://codepen.io/sebilasse/pen/BdaPzN

A function to measure could be based on <canvas> and look like this :

functiongetMetrics(fontName, fontSize) {
  // NOTE: if there is no getComputedStyle, this library won't work.if(!document.defaultView.getComputedStyle) {
    throw("ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values.");
  }
  if (!document.querySelector('canvas')) {
    var _canvas = document.createElement('canvas');
    _canvas.width = 220; _canvas.height = 220;
    document.body.appendChild(_canvas);
  }
  // Store the old text metrics function on the Canvas2D prototypeCanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText;
  /**
   *  Shortcut function for getting computed CSS values
   */var getCSSValue = function(element, property) {
    returndocument.defaultView.getComputedStyle(element,null).getPropertyValue(property);
  };
  /**
   * The new text metrics function
   */CanvasRenderingContext2D.prototype.measureText = function(textstring) {
    var metrics = this.measureTextWidth(textstring),
        fontFamily = getCSSValue(this.canvas,"font-family"),
        fontSize = getCSSValue(this.canvas,"font-size").replace("px",""),
        isSpace = !(/\S/.test(textstring));
        metrics.fontsize = fontSize;

    // For text lead values, we meaure a multiline text container.var leadDiv = document.createElement("div");
    leadDiv.style.position = "absolute";
    leadDiv.style.margin = 0;
    leadDiv.style.padding = 0;
    leadDiv.style.opacity = 0;
    leadDiv.style.font = fontSize + "px " + fontFamily;
    leadDiv.innerHTML = textstring + "<br/>" + textstring;
    document.body.appendChild(leadDiv);
    // Make some initial guess at the text leading (using the standard TeX ratio)
    metrics.leading = 1.2 * fontSize;
    // Try to get the real value from the browservar leadDivHeight = getCSSValue(leadDiv,"height");
    leadDivHeight = leadDivHeight.replace("px","");
    if (leadDivHeight >= fontSize * 2) { metrics.leading = (leadDivHeight/2) | 0; }
    document.body.removeChild(leadDiv);
    // if we're not dealing with white space, we can compute metricsif (!isSpace) {
        // Have characters, so measure the textvar canvas = document.createElement("canvas");
        var padding = 100;
        canvas.width = metrics.width + padding;
        canvas.height = 3*fontSize;
        canvas.style.opacity = 1;
        canvas.style.fontFamily = fontFamily;
        canvas.style.fontSize = fontSize;
        var ctx = canvas.getContext("2d");
        ctx.font = fontSize + "px " + fontFamily;

        var w = canvas.width,
            h = canvas.height,
            baseline = h/2;

        // Set all canvas pixeldata values to 255, with all the content// data being 0. This lets us scan for data[i] != 255.
        ctx.fillStyle = "white";
        ctx.fillRect(-1, -1, w+2, h+2);
        ctx.fillStyle = "black";
        ctx.fillText(textstring, padding/2, baseline);
        var pixelData = ctx.getImageData(0, 0, w, h).data;

        // canvas pixel data is w*4 by h*4, because R, G, B and A are separate,// consecutive values in the array, rather than stored as 32 bit ints.var i = 0,
            w4 = w * 4,
            len = pixelData.length;

        // Finding the ascent uses a normal, forward scanlinewhile (++i < len && pixelData[i] === 255) {}
        var ascent = (i/w4)|0;

        // Finding the descent uses a reverse scanline
        i = len - 1;
        while (--i > 0 && pixelData[i] === 255) {}
        var descent = (i/w4)|0;

        // find the min-x coordinatefor(i = 0; i<len && pixelData[i] === 255; ) {
          i += w4;
          if(i>=len) { i = (i-len) + 4; }}
        var minx = ((i%w4)/4) | 0;

        // find the max-x coordinatevar step = 1;
        for(i = len-3; i>=0 && pixelData[i] === 255; ) {
          i -= w4;
          if(i<0) { i = (len - 3) - (step++)*4; }}
        var maxx = ((i%w4)/4) + 1 | 0;

        // set font metrics
        metrics.ascent = (baseline - ascent);
        metrics.descent = (descent - baseline);
        metrics.bounds = { minx: minx - (padding/2),
                           maxx: maxx - (padding/2),
                           miny: 0,
                           maxy: descent-ascent };
        metrics.height = 1+(descent - ascent);
    } else {
        // Only whitespace, so we can't measure the text
        metrics.ascent = 0;
        metrics.descent = 0;
        metrics.bounds = { minx: 0,
                           maxx: metrics.width, // Best guessminy: 0,
                           maxy: 0 };
        metrics.height = 0;
    }
    return metrics;
  };

Note that you also need a good "reset.css" to reset the browser margins and paddings. You click "show CSS" and you can also use the generated CSS to mix multiple fonts: If they have different base sizes, normalize the second:

var factor = CSS1baseSize / CSS2baseSize;

and now recalculate each font in CSS2 with

var size = size * factor;

See a demo in https://codepen.io/sebilasse/pen/oENGev?editors=1100

What if it comes to images? The following demo uses two fonts with the same metrics plus an extra JS part. It is needed to calculate media elements like images for the baseline grid : https://codepen.io/sebilasse/pen/ddopBj

Post a Comment for "Css Font-size And Line-height Not Matching The Baseline"