【问题标题】:Scale font size based on content (CSS or JS)根据内容(CSS 或 JS)缩放字体大小
【发布时间】:2017-09-19 19:16:51
【问题描述】:

注意,我不是要求根据视口的大小来缩放字体 - 我的问题是不同的。

我的 HTML/CSS/JS 应用程序本质上向用户呈现了一个状态图。屏幕上有一条带有许多按钮的消息。按下每个按钮会导致不同的屏幕 - 等等 - 确实是非常简单的概念。

作为每个按钮的每个屏幕的文本来自数据库。

设计使得按钮大小是固定的(我无法控制它)。它们足够大,几乎可以容纳应用程序可能遇到的任何内容 - 英文。

最近,我需要添加对斯瓦希里语的支持 - 突然之间,2 个单词的 15 个英文字符变成了 5 个单词,其中 50 个斯瓦希里语字符 - 它不适合按钮。这是相当糟糕的——然而只有少数这样长的按钮标签。不幸的是,由于它们是动态的(来自数据库),我无法预测它会是什么。

我能做的就是减小字体大小以适应按钮内的文本。使用vwvh 等单位不起作用,因为无论视口大小如何,文本都应缩放为固定大小的按钮。

我想不出任何纯 CSS 的解决方案。我可以想到几个 JS 解决问题的方法(例如,放置文本,然后继续缩小直到适合 - 虽然我不太确定如何确定它适合)。

我只是无法完全弄清楚这一点。有任何想法吗?我对 CSS3 和 HTML5 很满意,只需要它在最新版本的 Chrome 和 Safari 中工作。

【问题讨论】:

  • 如果您可以将文本放入 SVG 元素中 - css-tricks.com/svg-text-typographic-designs
  • @Aprillion 嗯,有趣的想法。不幸的是 SVG 不支持自动换行。现在按钮最多允许 3 行文本,自动换行,垂直和水平居中。
  • 您可以使用虚拟元素进行计算吗? (如果你是我可能有一个解决方案)
  • Note, I am not asking to scale font based on size of container 你不是吗?听起来你想缩放字体,因为容器的大小太小了
  • @treyhakanson 我会采用任何解决方案

标签: javascript css font-size


【解决方案1】:

查看这个 jsbin:http://jsbin.com/sunamej/1/edit?html,css,js,output

文本根据在带有white-space: nowrap 的虚拟文本容器上进行的计算进行缩放。这允许将文本的总宽度与按钮的总宽度进行比较,并按比例缩小。请记住,由于没有考虑到单词的换行位置,因此会出现一些错误。包含的错误因素在很大程度上缓解了这种情况,但可能需要针对您的应用程序进行微调。实际上计算一些东西以完全考虑自动换行的位置将是艰巨的,并且对于只有几个单词/行的这样的应用程序来说是不工作的。以下是 bin 中的完整代码:

HTML:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <button class="btn">
    <span class="dummy-text">
      Testing with some large text that should scale
    </span>
    <span class="text">
      Testing with some large text that should scale
    </span>
  </button>
  <button class="btn">
    <span class="dummy-text">
      Testing with some
    </span>
    <span class="text">
      Testing with some
    </span>
  </button>
  <button class="btn">
    <span class="dummy-text">
      Testing with some large text
    </span>
    <span class="text">
      Testing with some large text
    </span>
  </button>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
</body>
</html>

CSS:

.btn {
  /* hardcoded dimens */
  height: 35px;
  width: 75px;
}

.dummy-text {
  /* hide dummy, don't wrap */
  display: none;
  white-space: nowrap;
}

Javascript:

console.clear();
// NOTE: use of jQuery is arbitrary; all functions
// are available in vanilla js

function scaleText(btn) {
  // select the dummy text
  var dtxt = btn.find('.dummy-text');
  // select the real text
  var txt = btn.find('.text');

  // get te with of the button and the dummy
  var tw = dtxt.width();
  var bw = btn.width();

  // number of lines of text the button allows
  var lines = 2;
  // factoring in error caused by wrapping; this
  // may need fine tuning for your application
  var err = 0.85;
  // get the fonts scale
  var scale = (bw * lines * err)/tw;

  // get the current font size
  var sz = parseInt(dtxt.css('font-size').replace('px', ''));
  // scale appropiately
  txt.css('font-size', sz * scale + 'px');
}

// apply to each button
var btns = $('.btn');
btns.each(function(i, btn) {
  scaleText($(btn));
});

【讨论】:

  • 谢谢,我去看看。我怀疑它需要大量的微调,因为几乎所有长文本都包含比宽度的一半稍长的单词,从而迫使额外的换行符。如果我仅根据字符和行宽来打断文本,我会得到两行,但如果换行适当,我会得到四行。
【解决方案2】:

Adjust size of an SVG-element to its content 的启发,它需要更多的微调和一种将长文本拆分为适当行数的方法,如果您可以从文本长度猜测宽度/高度,可能会用foreignObject 换行...但是这是一个可能的开始:

[...document.getElementsByTagName("svg")].forEach(svg => {
  const bbox = svg.getBBox();
  svg.setAttribute("viewBox", [bbox.x, bbox.y, bbox.width, bbox.height].join(" "));
})
button {
  width: 100px;
  height: 50px;
  padding: 0;
}

svg {
  width: 100%;
  height: 100%;
}
<button>
  <svg>
    <text>Short</text>
  </svg>
</button>
<button>
  <svg>
    <text>Longer text</text>
    <text y='1em'>split externally</text>
    <text y='2em'>to balanced lines</text>
  </svg>
</button>

【讨论】:

    猜你喜欢
    • 2022-10-24
    • 1970-01-01
    • 2020-04-25
    • 1970-01-01
    • 2016-09-14
    • 2019-10-13
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    相关资源
    最近更新 更多