自动调整动态文本大小以填充固定大小的容器

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

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

我可能想从最大字体大小开始-也许是32px,并且当文本太大而无法容纳容器时,请缩小字体大小直到适合为止。

蛋蛋L2020/03/23 14:49:52

我喜欢

let name = "Making statements based on opinion; back them up with references or personal experience."
let originFontSize = 15;
let maxDisplayCharInLine = 50; 
let fontSize = Math.min(originFontSize, originFontSize / (name.length / maxDisplayCharInLine));
西里Near2020/03/23 14:49:52

这是我创建的最优雅的解决方案。它使用二进制搜索,进行10次迭代。天真的方法是执行while循环并将字体大小增加1,直到元素开始溢出。您可以使用element.offsetHeightelement.scrollHeight确定元素何时开始溢出如果scrollHeight大于offsetHeight,则字体大小太大。

二进制搜索是一种更好的算法。它还受您要执行的迭代次数的限制。只需调用flexFont并插入div ID,它将在8px96px之间调整字体大小

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

请注意,如果需要,可以更改为使用offsetWidthscrollWidth,或将两者都添加到此功能。

// 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
    };
}
小卤蛋2020/03/23 14:49:52

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

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";
    }
}
宝儿2020/03/23 14:49:52

我从Marcus Ekwall分叉了上面的脚本:https : //gist.github.com/3945316并根据我的喜好进行了调整,现在在调整窗口大小时会触发它,以便孩子始终适合其容器。我已将以下脚本粘贴以供参考。

(function($) {
    $.fn.textfill = function(maxFontSize) {
        maxFontSize = parseInt(maxFontSize, 10);
        return this.each(function(){
            var ourText = $("span", this);
            function resizefont(){
                var parent = ourText.parent(),
                maxHeight = parent.height(),
                maxWidth = parent.width(),
                fontSize = parseInt(ourText.css("fontSize"), 10),
                multiplier = maxWidth/ourText.width(),
                newSize = (fontSize*(multiplier));
                ourText.css("fontSize", maxFontSize > 0 && newSize > maxFontSize ? maxFontSize : newSize );
            }
            $(window).resize(function(){
                resizefont();
            });
            resizefont();
        });
    };
})(jQuery);
理查德小小2020/03/23 14:49:52

由于性能不好,我发现以前的解决方案都不够用,所以我自己编写了使用简单数学而不是循环的解决方案。在所有浏览器中也应该正常工作。

根据此性能测试案例,它比此处找到的其他解决方案要快得多。

(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中

神乐GO神无2020/03/23 14:49:52

其他大多数答案都使用循环来减小字体大小,直到适合div为止,这非常慢,因为每次字体更改大小时页面都需要重新渲染元素。最终,我不得不编写自己的算法,以使其能够以某种方式定期执行其内容,而不会冻结用户浏览器。我添加了一些其他功能(旋转文本,添加填充)并将其打包为jQuery插件,您可以在以下位置获得它:

https://github.com/DanielHoffmann/jquery-bigtext

只需致电

$("#text").bigText();

它将很好地适合您的容器。

在这里查看实际操作:

http://danielhoffmann.github.io/jquery-bigtext/

现在它有一些限制,div必须具有固定的高度和宽度,并且不支持将文本换成多行。

我将努力获得一个设置最大字体大小的选项。

编辑:我发现插件有更多问题,除了标准插件之外,它不能处理其他盒子模型,并且div不能有边距或边框。我会努力的。

Edit2:我现在解决了这些问题和限制,并添加了更多选项。您可以设置最大字体大小,也可以选择使用宽度,高度或同时使用这两者来限制字体大小。我将努力在wrapper元素中接受max-width和max-height值。

Edit3:我已经将插件更新为版本1.2.0。对代码进行了重大清理,并添加了新选项(verticalAlign,horizo​​ntalAlign,textAlign),并支持span标记内的内部元素(如换行符或超棒的字体图标)。

老丝2020/03/23 14:49:52

尽管我偶尔会为这个答案而投票(谢谢!),但实际上,这并不是解决此问题的最佳方法。请在此处查看其他一些奇妙的答案,尤其是那些发现解决方案而没有循环的答案。


尽管如此,为了参考,这是我的原始答案

<html>
<head>
<style type="text/css">
    #dynamicDiv
    {
    background: #CCCCCC;
    width: 300px;
    height: 100px;
    font-size: 64px;
    overflow: hidden;
    }
</style>

<script type="text/javascript">
    function shrink()
    {
        var textSpan = document.getElementById("dynamicSpan");
        var textDiv = document.getElementById("dynamicDiv");

        textSpan.style.fontSize = 64;

        while(textSpan.offsetHeight > textDiv.offsetHeight)
        {
            textSpan.style.fontSize = parseInt(textSpan.style.fontSize) - 1;
        }
    }
</script>

</head>
<body onload="shrink()">
    <div id="dynamicDiv"><span id="dynamicSpan">DYNAMIC FONT</span></div>
</body>
</html>

这是带有的版本

<html>
<head>
<style type="text/css">
.dynamicDiv
{
    background: #CCCCCC;
    width: 300px;
    height: 100px;
    font-size: 64px;
    overflow: hidden;
}
</style>

<script type="text/javascript">
    function shrink()
    {
        var textDivs = document.getElementsByClassName("dynamicDiv");
        var textDivsLength = textDivs.length;

        // Loop through all of the dynamic divs on the page
        for(var i=0; i<textDivsLength; i++) {

            var textDiv = textDivs[i];

            // Loop through all of the dynamic spans within the div
            var textSpan = textDiv.getElementsByClassName("dynamicSpan")[0];

            // Use the same looping logic as before
            textSpan.style.fontSize = 64;

            while(textSpan.offsetHeight > textDiv.offsetHeight)
            {
                textSpan.style.fontSize = parseInt(textSpan.style.fontSize) - 1;
            }

        }

    }
</script>

</head>
<body onload="shrink()">
    <div class="dynamicDiv"><span class="dynamicSpan">DYNAMIC FONT</span></div>
    <div class="dynamicDiv"><span class="dynamicSpan">ANOTHER DYNAMIC FONT</span></div>
    <div class="dynamicDiv"><span class="dynamicSpan">AND YET ANOTHER DYNAMIC FONT</span></div>
</body>
</html>