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


312

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

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

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


119
可能是最令人惊奇的功能之一,应该在不需要JS的情况下添加到HTML5 / CSS3中。
约翰·马格诺里亚

我进行了一些测量,更改了动态文本的长度和容器的大小,以找出哪种字体大小可使文本完美适合。在进行了一些回归分析之后,我想出了一个简单的数学函数,它将自动生成最佳的字体大小。
Kim

2
事实证明,为您提供最佳字体大小的图形由f(x)= g(字母)*(x / 1000)^ n给出,其中g(x)是一个简单函数,n取决于您使用的字体。(尽管它可以为所有字体提供标准值,但是如果您不想对其进行调整以使其绝对完美……)。x是容器的大小(以正方形像素为单位)。
Kim

1
如果您仍然有兴趣,我可以添加答案。我个人认为,首先生成正确的字体大小是一种更好的方法,而不是尝试并失败直到脚本“正确”为止。
Kim

1
检查我的答案以获得更好的方法
Hoffmann

Answers:


167

谢谢攻击。我想使用jQuery。

您为我指出了正确的方向,这就是我最终得到的结果:

这是插件的链接:https : //plugins.jquery.com/textfill/
和源的链接:http : //jquery-textfill.github.io/

;(function($) {
    $.fn.textfill = function(options) {
        var fontSize = options.maxFontPixels;
        var ourText = $('span:visible:first', this);
        var maxHeight = $(this).height();
        var maxWidth = $(this).width();
        var textHeight;
        var textWidth;
        do {
            ourText.css('font-size', fontSize);
            textHeight = ourText.height();
            textWidth = ourText.width();
            fontSize = fontSize - 1;
        } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
        return this;
    }
})(jQuery);

$(document).ready(function() {
    $('.jtextfill').textfill({ maxFontPixels: 36 });
});

和我的HTML是这样的

<div class='jtextfill' style='width:100px;height:50px;'>
    <span>My Text Here</span>
</div>

这是我的第一个jquery插件,因此可能不尽如人意。指针当然是受欢迎的。


8
我实际上只是将其清理并打包为插件,可从
jquery.com上

3
@GeekyMonkey,您是否拉了插件?只是跟随到该页面的伪链接,并认为我可以看一下,但指向您网站的jQuery.com链接会返回404
大卫说恢复莫妮卡(Monica)2010年

注意:我发现由于某种原因,该插件仅在div(上例中的$('。jtextfill'))是根文档的一部分时才起作用。当div嵌入其他div时,.width()看起来返回零。
Jayesh

1
在我看来,该循环上的“ while”行对我来说是错误的–在“ ||”周围应加上括号 子表达式。现在的写法是,仅当宽度太大而不是高度时才检查最小字体大小。
Pointy

4
这种方法非常慢,每次字体更改大小时,都需要重新渲染元素。检查我的答案以获得更好的方法。
霍夫曼

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中


1
@乔恩,谢谢!没错,我的脚本不会执行多行操作,但是OP并没有特别要求这样做,因此您的假设可能是错误的。同样,这种行为在imo中也没有多大意义。我猜想添加多行支持的最好方法是根据单词的数量分割字符串,然后使用上述脚本计算每个部分,无论如何它都可能会更快。
mekwall

4
@Jon,我使用多行textfill玩了一点,最后得到了这个解决方案。沙尘暴的方法最有可能更准确,但是这种方法更快;)
mekwall

2
这是一个最小字体大小也最大字体的版本:gist.github.com/1714284
Jess

1
@霍夫曼 我的解决方案没有.css("font-size")循环调用。你从哪里得到那个的?我的解决方案可能更快,因为它没有您添加到插件中的任何奇特的东西。欢迎您将您的插件添加到jsperf中,我们将看看哪一个是最快的;)
mekwall

1
@MarcusEkwall噢,抱歉,由于某种原因,我虽然在那里看到了一段时间的循环。您的方法与我的方法相似,但实际上我会慢一些,因为我的插件还做了其他一些事情(例如调整高度和宽度,使文本居中集中和其他一些选项),没关系,真正缓慢的部分正在循环内调用.css函数。
霍夫曼

35

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


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

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

3
我发现此方法效果更好offsetWidth,我还必须创建一个size变量,然后附加pxtextSpan.style.fontSize = size+"px";
Wez 2012年

2
确保“ +” px”是必需的。
2014年

@IdanShechter很抱歉,漫长的等待!添加了一个例子!
攻击

谢谢救命!我不了解jQuery,所以我坚持使用您的解决方案:)
vintproykt

32

其他大多数答案都使用循环来减小字体大小,直到适合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标记内的内部元素(如换行符或超棒的字体图标)。


1
我想知道为什么不支持将文本包装成多行?
Manish Sapariya

1
@ManishSapariya支持,但是您需要手动添加换行符(br标签)。我不支持自动换行的原因是为了使其快速(仅将字体大小更改两次,而不是多次更改),我需要假设文本不会在单词之间换行。我的插件的工作方式是将font-size设置为1000px,然后查看将文本大小与容器进行比较的因素,然后将字体大小减小相同的因素。为了支持普通的文本换行,我将需要使用非常慢的慢速方法(多次减小字体大小)。
霍夫曼2014年

嘿! 由于这里没有私人消息传递,因此在StackOverflow上,我将不得不通过评论您的答案来问您。我喜欢您的jQuery插件,但无法为我工作。我已经包含了正确的jQuery库,下载了插件并包含了它。现在,当我尝试使用它时,控制台会显示“ Uncaught TypeError:undefined不是函数”。这是您熟悉的东西吗?你知道如何解决这个问题吗?感谢
Gust van de Wal14年

@GustvandeWal您需要在包含jquery库之后包含该插件
Hoffmann

是的 我有<脚本类型= “文/ JavaScript的” SRC =” code.jquery.com/jquery-2.1.1.min.js"></... SRC “JS / jQuery的bigtext.js”> </ SCRIPT >浏览器没有通知我它无法加载jQuery库或插件。
古斯塔·范·德·沃尔2014年

9

这基于上面发布的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);

区别在于它可以包含多个子元素,并且要考虑填充。使用font-size作为默认的最大大小,以避免混合javascript和css。
sandstrom

5
很好,但是我该如何使用呢?我做$('。outer')。textfill(); 我没有任何改变。
德鲁·贝克

3
谢谢,这是一个非常好的实现。我遇到的一件事:如果您要处理非常长的文本字符串和非常狭窄的容器,则文本字符串将伸出容器,但是outerWidth仍将被计算出来,好像不是这样。折腾“换行:断字;” 放入该容器的CSS中,它将解决此问题。
乔恩

8

这是一种经过改进的循环方法,该方法使用二进制搜索来以尽可能少的步骤找到适合父级的最大尺寸(这比单步固定字体大小更快,更准确)。该代码还以多种方式进行了性能优化。

默认情况下,将执行10个二进制搜索步骤,这将在最佳大小的0.1%之内。您可以将numIter设置为某个值N,以使其位于最佳大小的1/2 ^ N之内。

用CSS选择器调用它,例如: fitToParent('.title-span');

/**
 * Fit all elements matching a given CSS selector to their parent elements'
 * width and height, by adjusting the font-size attribute to be as large as
 * possible. Uses binary search.
 */
var fitToParent = function(selector) {
    var numIter = 10;  // Number of binary search iterations
    var regexp = /\d+(\.\d+)?/;
    var fontSize = function(elem) {
        var match = elem.css('font-size').match(regexp);
        var size = match == null ? 16 : parseFloat(match[0]);
        return isNaN(size) ? 16 : size;
    }
    $(selector).each(function() {
        var elem = $(this);
        var parentWidth = elem.parent().width();
        var parentHeight = elem.parent().height();
        if (elem.width() > parentWidth || elem.height() > parentHeight) {
            var maxSize = fontSize(elem), minSize = 0.1;
            for (var i = 0; i < numIter; i++) {
                var currSize = (minSize + maxSize) / 2;
                elem.css('font-size', currSize);
                if (elem.width() > parentWidth || elem.height() > parentHeight) {
                    maxSize = currSize;
                } else {
                    minSize = currSize;
                }
            }
            elem.css('font-size', minSize);
        }
    });
};

喜欢这个选项。我对其进行了修改,以添加vAlign和的参数paddingvAlign == true将所选元素的line-height设置为父母的高度。填充通过传递的值减小最终大小。它默认为5。我认为它看起来非常不错。
魔鬼的拥护者

6

我为AngularJS创建了一个指令-受到GeekyMonkey的回答的启发,但没有jQuery依赖关系。

演示: http //plnkr.co/edit/8tPCZIjvO3VSApSeTtYr?p = preview

标记

<div class="fittext" max-font-size="50" text="Your text goes here..."></div>

指示

app.directive('fittext', function() {

  return {
    scope: {
      minFontSize: '@',
      maxFontSize: '@',
      text: '='
    },
    restrict: 'C',
    transclude: true,
    template: '<div ng-transclude class="textContainer" ng-bind="text"></div>',
    controller: function($scope, $element, $attrs) {
      var fontSize = $scope.maxFontSize || 50;
      var minFontSize = $scope.minFontSize || 8;

      // text container
      var textContainer = $element[0].querySelector('.textContainer');

      angular.element(textContainer).css('word-wrap', 'break-word');

      // max dimensions for text container
      var maxHeight = $element[0].offsetHeight;
      var maxWidth = $element[0].offsetWidth;

      var textContainerHeight;
      var textContainerWidth;      

      var resizeText = function(){
        do {
          // set new font size and determine resulting dimensions
          textContainer.style.fontSize = fontSize + 'px';
          textContainerHeight = textContainer.offsetHeight;
          textContainerWidth = textContainer.offsetWidth;

          // shrink font size
          var ratioHeight = Math.floor(textContainerHeight / maxHeight);
          var ratioWidth = Math.floor(textContainerWidth / maxWidth);
          var shrinkFactor = ratioHeight > ratioWidth ? ratioHeight : ratioWidth;
          fontSize -= shrinkFactor;

        } while ((textContainerHeight > maxHeight || textContainerWidth > maxWidth) && fontSize > minFontSize);        
      };

      // watch for changes to text
      $scope.$watch('text', function(newText, oldText){
        if(newText === undefined) return;

        // text was deleted
        if(oldText !== undefined && newText.length < oldText.length){
          fontSize = $scope.maxFontSize;
        }
        resizeText();
      });
    }
  };
});

我一直遇到的一个问题是,resizeTextng-bind实际将文本分配给元素之前,似乎要调用它,导致它根据先前的文本而不是当前的文本进行大小调整。在上面的演示中,这并不是很糟糕,在该演示中,随着用户的键入它被反复调用,但是如果一次调用从空值到实数值(如单向绑定)被调用,它将保持最大大小。
Miral 2014年

5

我从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);

2
您正努力帮助申请者,这很棒。但是,仅留下链接的答案在某些情况下可能是有害的。虽然您的答案现在不错,但是如果链接消失了,您的答案将失去它的价值。因此,如果您在答案中总结文章中的内容,将很有帮助。请参阅问题以进行澄清。
Cody Guldner

5

这是我对OP答案的修改。

简而言之,许多尝试优化这一点的人抱怨说正在使用循环。是的,尽管循环可能很慢,但其他方法可能不准确。

因此,我的方法使用二进制搜索来找到最佳字体大小:

$.fn.textfill = function()
{
    var self = $(this);
    var parent = self.parent();

    var attr = self.attr('max-font-size');
    var maxFontSize = parseInt(attr, 10);
    var unit = attr.replace(maxFontSize, "");

    var minFontSize = parseInt(self.attr('min-font-size').replace(unit, ""));
    var fontSize = (maxFontSize + minFontSize) / 2;

    var maxHeight = parent.height();
    var maxWidth = parent.width();

    var textHeight;
    var textWidth;

    do
    {
        self.css('font-size', fontSize + unit);

        textHeight = self.height();
        textWidth = self.width();

        if(textHeight > maxHeight || textWidth > maxWidth)
        {
            maxFontSize = fontSize;
            fontSize = Math.floor((fontSize + minFontSize) / 2);
        }
        else if(textHeight < maxHeight || textWidth < maxWidth)
        {
            minFontSize = fontSize;
            fontSize = Math.floor((fontSize + maxFontSize) / 2);
        }
        else
            break;

    }
    while(maxFontSize - minFontSize > 1 && maxFontSize > minFontSize);

    self.css('font-size', fontSize + unit);

    return this;
}

function resizeText()
{
  $(".textfill").textfill();
}

$(document).ready(resizeText);
$(window).resize(resizeText);

这也允许元素指定最小和最大字体:

<div class="container">
    <div class="textfill" min-font-size="10px" max-font-size="72px">
        Text that will fill the container, to the best of its abilities, and it will <i>never</i> have overflow.
    </div>
</div>

此外,该算法是无单位的。您可以指定emrem%等,它将使用它的最终结果。

这是小提琴:https : //jsfiddle.net/fkhqhnqe/1/


2

我的网站存在完全相同的问题。我有一个页面显示在投影机上,墙壁上,大屏幕上。

因为我不知道我的字体的最大大小,所以我重复使用了@GeekMonkey上面的插件,但是增加了fontsize:

$.fn.textfill = function(options) {
        var defaults = { innerTag: 'span', padding: '10' };
        var Opts = jQuery.extend(defaults, options);

        return this.each(function() {
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var fontSize = parseFloat(ourText.css('font-size'),10);
            var doNotTrepass = $(this).height()-2*Opts.padding ;
            var textHeight;

            do {
                ourText.css('font-size', fontSize);
                textHeight = ourText.height();
                fontSize = fontSize + 2;
            } while (textHeight < doNotTrepass );
        });
    };

+1是该页面上唯一对我有效的插件!
skybondsor 2011年

2
这个外挂程式会让我的页面崩溃。
Jezen Thomas

1

这是已接受答案的版本,也可以采用minFontSize参数。

(function($) {
    /**
    * Resizes an inner element's font so that the inner element completely fills the outer element.
    * @author Russ Painter WebDesign@GeekyMonkey.com
    * @author Blake Robertson 
    * @version 0.2 -- Modified it so a min font parameter can be specified.
    *    
    * @param {Object} Options which are maxFontPixels (default=40), innerTag (default='span')
    * @return All outer elements processed
    * @example <div class='mybigdiv filltext'><span>My Text To Resize</span></div>
    */
    $.fn.textfill = function(options) {
        var defaults = {
            maxFontPixels: 40,
            minFontPixels: 10,
            innerTag: 'span'
        };
        var Opts = jQuery.extend(defaults, options);
        return this.each(function() {
            var fontSize = Opts.maxFontPixels;
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var maxHeight = $(this).height();
            var maxWidth = $(this).width();
            var textHeight;
            var textWidth;
            do {
                ourText.css('font-size', fontSize);
                textHeight = ourText.height();
                textWidth = ourText.width();
                fontSize = fontSize - 1;
            } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > Opts.minFontPixels);
        });
    };
})(jQuery);

谢谢,尽管我认为您在代码的顶部应该放了一个分号
Patrick Moore

1

您可以使用FitText.jsgithub页面)解决此问题。与TextFill相比,它确实很小而且效率很高。TextFill使用昂贵的while循环,而FitText不使用。

FitText也更灵活(我在有非常特殊要求的proyect中使用它,就像冠军!)。

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版本


fittext是否考虑高度?
Manish Sapariya 2014年

1
@ManishSapariya不,不是。它只是将容器宽度除以10,然后将其用作字体大小。
丹·H

1

编辑:此代码用于在HTML5视频顶部显示注释。调整视频大小(调整浏览器窗口大小)时,它会即时更改字体大小。注释已连接到视频(就像YouTube上的注释一样),这就是为什么代码使用实例而不是DOM句柄的原因直。

根据请求,我将添加一些我用来实现此目的的代码。(HTML5视频上的文本框。)代码是很久以前编写的,我很坦率地说,它很乱。由于问题已经得到回答,很久以前就已经接受了答案,因此我不必费心重写。但是,如果有人想简化一下,那就非常欢迎您!

// Figure out the text size:
var text = val['text'];
var letters = text.length;
var findMultiplier = function(x) { // g(x)
    /* By analysing some functions with regression, the resulting function that
     gives the best font size with respect to the number of letters and the size
     of the note is:
     g(x) = 8.3 - 2.75x^0.15 [1 < x < 255]
     f(x) = g(letters) * (x / 1000)^0.5
     Font size = f(size)
     */
    return 8.3 - 2.75 * Math.pow(x, 0.15);
};

var findFontSize = function(x) { // f(x)
    return findMultiplier(letters) * Math.pow(x / 1000, 0.5);
};

val.setFontSizeListener = function() {
    p.style.fontSize = '1px'; // So the text should not overflow the box when measuring.
    var noteStyle = window.getComputedStyle(table);
    var width = noteStyle.getPropertyValue('width');
    var height = noteStyle.getPropertyValue('height');
    var size = width.substring(0, width.length - 2) * height.substring(0, height.length - 2);
    p.style.fontSize = findFontSize(size) + 'px';
};
window.addEventListener('resize', val.setFontSizeListener);

您可能需要将这些数字从font-family调整为font-family。一个很好的方法是下载一个免费的图形可视化工具GeoGebra。更改文本的长度和框的大小。然后,您手动设置尺寸。将手动结果绘制到坐标系中。然后输入我在此处发布的两个方程式,并对数字进行调整,直到“我的”图形适合您自己的手动绘制点。


1

提议的迭代解决方案可以在两个方面大大加快:

1)将字号乘以某个常数,而不是加或减1。

2)首先,使用过程常数为零,例如,使每个循环的大小增加一倍。然后,大致了解从何处开始,再做一次更精细的调整,例如乘以1.1。尽管完美主义者可能想要理想字体的精确整数像素大小,但大多数观察者并不注意到100和110像素之间的差异。如果您是完美主义者,那么请进行第三次重复以进行更精细的调整。

我没有写一个特定的例程或插件来回答确切的问题,我只是依靠基本思想并编写代码的变体来处理各种布局问题,而不仅仅是文本,包括适合的div,span,images。 ..按宽度,高度,面积...在一个容器内,与另一个元素匹配...。

这是一个例子:

  var                           nWindowH_px             = jQuery(window).height();
  var                           nWas                    = 0;
  var                           nTry                    = 5;

  do{
   nWas = nTry;
   nTry *= 2;
   jQuery('#divTitle').css('font-size' ,nTry +'px');
  }while( jQuery('#divTitle').height() < nWindowH_px );

  nTry = nWas;

  do{
   nWas = nTry;
   nTry = Math.floor( nTry * 1.1 );
   jQuery('#divTitle').css('font-size' ,nTry +'px');
  }while( nWas != nTry   &&   jQuery('#divTitle').height() < nWindowH_px );

  jQuery('#divTitle').css('font-size' ,nWas +'px');

1

这是我创建的最优雅的解决方案。它使用二进制搜索,进行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
    };
}

谢谢,这看起来很棒!我正在得到ReferenceError: lastSizeTooSmall is not defined。也许需要在某个地方定义?
ndbroadbent

0

我遇到了同样的问题,解决方案基本上是使用javascript来控制字体大小。在codepen上检查以下示例:

https://codepen.io/ThePostModernPlatonic/pen/BZKzVR

这是仅用于高度的示例,也许您需要在宽度上加上一些。

尝试调整大小

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Documento sem título</title>
<style>
</style>
</head>
<body>
<div style="height:100vh;background-color: tomato;" id="wrap">        
  <h1 class="quote" id="quotee" style="padding-top: 56px">Because too much "light" doesn't <em>illuminate</em> our paths and warm us, it only blinds and burns us.</h1>
</div>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
  var multiplexador = 3;
  initial_div_height = document.getElementById ("wrap").scrollHeight;
  setInterval(function(){ 
    var div = document.getElementById ("wrap");
    var frase = document.getElementById ("quotee");
    var message = "WIDTH div " + div.scrollWidth + "px. "+ frase.scrollWidth+"px. frase \n";
    message += "HEIGHT div " + initial_div_height + "px. "+ frase.scrollHeight+"px. frase \n";           
    if (frase.scrollHeight < initial_div_height - 30){
      multiplexador += 1;
      $("#quotee").css("font-size", multiplexador); 
    }
    console.log(message);          
  }, 10);
</script>
</html>

0

我喜欢

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

0

只是想为contenteditables添加我的版本。

$.fn.fitInText = function() {
  this.each(function() {

    let textbox = $(this);
    let textboxNode = this;

    let mutationCallback = function(mutationsList, observer) {
      if (observer) {
        observer.disconnect();
      }
      textbox.css('font-size', 0);
      let desiredHeight = textbox.css('height');
      for (i = 12; i < 50; i++) {
        textbox.css('font-size', i);
        if (textbox.css('height') > desiredHeight) {
          textbox.css('font-size', i - 1);
          break;
        }
      }

      var config = {
        attributes: true,
        childList: true,
        subtree: true,
        characterData: true
      };
      let newobserver = new MutationObserver(mutationCallback);
      newobserver.observe(textboxNode, config);

    };

    mutationCallback();

  });
}

$('#inner').fitInText();
#outer {
  display: table;
  width: 100%;
}

#inner {
  border: 1px solid black;
  height: 170px;
  text-align: center;
  display: table-cell;
  vertical-align: middle;
  word-break: break-all;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="outer">
  <div id="inner" contenteditable=true>
    TEST
  </div>
</div>


0

我找到了一种防止使用循环缩小文本的方法。它通过将字体大小乘以容器宽度和内容宽度之间的比率来调整字体大小。因此,如果容器的宽度是内容的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/的测试的一部分


0

我使用了geekMonkey解决方案,但是它太慢了。他所做的是将字体大小调整为最大(maxFontPixels),然后检查字体大小是否适合容器。否则它将字体大小减小1px,然后再次检查。为什么不简单地检查以前的容器的高度并提交该值呢?(是的,我知道为什么,但是我现在提出了一个解决方案,该解决方案仅适用于高度,并且具有最小/最大选项)

这是一个更快的解决方案:

var index_letters_resize;
(index_letters_resize = function() {
  $(".textfill").each(function() {
    var
      $this = $(this),
      height = Math.min( Math.max( parseInt( $this.height() ), 40 ), 150 );
    $this.find(".size-adjust").css({
      fontSize: height
    });
  });
}).call();

$(window).on('resize', function() {
  index_letters_resize();
);

这将是HTML:

<div class="textfill">
  <span class="size-adjust">adjusted element</span>
  other variable stuff that defines the container size
</div>

同样:此解决方案仅检查容器的高度。这就是为什么该函数不必检查(如果元素适合内部)的原因。但是我还实现了一个最小值/最大值(40min,150max),因此对我来说,它可以很好地工作(并且还可以调整窗口大小)。


-1

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

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";
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.