我需要显示用户输入的文本到一个固定大小的div。我想要的是字体大小自动调整,以便文本尽可能多地填充框。

如果div是400px x 300px。如果有人输入ABC,那么字体就很大。如果他们输入一个段落,那么它将是一个很小的字体。

我可能想要从最大字体大小开始——可能是32px,当文本太大而不适合容器时,缩小字体大小直到它适合。


当前回答

我找到了一种方法来防止使用循环来缩小文本。它通过将字体大小乘以容器宽度和内容宽度之间的比率来调整字体大小。因此,如果容器的宽度是内容的1/3,字体大小将减少1/3,容器的宽度也将减少1/3。为了扩大规模,我使用了while循环,直到内容大于容器。

function fitText(outputSelector){
    // max font size in pixels
    const maxFontSize = 50;
    // get the DOM output element by its selector
    let outputDiv = document.getElementById(outputSelector);
    // get element's width
    let width = outputDiv.clientWidth;
    // get content's width
    let contentWidth = outputDiv.scrollWidth;
    // get fontSize
    let fontSize = parseInt(window.getComputedStyle(outputDiv, null).getPropertyValue('font-size'),10);
    // if content's width is bigger than elements width - overflow
    if (contentWidth > width){
        fontSize = Math.ceil(fontSize * width/contentWidth,10);
        fontSize =  fontSize > maxFontSize  ? fontSize = maxFontSize  : fontSize - 1;
        outputDiv.style.fontSize = fontSize+'px';   
    }else{
        // content is smaller than width... let's resize in 1 px until it fits 
        while (contentWidth === width && fontSize < maxFontSize){
            fontSize = Math.ceil(fontSize) + 1;
            fontSize = fontSize > maxFontSize  ? fontSize = maxFontSize  : fontSize;
            outputDiv.style.fontSize = fontSize+'px';   
            // update widths
            width = outputDiv.clientWidth;
            contentWidth = outputDiv.scrollWidth;
            if (contentWidth > width){
                outputDiv.style.fontSize = fontSize-1+'px'; 
            }
        }
    }
}

这段代码是我上传到Github https://github.com/ricardobrg/fitText/的测试的一部分

其他回答

下面是这个解决方案的另一个版本:

shrinkTextInElement : function(el, minFontSizePx) {
    if(!minFontSizePx) {
        minFontSizePx = 5;
    }
    while(el.offsetWidth > el.parentNode.offsetWidth || el.offsetHeight > el.parentNode.offsetHeight) {

        var newFontSize = (parseInt(el.style.fontSize, 10) - 3);
        if(newFontSize <= minFontSizePx) {
            break;
        }

        el.style.fontSize = newFontSize + "px";
    }
}

它使用二分搜索,进行10次迭代。最简单的方法是执行while循环,并将字体大小增加1,直到元素开始溢出。可以使用element来确定元素何时开始溢出。offsetHeight和element.scrollHeight。如果scrollHeight大于offsetHeight,则字体大小过大。

二分搜索是一个更好的算法。它还受到希望执行的迭代次数的限制。只需调用flexFont并插入div id,它将在8px到96px之间调整字体大小。

我花了一些时间研究这个主题,并尝试了不同的库,但最终我认为这是最简单、最直接的解决方案。

注意,如果你愿意,你可以更改使用offsetWidth和scrollWidth,或者将两者都添加到这个函数中。

    // Set the font size using overflow property and div height
    function flexFont(divId) {
        var content = document.getElementById(divId);
        content.style.fontSize = determineMaxFontSize(content, 8, 96, 10, 0) + "px";
    };

    // Use binary search to determine font size
    function determineMaxFontSize(content, min, max, iterations, lastSizeNotTooBig) {
        if (iterations === 0) {
            return lastSizeNotTooBig;
        }
        var obj = fontSizeTooBig(content, min, lastSizeNotTooBig);

        // if `min` too big {....min.....max.....}
        // search between (avg(min, lastSizeTooSmall)), min)
        // if `min` too small, search between (avg(min,max), max)
        // keep track of iterations, and the last font size that was not too big
        if (obj.tooBig) {
            (lastSizeTooSmall === -1) ?
                determineMaxFontSize(content, min / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall) :
                    determineMaxFontSize(content, (min + lastSizeTooSmall) / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall);
            
        } else {
            determineMaxFontSize(content, (min + max) / 2, max, iterations - 1, obj.lastSizeNotTooBig, min);
        }
    }

    // determine if fontSize is too big based on scrollHeight and offsetHeight, 
    // keep track of last value that did not overflow
    function fontSizeTooBig(content, fontSize, lastSizeNotTooBig) {
        content.style.fontSize = fontSize + "px";
        var tooBig = content.scrollHeight > content.offsetHeight;
        return {
            tooBig: tooBig,
            lastSizeNotTooBig: tooBig ? lastSizeNotTooBig : fontSize
        };
    }

这是基于GeekyMonkey上面发布的内容,并进行了一些修改。

; (function($) {
/**
* Resize inner element to fit the outer element
* @author Some modifications by Sandstrom
* @author Code based on earlier works by Russ Painter (WebDesign@GeekyMonkey.com)
* @version 0.2
*/
$.fn.textfill = function(options) {

    options = jQuery.extend({
        maxFontSize: null,
        minFontSize: 8,
        step: 1
    }, options);

    return this.each(function() {

        var innerElements = $(this).children(':visible'),
            fontSize = options.maxFontSize || innerElements.css("font-size"), // use current font-size by default
            maxHeight = $(this).height(),
            maxWidth = $(this).width(),
            innerHeight,
            innerWidth;

        do {

            innerElements.css('font-size', fontSize);

            // use the combined height of all children, eg. multiple <p> elements.
            innerHeight = $.map(innerElements, function(e) {
                return $(e).outerHeight();
            }).reduce(function(p, c) {
                return p + c;
            }, 0);

            innerWidth = innerElements.outerWidth(); // assumes that all inner elements have the same width
            fontSize = fontSize - options.step;

        } while ((innerHeight > maxHeight || innerWidth > maxWidth) && fontSize > options.minFontSize);

    });

};

})(jQuery);

我没有发现任何以前的解决方案是足够的,由于糟糕的性能,所以我自己使用简单的数学,而不是循环。在所有浏览器中都可以正常工作。

根据这个性能测试用例,它比这里找到的其他解决方案快得多。

(function($) {
    $.fn.textfill = function(maxFontSize) {
        maxFontSize = parseInt(maxFontSize, 10);
        return this.each(function(){
            var ourText = $("span", this),
                parent = ourText.parent(),
                maxHeight = parent.height(),
                maxWidth = parent.width(),
                fontSize = parseInt(ourText.css("fontSize"), 10),
                multiplier = maxWidth/ourText.width(),
                newSize = (fontSize*(multiplier-0.1));
            ourText.css(
                "fontSize", 
                (maxFontSize > 0 && newSize > maxFontSize) ? 
                    maxFontSize : 
                    newSize
            );
        });
    };
})(jQuery);

如果你想投稿,我已经把这个添加到Gist。

你可以使用FitText.js (github页面)来解决这个问题。与TextFill相比是非常小和有效的。TextFill使用了昂贵的while循环,而FitText没有。

FitText也更灵活(我在一个有非常特殊要求的项目中使用它,工作起来像个冠军!)。

HTML:

<div class="container">
  <h1 id="responsive_headline">Your fancy title</h1>
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="jquery.fittext.js"></script>
<script>
  jQuery("#responsive_headline").fitText();
</script>

你也可以设置选项:

<script>
  jQuery("#responsive_headline").fitText(1, { minFontSize: '30px', maxFontSize: '90px'});
</script>

CSS:

#responsive_headline {
   width: 100%;
   display: block;
}

如果你需要它,FitText也有一个非jquery版本。