Изменение размера шрифта в зависимости от длины строки
У меня есть вертикальное меню, и я хочу сделать его локализуемым, но локализованные строки в элементах меню часто выходят за край.
Поэтому вопрос заключается в том, как изменить размер шрифта в зависимости от длины строки в CSS. И если возможно, без JavaScript.
Спасибо!
UPD: JQuery неприемлемо. В любом случае в Pure JS?
Ответы
Ответ 1
Вы должны ознакомиться с использованием плагинов, они экономят много времени и, конечно же, они очень надежны (они написаны опытными сценаристами/программистами и были протестированы сообществом). Однако похоже, что вы хотите получить чистое решение JS. Я только что сделал этот код для вас. Он работает нормально (хотя я не уверен, насколько он хорош, как некоторые плагины). Единственным требованием является элемент (который вы хотите скорректировать размер шрифта в соответствии с длиной текста) должен содержать обычный текст, а не некоторый HTML-код.
Идея реализовать его с использованием чистого JS проста, вам нужен какой-то фиктивный элемент, созданный с помощью script, этот фиктивный элемент используется для измерения размера текста. Нам нужно настроить размер шрифта фиктивного элемента до тех пор, пока размер текста (как и фиктивный элемент) не будет ограничен размером элемента (размер шрифта которого вы хотите настроить). Я сделал код очень четко, надеюсь, что вы поймете это лучше после прочтения кода:
//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
- это вьетнамское слово, означающее хризантему, а второе меню #menu2
- это, конечно, английское слово хризантема. Они имеют разную длину, однако обе должны иметь фиксированную ширину 100px
, поэтому второе меню #menu2
должно иметь меньший размер шрифта, чтобы соответствовать пространству.
Ответ 2
Вы можете использовать jQuery Text Fill, как это.
-
Загрузите плагин: <script src="jquery.textfill.js" ></script>
-
Поместите id <input type="text" id="dyntext" value="e=mc²"></input>
-
Используйте код для создания магии. Предпочтительно поместите это в теги <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]()
Ответ 3
Это невозможно без Javascript. Используя Javascript, вы можете использовать одну из многих библиотек, например FitText.
Таким образом, вы можете использовать Javascript-библиотеку для этого, но это также означает, что разные метки имеют разные размеры шрифта.
Я думаю, что лучшим подходом было бы стиль меню таким образом, чтобы он грациозно обрабатывал многострочные подписи. Таким образом, длина не имеет большого значения.
Потому что какой-то язык "длиннее", чем другие (например, французские метки в avarage в 1,5-2 раза больше, чем на английском языке, рекомендуется протестировать ваш интерфейс с одним из этих языков.
И для размера шрифта вы можете добавить модификатор на стороне сервера, если вы знаете, что текущий язык является французским, вы можете добавить класс 'gui-subtions-very-long' в тег html
и примените свой CSS на основе этого класса. Таким образом, у вас может быть универсальный модификатор, который вы можете настроить для каждого языка. Я думаю, что лучшее решение, чем создание всех меток, соответствует одной строке.
Имейте в виду, что более мелкие размеры труднее читать. Вы не можете просто сделать шрифты на половину размера, если текст в два раза длиннее. Вам нужно будет настроить свой дизайн (или его реализацию), чтобы сделать возможными более длинные тексты.
Ответ 4
Я действительно искал это в прошлом, тогда нашел ответ, который действительно помогло, но не мог вспомнить точно...:(
Но так как он отвечает на вопрос, используя чистый 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 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>
Ответ 5
Я предлагаю крошечный пример. На чистом 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>