根据字符串长度调整字体大小

时间:2014-05-26 14:46:04

标签: css font-size

我有一个垂直菜单,我希望它可以进行本地化,但菜单元素中的本地化字符串通常会脱离边缘。
所以问题是如何根据CSS中的字符串长度调整字体大小。如果可能的话,没有JavaScript 谢谢!

UPD:JQuery是不可接受的。在Pure JS中的任何方式?

5 个答案:

答案 0 :(得分:6)

您应该熟悉使用插件,它们可以节省您很多时间,当然它们非常可靠(它们由经验丰富的脚本编写者/程序员编写,并且已经过社区测试)。但是看起来你想要一些纯粹的JS解决方案。我刚刚为你制作了这个代码。它工作得相当好(虽然我不确定它是否和某些插件一样好)。唯一的要求是元素(您希望根据文本长度调整字体大小) 应包含纯文本 ,而不是某些HTML代码。

使用纯JS实现它的想法很简单,你需要使用脚本创建一些虚拟元素,这个虚拟元素用于测量文本的大小。我们需要调整虚拟元素的字体大小,直到文本(以及虚拟元素)的大小应该限制为元素的大小(要调整的字体大小)。我非常清楚地编写了代码,希望您在阅读代码后能够更好地理解代码:

//we just need 1 dummy element for the whole page.
var dummy = document.createElement('div');
dummy.className = 'dummy';
var inSingleLineMode, inMultilineMode;    
//function used to adjust the font-size of the element
//so that the width is fixed (single-line mode) or both the width and height are 
//fixed (multi-line mode), of course the text should be contained within 
//the fixed width and height.
function adjustFontSize(element, singleLine){
  if(!element.innerHTML) return;
  var elementStyle = getComputedStyle(element);        
  dummy.style.font = elementStyle.font;
  initMode(singleLine, function(){ dummy.style.width = elementStyle.width });
  dummy.style.padding = elementStyle.padding;
  dummy.style.boxSizing = elementStyle.boxSizing;
  dummy.innerHTML = element.innerHTML;
  document.body.appendChild(dummy);
  var dummyStyle = getComputedStyle(dummy);          
  while(singleLine ? parseInt(dummyStyle.width) < parseInt(elementStyle.width) :
                     parseInt(dummyStyle.height) < parseInt(elementStyle.height)){
    dummy.style.fontSize = parseFloat(dummyStyle.fontSize) + 1 + 'px';
    dummyStyle = getComputedStyle(dummy);
  }
  while(singleLine ? parseInt(dummyStyle.width) > parseInt(elementStyle.width) :
                     parseInt(dummyStyle.height) > parseInt(elementStyle.height)){
    dummy.style.fontSize = parseFloat(dummyStyle.fontSize) - 1 + 'px';
    dummyStyle = getComputedStyle(dummy);
  }    
  element.style.fontSize = dummyStyle.fontSize;
  document.body.removeChild(dummy);
}
function initMode(singleLine, callback){
  if(!dummy) return;
  if(singleLine&&!inSingleLineMode) {
    dummy.style.whiteSpace = 'nowrap';
    dummy.style.width = 'auto';
    dummy.style.display = "inline-block";
    inSingleLineMode = true;
    inMultiLineMode = false;
  } else if(!singleLine&&!inMultilineMode) {
    if(callback) callback();
    dummy.style.whiteSpace = 'initial';
    dummy.style.display = "block";
    dummy.style.wordWrap = 'break-word';
    inMultilineMode = true;
    inSingleLineMode = false;
  }
}

Demo.

在演示中,您可以看到第一个菜单#menu1是越南语单词,意思是 Chrysanthemum ,而第二个菜单#menu2当然是英语单词菊花。它们的长度差异很大,但两者都应该具有100px的固定宽度,因此第二个菜单#menu2应该具有较小的字体大小以适应空间。

答案 1 :(得分:5)

您可以像这样使用jQuery Text Fill

  1. 加载插件:<script src="jquery.textfill.js" ></script>

  2. 加上身份<input type="text" id="dyntext" value="e=mc²"></input>

  3. 使用代码做魔术。最好将其放在<script>标签中:

  4. 最终结果将如下所示:

     function update() {
      var size = parseInt($('#maxsize').val(), 10);
      if (!isNaN(size)) {
        $('.dyntextval').html($('#dyntext').val());
        $('.jtextfill').textfill({debug: true, maxFontPixels: size});
      }
    }
    
    $(function () {
      $('#maxsize').keyup(update);
      $('#dyntext').keyup(update);
      update()
    });
    

    enter image description here

答案 2 :(得分:2)

如果没有Javascript,这是不可能的。使用Javascript,您可以使用众多库中的一个,例如FitText

所以你可以使用Javascript库,但这也意味着各种标签有不同的字体大小。 我认为最好的方法是以一种优雅地处理多行字幕的方式设置菜单样式。这样,长度并不重要。

因为某些语言的篇幅较长而且#39;与其他人相比(例如法国唱片公司的版本是英文的1.5到2倍,用其中一种语言测试你的界面是一个好主意。

对于字体大小,您可以在服务器端添加修饰符,如果您知道当前语言是法语,则可以添加类&#39; gui-captions-very-long&#39;到html标记并根据该类应用CSS。这样,您就可以拥有一个可以根据语言配置的通用修饰符。我认为这比将所有标签放在一条线上更好。

请记住,较小的尺寸难以阅读。如果文本的长度是文本的两倍,则不能只将字体的大小设置为一半。您必须调整您的设计(或其实现)以使更长的文本成为可能。

答案 3 :(得分:2)

我建议一个很小的例子。在纯JavaScript上。

https://gist.github.com/dejurin/9bef02be6876e068ee276bee31cb3bcb

    "use strict";
    (function(w, d) {
        var fit = d.getElementById("fit");
        var wrap = d.getElementById("wrap");
        fontFitResize(fit, wrap);
        
            
    function fontFitResize(fit, wrap, step = 0.5) {
        var currentSize;
        while(fit.offsetWidth < wrap.offsetWidth) {
            currentSize = parseFloat(w.getComputedStyle(wrap, null).getPropertyValue('font-size'));
            wrap.style.fontSize = (currentSize - step) + 'px';
            console.log(wrap.style.fontSize);
        }
    }
        
    })(window, document);
.fit {
border: 1px solid #ff0000;
white-space:nowrap;
font-size:24px;
width:200px;
}
<div id="fit" class="fit">
  <span id="wrap">Resize font depending on string length</span>
</div>

答案 4 :(得分:1)

我确实在过去寻找那个,然后找到了一个真正为我做了诀窍的答案,但不记得确切...... :( 但是因为它确实使用纯javascript 没有插件/库来回答这个问题(从那以后做了一些优化),现在就是这样! (附实例):

// First we add a new function to the String prototype,
// this will be used to get the length of current string according
// to its font-family and font-size
String.prototype.textWidth = function(fontFamily, fontSize) {
  var container = document.createElement('div');
  container.style.visibility = 'hidden';
  container.style.fontFamily = fontFamily;
  container.style.fontSize = fontSize + 'px';
  container.style.display = 'inline';
  document.body.appendChild(container);
  container.innerHTML = this;
  var pxLength = container.offsetWidth;
  container.parentNode.removeChild(container);
  return pxLength;
};

// this is the function that will resize our text if it's too long
// classNameTarget (String) = the className of the element we need to resize e a 
//    tag or an id but you'll need to make modification to this function!
// maxWidth (int) = the max width (in px) of your final string
// fontFamily (String) = the family currently used by your string(wrong one might lead
//    to wrong result!)
// fontSize (int) = the initial font-size of your string
var testWidth = function(classNameTarget, maxWidth, fontFamily, fontSize) {
    maxWidth = maxWidth || 100;
    // first we get all targets
    var containers = document.getElementsByClassName(classNameTarget);
    for (var i = 0; i < containers.length; i++) {
    // for each of them we fetch their current length
        var length = containers[i].innerHTML.textWidth(fontFamily, fontSize);
        if (length > maxWidth){
        // if the current length is bigger then we resize it by using a span styling with
        // the new font-size
            containers[i].innerHTML = "<span style=\"font-size:" + Math.floor(parseInt(fontSize) / (length / maxWidth)) + "px;\">" + containers[i].innerHTML + "</span>";
        }
    }
};

// we want our cell to have text no longer than 75px while having them starting at 50px 
// font-size in arial
testWidth("firstname", 75, "arial", 50);
testWidth("lastname", 75, "arial", 50);
<table>
  <thead>
    <tr>
      <th>firstname</th>
      <th>lastname</th>
    </tr>
  </thead>
  <tbody style="font-size: 50px; font-family: arial;">
    <tr>
      <td class="firstname">Bob</td>
      <td class="lastname">Tomysonorubia</td>
    </tr>
    <tr>
      <td class="firstname">John</td>
      <td class="lastname">Doe</td>
    </tr>
    <tr>
      <td class="firstname">François-Xavier</td>
      <td class="lastname">De la nouvelle Orléan</td>
    </tr>
  </tbody>
</table>

testWidth方法可能需要一些关于你的当前需求的调整,或许你想调查querySelectorquerySelectorAll以使其非常通用