For single-line text, it is relatively easy to adjust the font size of the container. This article mainly describes the method of adapting multi-line text to the container (also applies to the single-line case), but it is a little more complicated with one more dimension

preface

  • You need to know how to operate mathematical inequalities
  • We need to know the root formula of a quadratic equation with one variable
  • In this paper, font spacing and line height are not considered. It is assumed that font spacing is 0 and line height is 1. If necessary, corresponding values are added to the font size FS

The preset variables

  • To be solved: font sizefs
  • Known quantity: container widthWContainer heightH, word numberNUM
  • Unknown: The number of lines when the text fits the container in the best way:rowAnd the number of columns:col

Steps to calculate the minimum font maximum value

  1. The inequality is derived from the relationship between the number of lines, font size, and container height: h-fs <= row * fs <= H

  2. The inequality is derived from the relationship between the column number, font size, and container width: W-fs <= col * fs <= W

  3. Row * col >= NUM. Row * col >= NUM

  4. By eliminating the unknowns with the three inequalities (row * fs <= H and col * fs <= W in steps 1 and 2 multiplied by step 3 to cancel row and col), we can easily obtain: Fs * fs * NUM <= H * W, the maximum value of fs can be obtained by solving the inequality. The limit of this value is that the text exactly fills the container. In fact, this case almost does not exist, because it is difficult to guarantee that each row or column contains exactly how many words, leaving a gap less than one word. Therefore, the optimal value of FS cannot be this maximum, causing text to overflow the container

  5. Here’s how to get the minimum of FS.

    1. Using steps 1 and 2H - fs <= row * fsW - fs <= col * fs, and can be obtained by multiplying(H - fs) * (W - fs) <= row * col * fs * fs
    2. Step 3 Obtainfs * fs * NUM <= row * col * fs * fs
    3. These two inequalities are the same on the right-hand side, but if we compare the left-hand side, we can think of it this way, that the area is zeroH * WIs divided into rectangles with an area offs * fs(there will be gaps, but this does not affect the comparison, assuming it can be divided exactly),(H - fs) * (W - fs)It’s less than the original rectangleR + L - 1(R for a row, L for a column), andfs * fs * NUMSaid aNUMOne square, this oneNUMFollowing the principle that the text should fit the container in the best way, this number of squares must be filled to the last line of the container, which is the least square from the original rectangleR(R for row) square
    4. Therefore, we get(H - fs) * (W - fs) <= fs * fs * NUM, can be obtained by finding the root formula of the quadratic equation of one variablefsThe minimum value
    5. The limit of this value is that the text fills the container with a line of space so that no overflow occurs, but it is not enough to fit the container in the best way (just fill),fsThe optimal solution is between the maximum and the minimum.

Deduce the optimal solution

  • There are two methods: one is to start from the maximum value, check whether the height overflows, subtract a fixed value (set to 1) and then check until the overflow does not occur, and the optimal solution is obtained
  • The other is to start from the minimum value and check whether the height overflows. If there is no overflow, add 1 and then check until the overflow, and get the optimal solution
  • Because the analysis shows that the optimal solution is closer to the minimum value, the number of cycles can be reduced from the minimum value
  • Check method: Starting from the minimum value,Math.ceil(NUM / Math.floor(W / fs)) * fs > HOverflows if this condition is met, abort the loop, otherwisefs + 1Continue the loop, and when the loop is overfs - 1For the optimal solution
  • After obtaining the optimal solution, you can set the maximum and minimum values of the desired font size

Reference code

autoModifyFontSize(elList){
    elList.forEach(el= > {
        const NUM = el.innerText.length;
        const W = el.offsetWidth;
        const H = el.offsetHeight;
        const minFontSize = 28;
        const maxFontSize = 84;
        H-fs <= row * fs <= H w-fs <= column * fs <= W row * column >= NUM
        // let fontSizeMax = Math.sqrt(W * H / NUM);
        // console.log('Max', fontSizeMax)
        let fontSizeMin = (Math.sqrt((W + H) * (W + H) + 4 * W * H * NUM - 4 * W * H) - W - H) / (2 * NUM - 2)
        console.log('Min', fontSizeMin)

        let signState = true;
        let fontSize = fontSizeMin;
        while (signState) {
            if(Math.ceil(NUM / Math.floor(W / fontSize)) * fontSize > H){
                / / stop
                signState = false;
                break;
            }else{
                / / to continue
                signState = true;
            }
            fontSize = fontSize + 1;
        }
        fontSize = fontSize - 1;

        if(fontSize >= maxFontSize){
            fontSize = maxFontSize
        }
        if(fontSize <= minFontSize){
            fontSize = minFontSize
        }
        console.log(fontSize)
        el.style.fontSize = `${fontSize}px`; })},Copy the code