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

Gee*_*key 305 html css jquery

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

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

我可能想要从最大字体大小开始 - 可能是32px,虽然文本太大而不适合容器,但缩小字体大小直到它适合.

Gee*_*key 164

谢谢攻击.我想使用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 });
});
Run Code Online (Sandbox Code Playgroud)

我的HTML是这样的

<div class='jtextfill' style='width:100px;height:50px;'>
    <span>My Text Here</span>
</div>
Run Code Online (Sandbox Code Playgroud)

这是我的第一个jquery插件,所以它可能没有它应该的那么好.指针当然是受欢迎的.

  • 我实际上只是清理它并将其打包为jquery.com提供的插件,网址为http://plugins.jquery.com/project/TextFill (8认同)
  • 这种方法非常慢,每次字体更改大小时都需要重新呈现元素.检查我的答案,以获得更好的方法. (4认同)
  • @GeekyMonkey,你拉了插件吗?只是跟着这个页面的欺骗链接,并认为我看看,但jQuery.com链接到您的网站返回'404`. (3认同)

mek*_*all 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);
Run Code Online (Sandbox Code Playgroud)

如果你想贡献我已经把这个添加到Gist.

  • @Jon,我在多行文本填充方面玩了一点,最后得到了[此解决方案](http://jsfiddle.net/mekwall/fNyHs/).沙尘暴的方法很可能更准确,但这个更快;) (4认同)
  • 这是一个具有最小字体大小和最大值的版本:https://gist.github.com/1714284 (2认同)

att*_*ack 33

尽管我喜欢这个答案的偶尔的赞成(谢谢!),但这并不是解决这个问题的最佳方法.请在这里查看一些其他精彩的答案,特别是那些找到没有循环的解决方案的答案.


不过,为了便于参考,这是我原来的答案:

<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>
Run Code Online (Sandbox Code Playgroud)

这是一个有的版本:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 我发现这对`offsetWidth`效果更好,我还必须为size创建一个变量然后追加px`textSpan.style.fontSize = size +"px";` (3认同)
  • 确定'+'px"'是必要的. (2认同)

Hof*_*ann 32

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

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

简单地打电话

$("#text").bigText();
Run Code Online (Sandbox Code Playgroud)

它很适合你的容器.

在这里看到它:

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

目前它有一些限制,div必须具有固定的高度和宽度,并且它不支持将文本包装成多行.

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

编辑:我发现插件有一些问题,它除了标准版之外它不处理其他框模型而且div不能有边距或边框.我会努力的.

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

Edit3:我已将插件更新到1.2.0版.代码和新选项(verticalAlign,horizo​​ntalAlign,textAlign)的主要清理以及对span标记内部元素的支持(如换行符或字体很棒的图标).


san*_*rom 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);
Run Code Online (Sandbox Code Playgroud)

  • 这很棒,但我该如何使用它?我做$('.outer').textfill(); 我没有改变. (5认同)
  • 谢谢,这是一个非常好的实现.有一件事我遇到了:如果你正在处理很长的文本字符串和很窄的容器,文本字符串会伸出容器,但如果它不outerWidth仍将被计算.抛出"自动换行:破词;" 进入你的容器的CSS,它将解决这个问题. (3认同)

Luk*_*son 7

这是一个改进的循环方法,它使用二进制搜索以尽可能少的步骤找到适合父级的最大可能大小(这比步进固定字体大小更快,更准确).代码也以多种方式优化以提高性能.

默认情况下,将执行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);
        }
    });
};
Run Code Online (Sandbox Code Playgroud)


sqr*_*ren 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();
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)


nim*_*rod 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);
Run Code Online (Sandbox Code Playgroud)

  • 你试图帮助提问者真是太好了.但是,在某些情况下,仅使用链接留下答案可能会有害.虽然你的答案现在很好,但如果链接永远消失,你的答案就会失去它的价值.因此,如果您在答案中总结文章中的内容,将会很有帮助.请参阅[this](http://goo.gl/wQTjc)问题以获得澄清. (2认同)

Boo*_*oom 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);
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

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