自动resize的dynamic文本以填充固定大小的容器

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

所以 – 如果div是400px x 300px。 如果有人进入美国广播公司,那么它真的很大 如果他们input一个段落,那么它将是一个小字体。

我可能想从最大字体大小开始 – 也许是32px,而文本太大而不适合容器,缩小字体大小直到适合。

感谢攻击 。 我想使用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插件,所以它可能不如应有的。 指针当然是受欢迎的。

由于性能不好,我没有发现任何以前的解决scheme是足够的,所以我做了我自己的使用简单的math,而不是循环。 在所有浏览器中也应该正常工作。

根据这个性能testing的情况,它比其他解决scheme在这里find的要快得多。

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

大多数其他的答案使用循环来减小字体大小,直到它适合div,这是非常缓慢的,因为每次字体改变大小页面需要重新呈现元素。 我最终不得不编写自己的algorithm,使其能够在不冻结用户浏览器的情况下定期更新其内容。 我添加了一些其他function(旋转文本,添加填充),并将其打包为一个jQuery插件,你可以在:

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

只需打电话

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

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

在这里看到它的行动:

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

现在它有一些限制,div必须有一个固定的高度和宽度,它不支持包装文本到多行。

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

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

编辑2:我现在已经修复了这些问题和限制,并增加了更多的选项。 您可以设置最大字体大小,也可以select使用宽度,高度或两者都限制字体大小。 我将接受包装器元素中的最大宽度和最大高度值。

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

尽pipe我喜欢偶尔向上提供的答案(谢谢!),但这并不是解决这个问题的最好办法。 请在这里查看一些其他精彩的答案,尤其是那些已经find解决scheme而无需循环的答案。


不过,为了参考,这里是我的原始答案

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

这是基于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); 

我为AngularJS创build了一个指令 – 受到了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(); }); } }; }); 

我从Marcus Ekwall分叉了上面的脚本: https ://gist.github.com/3945316,并调整它到我的喜好,它现在触发窗口resize时,以便孩子总是适合其容器。 我已经粘贴了下面的脚本以供参考。

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

这是我对OP的答案的修改。

总之,许多试图优化这个的人抱怨说,循环被使用了。 是的,虽然循环可能很慢,但其他方法可能不准确。

因此,我的方法使用二进制search来find最好的字体大小:

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

而且,这个algorithm是无法实现的。 您可以指定emrem%等,并将其用于最终结果。

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

这里有一个改进的循环方法,它使用二进制search以尽可能less的步骤find适合父代的最大可能尺寸(这比以固定字体尺寸步进更快,更准确)。 该代码还在几个方面进行了优化性能。

默认情况下,将执行10个二进制search步骤,这将在最佳大小的0.1%以内。 您可以改为将numIter设置为某个值N以获得最佳大小的1/2 ^ N。

用CSSselect器调用它,例如: 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); } }); }; 

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

由于我不知道字体的最大尺寸,我重新使用了@GeekMonkey上面的插件,但增加了字体大小:

 $.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 ); }); }; 

这里是接受的答案,也可以采取一个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); 

你可以使用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的版本 。

编辑:此代码是用来显示在HTML5video顶部的笔记。 当video被resize时(当浏览器窗口被resize时),它会随时更改字体大小。笔记已连接到video(就像YouTube上的注释一样),这就是为什么代码使用实例而不是DOM句柄直。

根据要求,我会抛出一些我用来实现这个目标的代码。 (在HTML5video上的文本框)代码是很久以前写的,我很坦率地认为它很杂乱。 既然这个问题已经回答了,很久以前答案已经被接受了,所以我不打算重写这个。 但如果有人想简化这一点,你是欢迎!

 // 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的免费graphics可视化工具。 更改文本的长度和框的大小。 然后你手动设置大小。 将手动结果绘制到坐标系中。 然后input我在这里发布的两个等式,然后调整数字,直到“我的”graphics符合您自己的手动绘制点。

提出的迭代解决scheme可以在两个方面大幅提高:

1)将字体大小乘以某个常量,而不是加1或减1。

2)首先,使用一个过程常数为零,比方说每个循环的大小加倍。 然后,大概从哪里开始,做一个更好的调整,比如乘以1.1。 尽pipe完美主义者可能需要理想字体的精确整数像素大小,但大多数观察者并没有注意到100和110像素之间的差异。 如果你是一个完美主义者,那么重新进行第三次更好的调整。

而不是写一个具体的例程或插件来回答确切的问题,我只是依靠基本的想法和编写代码的变种来处理各种布局问题,而不仅仅是文本,包括拟合div,跨度,图像。 ..通过宽度,高度,面积,…在一个容器内,与另一个元素相匹配….

这是一个例子:

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

我知道这是一个老人,但仍然有人需要这个function。 我去geekMonkey解决scheme,但它的重击。 只是因为它慢。 他所做的是将字体大小调整到最大(maxFontPixels),然后检查它是否适合容器内部。 否则它将字体大小减less1px并再次检查。 为什么不简单地检查以前的容器的高度,并提交该值? (是的,我知道为什么,但我现在提出了一个解决scheme,只能在高度上工作,也有最小/最大选项)

方式更快的解决scheme:

 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> 

再次:这个解决scheme只检查容器的高度。 这就是为什么这个函数不需要检查,如果元素适合里面。 但我也实施了最小/最大值(40分钟,150max),所以对我来说这工作得很好(也适用于窗口大小调整)。

我得到了同样的问题,解决scheme是基本上使用JavaScript来控制字体大小。 在codepen上检查这个例子:

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

这是例子只是为了身高,也许你需要把一些if的宽度。

尝试调整它的大小

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

这是这个解决scheme的另一个版本:

 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"; } }