简体   繁体   English

JavaScript 缩放文本以适应固定的 Div

[英]JavaScript Scale Text to Fit in Fixed Div

In JavaScript/jQuery, how can I scale a varying-length line of text inside a fixed-width Div so that the one line always fits inside the Div (as one line)?在 JavaScript/jQuery 中,如何在固定宽度的 Div 中缩放可变长度的文本行,以便一行始终适合 Div(作为一行)?

This is somewhat of a hack, but will do what you want.这有点像黑客,但会做你想做的。

<div id="hidden-resizer" style="visibility: hidden"></div>

Place this at the bottom of your page, where it will not be moving other elements on the page.将它放在页面底部,它不会移动页面上的其他元素。

Then do this:然后这样做:

var size;
var desired_width = 50;
var resizer = $("#hidden-resizer");

resizer.html("This is the text I want to resize.");

while(resizer.width() > desired_width) {
  size = parseInt(resizer.css("font-size"), 10);
  resizer.css("font-size", size - 1);
}

$("#target-location").css("font-size", size).html(resizer.html());

HTML: HTML:

<div class="box" style="width:700px">This is a sentence</div>
<div class="box" style="width:600px">This is a sentence</div>
<div class="box" style="width:500px">This is a sentence</div>
<div class="box" style="width:400px">This is a sentence</div>

JavaScript: JavaScript:

$( '.box' ).each(function ( i, box ) {

    var width = $( box ).width(),
        html = '<span style="white-space:nowrap"></span>',
        line = $( box ).wrapInner( html ).children()[ 0 ],
        n = 100;

    $( box ).css( 'font-size', n );

    while ( $( line ).width() > width ) {
        $( box ).css( 'font-size', --n );
    }

    $( box ).text( $( line ).text() );

});

Live demo: http://jsfiddle.net/e8B9j/2/show/现场演示: http : //jsfiddle.net/e8B9j/2/show/

Remove "/show/" from the URL to view the code.从 URL 中删除“/show/”以查看代码。

I have written a jQuery plugin to do this:我写了一个 jQuery 插件来做到这一点:

http://michikono.github.com/boxfit http://michikono.github.com/boxfit

The plugin will scale the text both horizontally and vertically to the maximum available size inside the box and then center it.该插件会将文本水平和垂直缩放到框内的最大可用大小,然后将其居中。

The only thing you need to do is define a div with text inside it:您唯一需要做的就是定义一个包含文本的 div:

<div id="scale">some text</div>

And then call:然后调用:

$('#scale').boxfit()

The method will accept some arguments to disable/enable text wrapping and centered alignment.该方法将接受一些参数来禁用/启用文本换行和居中对齐。

For new Browsers you can use Inline-SVG.对于新的浏览器,您可以使用 Inline-SVG。 This can be scaled like an image via CSS .. !这可以通过 CSS 像图像一样缩放 ..!

 .smallerVersion{ max-width: 50% }
 <!DOCTYPE html> <html> <head> <title>Scale SVG example</title> </head> <body> <h2>Default version:</h2> <svg viewBox="0 0 240 80" xmlns="http://www.w3.org/2000/svg"> <style> .small { font: italic 13px sans-serif; } .heavy { font: bold 30px sans-serif; } /* Note that the color of the text is set with the * * fill property, the color property is for HTML only */ .Rrrrr { font: italic 40px serif; fill: red; } </style> <text x="20" y="35" class="small">My</text> <text x="40" y="35" class="heavy">cat</text> <text x="55" y="55" class="small">is</text> <text x="65" y="55" class="Rrrrr">Grumpy!</text> </svg> <h2>Scaled version:</h2> <svg class="smallerVersion" viewBox="0 0 240 80" xmlns="http://www.w3.org/2000/svg"> <style> .small { font: italic 13px sans-serif; } .heavy { font: bold 30px sans-serif; } /* Note that the color of the text is set with the * * fill property, the color property is for HTML only */ .Rrrrr { font: italic 40px serif; fill: red; } </style> <text x="20" y="35" class="small">My</text> <text x="40" y="35" class="heavy">cat</text> <text x="55" y="55" class="small">is</text> <text x="65" y="55" class="Rrrrr">Grumpy!</text> </svg> </body> </html>

( width: 100%; ) width: 100%;

Most of the other answers use a loop to reduce the font-size until it fits on the div, this is VERY slow since the page needs to re-render the element each time the font changes size.大多数其他答案使用循环来减小字体大小,直到它适合 div,这非常慢,因为每次字体更改大小时页面都需要重新渲染元素。 I eventually had to write my own algorithm to make it perform in a way that allowed me to update its contents periodically without freezing the user browser.我最终不得不编写自己的算法,使其以一种允许我定期更新其内容的方式执行,而不会冻结用户浏览器。 I added some other functionality (rotating text, adding padding) and packaged it as a jQuery plugin, you can get it at:我添加了一些其他功能(旋转文本、添加填充)并将其打包为 jQuery 插件,您可以在以下位置获取它:

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

simply call简单地打电话

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

and it will fit nicely on your container.它将非常适合您的容器。

See it in action here:在这里查看它的实际效果:

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

For now it has some limitations, the div must have a fixed height and width and it does not support wrapping text into multiple lines.现在它有一些限制,div 必须有固定的高度和宽度,它不支持将文本换行成多行。

Edit2: I have now fixed those problems and limitations and added more options. Edit2:我现在已经解决了这些问题和限制,并添加了更多选项。 You can set maximum font-size and you can also choose to limit the font-size using either width, height or both (default is both).您可以设置最大字体大小,也可以选择使用宽度、高度或两者(默认为两者)来限制字体大小。 I will work into accepting a max-width and max-height values in the wrapper element.我将努力接受包装元素中的 max-width 和 max-height 值。

I don't know of an exact way, but here's an approximation:我不知道确切的方法,但这是一个近似值:

var factor = 1/3;  // approximate width-to-height ratio
var div = $('#mydiv');
div.css('font-size', div.width() / (div.text().length * factor) + 'px');

You will need to adjust factor based on the font you are using.您需要根据您使用的字体调整factor 1/3 seems to work okay for Times New Roman. 1/3 似乎适用于 Times New Roman。

Modified version of @sworoc with the support of the target class在目标类的支持下修改了@sworoc 的版本

function resizeText(text, size, target) {

    var fontSize = 0;
    var resizer = $('<span>');

    resizer.html(text).hide();
    resizer.attr('class', target.attr('class'));
    $('body').append(resizer);

    while(resizer.width() < size) {
        fontSize++
        resizer.css("font-size", fontSize);
    }

    target.css('font-size', fontSize).html(text);
    resizer.remove();
}

Usage用法

resizeText("@arunoda", 350, $('#username'));

Inside your div, have the text in a span that has no padding.在您的 div 中,将文本放在没有填充的跨度中。 Then the span's width will be the length of the text.那么跨度的宽度将是文本的长度。
Untested code for finding the correct font-size to use:用于查找要使用的正确字体大小的未经测试的代码:

var objSpan = $('.spanThatHoldsText');  
var intDivWidth = $('.divThatHasAFixedWidth').width();  
var intResultSize;  

for (var intFontSize = 1; intFontSize < 100; intFontSize++)  

  objSpan.css('font-size', intFontSize);  

  if (objSpan.width() > intDivWidth) {  
    intResultSize = intFontSize - 1;  
    break;  
  }  

}

objSpan.css('font-size', intResultSize);

Here is a coffeescript solution I came up with.这是我想出的一个咖啡脚本解决方案。 I clone the element that is needing to have it's font resized then remove that at the end of the calculation.我克隆需要调整其字体大小的元素,然后在计算结束时将其删除。 To increase performance I have some code that only executes the calculation after resizing has stopped for 200ms.为了提高性能,我有一些代码仅在调整大小停止 200 毫秒后才执行计算。

Tag elements with class autofont for this to be done unobtrusively.使用类autofont标记元素,以便不显眼地完成。

# 
# Automagically resize fonts to fit the width of the 
# container they are in as much as possible. 
#
fixfonts = ->

  scaler = 1.2

  for element in $('.autofont')

    size =  1
    element = $(element)
    desired_width = $(element).width()

    resizer = $(element.clone())
    resizer.css
      'font-size': "#{size}em"
      'max-width': desired_width
      'display': 'inline'
      'width': 'auto'
    resizer.insertAfter(element)

    while resizer.width() < desired_width
      size = size * scaler
      resizer.css
        'font-size':  "#{size}em"

    $(element).css
        'font-size': "#{size / scaler }em"

    resizer.remove()

$(document).ready =>
  fixfonts()

  timeout = 0
  doresize = ->
    timeout--
    if timeout == 0
      fixfonts()

  $(window).resize ->
    timeout++
    window.setTimeout doresize, 200

I had a similar issue, which made me write my own plugin for this.我有一个类似的问题,这让我为此编写了自己的插件。 One solution is to use the shrink-to-fit-approach, as described above.一种解决方案是使用收缩贴合方法,如上所述。 However if you have to fit multiple items or are concerned with performance, eg, on window resize, have a look at jquery-quickfit .但是,如果您必须适应多个项目或关心性能,例如调整窗口大小,请查看jquery-quickfit

It meassures and calculates a size invariant meassure for each letter of the text to fit and uses this to calculate the next best font-size which fits the text into the container.它测量并计算适合文本的每个字母的大小不变度量,并使用它来计算适合文本到容器中的下一个最佳字体大小。

The calculations are cached, which makes it very fast (there is virtually no performance hit from the 2nd resize on forward) when dealing with multiple texts or having to fit a text multiple times, like eg, on window resize.计算被缓存,这使得它在处理多个文本或必须多次适应文本时非常快(从第二次调整大小开始实际上没有性能影响),例如在窗口调整大小时。

Production example, fitting 14x16x2 texts生产示例,拟合 14x16x2 文本

Here's my modification to @teambob's suggestion (in above comments ) that takes also the height of the container into account:这是我对@teambob 的建议(在上面的评论中)的修改,它也考虑了容器的高度:

<div class="box" style="width:700px; height:200px">This is a sentence</div>
<div class="box" style="width:600px; height:100px">This is a sentence</div>
<div class="box" style="width:500px; height:50px">This is a sentence</div>
<div class="box" style="width:400px; height:20px">This is a sentence</div>

And then..进而..

$('.box').each(function(i, box) {

    var width = $(box).width(),
        height = $(box).height(),
        html = '<span style="white-space:nowrap">',
        line = $(box).wrapInner(html).children()[0],
        maxSizePX = 2000;

    $(box).css('font-size', maxSizePX);
    var widthFontSize = Math.floor(width/$(line).width()*maxSizePX),
        heightFontSize = Math.floor(height/$(line).height()*maxSizePX),
        maximalFontSize = Math.min(widthFontSize, heightFontSize, maxSizePX);

    $(box).css('font-size', maximalFontSize);
    $(box).text($(line).text());

});

See Fiddle小提琴

I made (yet) another plugin to address this issue:我制作了(还)另一个插件来解决这个问题:

https://github.com/jeremiahrose/perfectFit.js https://github.com/jeremiahrose/perfectFit.js

It generates SVG's so it's very fast - just runs once on page load.它生成 SVG,因此速度非常快 - 只需在页面加载时运行一次。 Capable of automatically wrapping and scaling individual words to fit a div exactly.能够自动包装和缩放单个单词以完全适合 div。

I couldn't figure out how to add this to sworoc's post but i thought i would share anyway: Lonesomeday's solution gets messed up if you are using any sort of AJAX navigation.我不知道如何将其添加到 sworoc 的帖子中,但我想无论如何我都会分享:如果您使用任何类型的 AJAX 导航,Lonesomeday 的解决方案就会变得一团糟。 I modified it slightly to:我稍微修改为:

if ($('#hidden-resizer').length == 0){ 
    $('<div />', {id: 'hidden-resizer'}).hide().appendTo(document.body); 
}

Here is my solution: I measure the text in a new div within the provided div, so that the styling should be inherited.这是我的解决方案:我在提供的 div 中测量新 div 中的文本,以便应该继承样式。 Then I insert the text into the div with a span to set the font-size.然后我将文本插入带有跨度的 div 以设置字体大小。 It will max out to the default font size but will shrink to fit.它将最大化为默认字体大小,但会缩小以适应。

It does not loop: it only draws the text once in a throw-away div before drawing directly to the supplied div.它不会循环:在直接绘制到提供的 div 之前,它只在一次性 div 中绘制一次文本。 See @Hoffmann answer - I just did not like an entire 'plugin' to answer the question.参见@Hoffmann 的回答——我只是不喜欢用一个完整的“插件”来回答这个问题。

requires jquery.需要jquery。

var txt = txt || {}
txt.pad_factor = 1.1;
txt.insertText_shrinkToFit = function(div,text)
{
  var d = txt.cache || $('<div></div>');
  txt.cache = d;

  d.css('white-space','nowrap');
  d.css('position','absolute');
  d.css('top','-10000px');
  d.css('font-size','1000px');

  var p = $(div);
  var max_w = parseInt(p.css('max-width')) || p.width();
  var max_h = parseInt(p.css('font-size'));

  p.append(d);
  d.html(text);
  var w = d.width() * txt.pad_factor; 
  d.remove();

  var h = Math.floor(max_w*1000/w);
  var s = ( max_h < h ? max_h : h ) + "px";

  p.html('<SPAN style="font-size:' + s + '">' + text + '</SPAN>');
}

For example:例如:

<html><head><script src=http://code.jquery.com/jquery-latest.min.js></script>
<script>/*insert code, from above, here.*/</script></head><body>

<div id=mysmalldiv style="max-width:300px;font-size:50px"></div>
<script>
  txt.insertText_shrinkToFit("#mysmalldiv","My super long text for this div.");
</script>

</body></html>

For testing: this is how I found that I needed the 1.1 pad_factor;测试:这就是我发现我需要 1.1 pad_factor 的方式; which you may tune to your needs.您可以根据自己的需要进行调整。

<div id=mytestdiv style="max-width:300px;font-size:50px"></div>
<script>
  var t = "my text ";
  var i = 0;
  var f = function() {
    t += i + " ";
    txt.insertText_shrinkToFit("#mytestdiv",t);
    i++;
    if(i < 100) 
      setTimeout(f,1000);
  }
  f();
</script>

Note: this is assuming px font-size.注意:这是假设 px 字体大小。 I have not tested with em or pt.我还没有用 em 或 pt 测试过。

There is a great way to do this for single line texts, like headers and such, in pure CSS:对于纯 CSS 中的单行文本,例如标题等,有一种很好的方法可以做到这一点:

h1{
    font-size: 4.5vw;
    margin: 0 0 0 0;
    line-height: 1em;
    height: 1em;
}

h1:after{
    content:"";
    display: inline-block;
    width: 100%;
}

Make sure your font-size stays small enough to keep the header 1 line.确保您的字体大小保持足够小以保持标题 1 行。 Using 'vw' (viewport width) instead of 'px' makes it very easy to do this and scale at the same time.使用“vw”(视口宽度)而不是“px”可以很容易地做到这一点并同时进行缩放。 viewport width has the tendency to get nasty when you make your browser window very big, many sites use this to keep the site under a certain width on really wide screens:当您将浏览器窗口设置得很大时,视口宽度往往会变得令人讨厌,许多站点使用它来将站点在真正宽的屏幕上保持在一定的宽度以下:

body{
   max-width: 820px;
   margin: 0 auto;
}

To make sure your font is not based on how big the viewport window is once the rest of your site stops scaling use this:要确保您的字体不基于站点其余部分停止缩放后视口窗口的大小,请使用以下命令:

@media(min-width:820px){
   h1{
      font-size: 30px; 
   }
}

you can do multiple things like你可以做很多事情,比如

overflow:hidden

this cuts the extra line这减少了额外的线

overflow:auto // this shows the scroll bar overflow:auto // 显示滚动条

see this看到这个

http://www.w3schools.com/Css/pr_pos_overflow.asp http://www.w3schools.com/Css/pr_pos_overflow.asp

try to do this //check the length of the text尝试这样做//检查文本的长度

if($('#idfortext').length>sometthing)
{
var fontsize=10;
}
$('#yourid').css('font-size',fontsize)

Im not sure there is any accurate way to measure text's width in pixels (which is what you're really looking for at the root of your problem), as each browser may display the fonts differently.我不确定是否有任何准确的方法来测量以像素为单位的文本宽度(这是您真正要寻找的问题根源),因为每个浏览器可能会以不同的方式显示字体。 You might want to try using this CSS code, in addition to doing some "Fuzzy" resizing based on the number of letters in the sentence.除了根据句子中的字母数进行一些“模糊”调整外,您可能还想尝试使用此 CSS 代码。 You can try using a fixed-width font (or style) to display the text so that each character takes up the same amount of space.您可以尝试使用固定宽度的字体(或样式)来显示文本,以便每个字符占用相同的空间。 This way, you can make a best guess, and the CSS will at least give you a nice "..." before cropping the text, if needed.这样,您可以做出最好的猜测,如果需要,CSS 至少会在裁剪文本之前给您一个漂亮的“...”。

.truncate 
{ 
    overflow: hidden; 
    white-space: nowrap; 
    text-overflow: ellipsis; 
} 

This is what I found today:这是我今天发现的:

  1. Set a really big fake font-size (f) to the target text为目标文本设置一个非常大的假字体大小(f)
  2. measure width (w) height (h) of the text container and divide by font-size (f):测量文本容器的宽度 (w) 高度 (h) 并除以字体大小 (f):

    • iw = w/f
    • ih = h/f
  3. Divide main container width (W) by iw and main container height (H) by ih:将主容器宽度 (W) 除以 iw,将主容器高度 (H) 除以 ih:

    • kw = W/iw
    • kh = H/ih
  4. Pick lowest between kw and kh: that is the wanted FontSize.在 kw 和 kh 之间选择最低的:这是想要的 FontSize。

https://jsfiddle.net/pinkynrg/44ua56dv/ https://jsfiddle.net/pinkynrg/44ua56dv/

function maximizeFontSize($target) {

  var testingFont = 1000;
    $target.find(".text-wrapper").css("font-size", testingFont+"px");

  var textWidth = $(".text-wrapper").width()/1000;
  var textHeight = $(".text-wrapper").height()/1000;
  var width = $(".container").width();
  var height = $(".container").height();

  var kWidth = width/textWidth;
  var kHeight = height/textHeight;
  var fontSize = kWidth < kHeight ? kWidth : kHeight;

  // finally
  $(".text-wrapper")
    .css("font-size", fontSize+"px")
    .css("line-height", height+"px");
}

I'm using vanilla js.我正在使用香草 js。 A solution that worked for me for changes in horizontal sizing is when I create the div, I set a default font size % for a given width.一个对我改变水平尺寸有用的解决方案是,当我创建 div 时,我为给定的宽度设置了默认字体大小 %。 In my case, I'm wrapping the div in a bigger class, but for these purposes, you could use:就我而言,我将 div 包装在一个更大的类中,但出于这些目的,您可以使用:

document.getElementById("mydiv").fontScale = {scaleVal: scaleFactor, defaultWidth: defaultWidth}

the scaleFactor is the size of the font (in percentage) that you want for a given width (the default width). scaleFactor 是给定宽度(默认宽度)所需的字体大小(百分比)。 Then when I get a resize event:然后当我收到调整大小事件时:

let myDiv = document.getElementById("mydiv");
let width = myDiv.offsetWidth;
myDiv.style[fontSize] = String(width/myDiv.fontScale.defaultWidth * myDiv.fontScale.scaleFactor * 100) + "%";

I worked off a few posts here and made a jQuery plugin out of it.我在这里写了几篇文章,并用它制作了一个 jQuery 插件。 I found that starting from the bottom and going up wasn't very performant, so I make the assumption that the current font-size is close, and worked from there.我发现从底部开始向上的性能不是很好,所以我假设当前的字体大小很接近,并从那里开始工作。

  $.fn.fitTextToWidth = function(desiredWidth) {
    // In this method, we want to start at the current width and grow from there, assuming that we are close to the desired size already.
    var $el = $(this);
    var resizer = $('<'+$el.get(0).tagName+' />').css({'vsibility':'hidden','position':'absolute','left':'-9999px','display':'inline'}).html($el.html());
    resizer.appendTo(document.body);

    var size = parseInt($el.css('font-size'));
    resizer.css('font-size',size+'px');

    var growing = desiredWidth > resizer.width() ? true : false;
    var adder = growing ? 1 : -1;
    do {
        size += adder;
        resizer.css('font-size',size+'px');
    } while(((growing && resizer.width()<desiredWidth) || (!growing && resizer.width()>desiredWidth)) && size>10 && size<100);
    if (growing)
        size -= 2; //we never want to go over
    resizer.remove();

    $el.css('font-size',size+'px'); 
  }

  // Example use:
  $('#main h1').fitTextToWidth(350);

The only gotcha with this is that it assumes the CSS for the element is global and only applied to the element type.唯一的问题是它假定元素的 CSS 是全局的,并且只应用于元素类型。 In other words, it creates a tag of the same name in and assumes it will have the same CSS attributes as the element we want to change.换句话说,它创建一个同名的标签 in 并假设它与我们要更改的元素具有相同的 CSS 属性。 If this isn't true for you, just modify the line where resizer gets created.如果这对您来说不正确,只需修改创建resizer的行。

plugin to fit to the width and height of a container适合容器宽度和高度的插件

http://blissitec.github.io/scaletextjs/ http://blissitec.github.io/scaletextjs/

Simple solution简单的解决方案

<div class="fitt-text"><span>text</span></div>

js js

$(".fitt-text").css('font-size', '1vw');
    
var cw = $(".fitt-text").width();
var w = $(".fitt-text span").width();
var f = cw/w;

$(".fitt-text").css('font-size', f + 'vw');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM