web-dev-qa-db-ja.com

文字列の長さに応じてフォントのサイズを変更する

垂直メニューがあり、ローカライズ可能にしたいのですが、メニュー要素のローカライズされた文字列がエッジから外れることがよくあります。
問題は、CSSの文字列の長さに応じてフォントのサイズを変更できるようにする方法です。そして可能であれば、JavaScriptなしで。
ありがとう!

UPD:JQueryは受け入れられません。 Pure JSではどうですか?

16
RussianVodka

プラグインの使用に慣れておく必要があります。プラグインは時間を大幅に節約し、もちろん非常に信頼性があります(プラグインは経験豊富なスクリプト作成者/プログラマーによって作成され、コミュニティによってテストされています)。ただし、純粋な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;
  }
}

デモ

デモでは、最初のメニュー#menu1がベトナム語の意味であり、2番目のメニュー#menu2がもちろん英語の単語であることがわかります。 = /// =)菊。長さは大きく異なりますが、どちらも100pxの固定幅であると想定されているため、2番目のメニュー#menu2は、スペースに合わせてフォントサイズを小さくする必要があります。

7
King King

jQuery Text Fill のように使用できます。

  1. プラグインをロードします:<script src="jquery.textfill.js" ></script>

  2. IDを入力してください<input type="text" id="dyntext" value="e=mc²"></input>

  3. コードを使用して魔法を実行します。できればこれを<script>タグに入れてください。

最終結果は次のようになります。

 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

5
Ali Gajani

これはJavascriptなしでは不可能です。 Javascriptを使用すると、 FitText のような多くのライブラリの1つを使用できます。

したがって、couldはこれにJavascriptライブラリを使用できますが、これは、さまざまなラベルのフォントサイズが異なることも意味します。複数行のキャプションを適切に処理するようにメニューのスタイルを設定するのが最善の方法だと思います。そうすれば、長さはそれほど重要ではありません。

一部の言語は他の言語よりも「長い」ため(たとえば、フランス語のラベルは英語の1.5〜2倍の平均であるため、これらの言語の1つでインターフェイスをテストすることをお勧めします。

また、フォントサイズについては、サーバー側に修飾子を追加できます。現在の言語がフランス語であることがわかっている場合は、htmlタグにクラス 'gui-captions-very-long'を追加できます。そのクラスに基づいてCSSを適用します。そうすれば、言語ごとに構成できる汎用修飾子を使用できます。これは、すべてのラベルを1行に収めるよりも優れたソリューションだと思います。

ただし、サイズが小さいほど読みにくいことに注意してください。テキストの長さが2倍の場合、フォントを半分のサイズにすることはできません。より長いテキストを可能にするには、デザイン(またはその実装)を調整する必要があります。

2
GolezTrol

小さな例を提案します。純粋な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>
2
Falselight

私は過去にそれを探しましたが、実際に私のためにトリックをした答えを見つけましたが、正確には覚えていません... :(しかし、それはpure 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メソッドは、現在のニーズに関していくつかの調整が必要な場合があります。おそらく、 querySelector または querySelectorAll を調べて、非常に一般的なものにする必要があります。

1
MI53RE