基于容器大小的字体缩放

1755

我很难理解字体缩放。

目前我有一个网站,正文的font-size为100%。100%是相对于什么呢?这似乎计算出16像素。

我一直以为100%会与浏览器窗口大小有关, 但显然不是这样,因为无论窗口是否调整大小到移动设备或全屏桌面,都是16像素。

我该如何使网站上的文本根据其容器自适应缩放?我试过使用em,但它也不能缩放。

我的想法是,当您调整大小时,像菜单这样的东西会变形,因此我需要减少与容器宽度相关的.menuItem等元素的pxfont-size。(例如,在大型桌面上的菜单中,22px非常完美。在平板电脑宽度下,16px更合适。)

我知道我可以添加断点,但我真的希望文本能够自适应缩放,并且拥有额外的断点,否则,我将控制文本的每100像素宽度而拥有数百个断点。


51
你需要的是响应式或视口尺寸字体。http://css-tricks.com/viewport-sized-typography/ - gearsdigital
12
看看 **FitText**。 - Patsy Issa
4
使用CSS容器查询 - Janosh
@PatsyIssa 有没有 fittext 的 React 版本? - undefined
41个回答

9

使用CSS变量

目前还没有人提到CSS变量,但这种方法对我来说最有效:

假设您的页面上有一列,其宽度为移动用户屏幕的100%,但具有最大宽度为800px,在桌面上,该列两侧有一些空间。请将以下内容放在页面顶部:

<script> document.documentElement.style.setProperty('--column-width', Math.min(window.innerWidth, 800)+'px'); </script>

现在,您可以使用该变量(而不是内置的vw单位)来设置字体的大小。例如:

p {
  font-size: calc( var(--column-width) / 100 );
}

虽然这不是一种纯粹的CSS方法,但它相当接近。


如果您需要从 JavaScript 进行操作,这实际上是一个很好的解决方案 - 谢谢! - Mladen Mihajlovic
这很酷,但我认为它不支持响应式设计,setProperty 只会运行一次,对吗? - BjornW
@BjornW 你可以简单地将它放在监听器中。例如,当页面调整大小时的监听器。 - LuckyLuke Skywalker

8

在艺术设计方面,如果你需要将两行或更多行的文本放在同一宽度内,无论字符数量如何,那么你有很好的选择。

最好找到一种动态解决方案,这样无论输入什么文本,我们都可以得到一个漂亮的显示。

让我们看看我们可能如何处理。

var els     = document.querySelectorAll(".divtext"),
refWidth    = els[0].clientWidth,
refFontSize = parseFloat(window.getComputedStyle(els[0],null)
                               .getPropertyValue("font-size"));

els.forEach((el,i) => el.style.fontSize = refFontSize * refWidth / els[i].clientWidth + "px")
#container {
  display: inline-block;
  background-color: black;
  padding: 0.6vw 1.2vw;
}
.divtext {
  display: table;
  color: white;
  font-family: impact;
  font-size: 4.5vw;
}
<div id="container">
  <div class="divtext">THIS IS JUST AN</div>
  <div class="divtext">EXAMPLE</div>
  <div class="divtext">TO SHOW YOU WHAT</div>
  <div class="divtext">YOU WANT</div>
</div>

我们所做的就是获取第一行的宽度(els[0].clientWidth)和字体大小(parseFloat(window.getComputedStyle(els[0],null).getPropertyValue("font-size")))作为参考,然后根据计算得到的结果,推断出后续行的字体大小。

8

使用vwem等单位肯定是可行的,但我认为它总需要人为微调。

这里有一个脚本,我刚写的,基于@ tnt-rox'的答案,试图自动化那种人为微调:

$('#controller').click(function(){
    $('h2').each(function(){
        var
            $el = $(this),
            max = $el.get(0),
            el = null
        ;
        max =
            max
            ? max.offsetWidth
            : 320
        ;
        $el.css({
            'font-size': '1em',
            'display': 'inline',
        });
        el = $el.get(0);

        el.get_float = function(){
            var
                fs = 0
            ;
            if (this.style && this.style.fontSize) {
                fs = parseFloat(this.style.fontSize.replace(/([\d\.]+)em/g, '$1'));
            }
            return fs;
        };

        el.bigger = function(){
            this.style.fontSize = (this.get_float() + 0.1) + 'em';
        };

        while (el.offsetWidth < max) {
            el.bigger();
        }

        // Finishing touch.
        $el.css({
            'font-size': ((el.get_float() -0.1) +'em'),
            'line-height': 'normal',
            'display': '',
        });
    });  // end of (each)
});    // end of (font scaling test)
div {
  width: 50%;
  background-color: tomato;
  font-family: 'Arial';
}

h2 {
  white-space: nowrap;
}

h2:nth-child(2) {
  font-style: italic;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="button" id="controller" value="Apply" />
<div>
  <h2>Lorem ipsum dolor</h2>
  <h2>Test String</h2>
  <h2>Sweet Concatenation</h2>
  <h2>Font Scaling</h2>
</div>

它基本上将字体大小减小到1em,然后从0.1开始递增直到达到最大宽度。 JSFiddle

7

百分之百相对于基础字体大小,如果您没有设置,它将是浏览器用户代理的默认大小。

为了获得您想要的效果,我建议使用一段JavaScript代码来根据窗口尺寸调整基础字体大小。


6

这个网页组件可以改变字体大小,使内部文本宽度与容器宽度匹配。请查看演示

您可以像这样使用:

<full-width-text>Lorem Ipsum</full-width-text>

6

6
在你的CSS中,在底部尝试添加以下内容,并将320像素宽度更改为你的设计开始断裂的位置:
@media only screen and (max-width: 320px) {
  body { font-size: 1em; }
}

那么,您需要根据自己的喜好以"px"或"em"的形式给出字体大小。

6
我已经准备好了一个简单的比例尺函数,使用CSS transform而不是font-size。您可以在任何容器中使用它,无需设置媒体查询等。 :)
博客文章: 全宽CSS和JS可伸缩头 代码:
function scaleHeader() {
  var scalable = document.querySelectorAll('.scale--js');
  var margin = 10;
  for (var i = 0; i < scalable.length; i++) {
    var scalableContainer = scalable[i].parentNode;
    scalable[i].style.transform = 'scale(1)';
    var scalableContainerWidth = scalableContainer.offsetWidth - margin;
    var scalableWidth = scalable[i].offsetWidth;
    scalable[i].style.transform = 'scale(' + scalableContainerWidth / scalableWidth + ')';
    scalableContainer.style.height = scalable[i].getBoundingClientRect().height + 'px';
  }
}

工作演示: https://codepen.io/maciejkorsan/pen/BWLryj

1
我认为OP正在寻找CSS解决方案。 - m02ph3u5

5

我的解决方案是基于jQuery的,通过逐渐增加字体大小直到容器高度大幅增加(意味着出现了换行),从而实现文本自适应。

它非常简单,但效果相当不错,并且非常易于使用。您不需要知道使用的字体有关的任何信息,一切都由浏览器处理。

您可以在http://jsfiddle.net/tubededentifrice/u5y15d0L/2/上进行测试。

神奇的事情发生在这里:

var setMaxTextSize=function(jElement) {
    // Get and set the font size into data for reuse upon resize
    var fontSize=parseInt(jElement.data(quickFitFontSizeData)) || parseInt(jElement.css("font-size"));
    jElement.data(quickFitFontSizeData, fontSize);

    // Gradually increase font size until the element gets a big increase in height (i.e. line break)
    var i = 0;
    var previousHeight;
    do
    {
        previousHeight=jElement.height();
        jElement.css("font-size", "" + (++fontSize) + "px");
    }
    while(i++ < 300 && jElement.height()-previousHeight < fontSize/2)

    // Finally, go back before the increase in height and set the element as resized by adding quickFitSetClass
    fontSize -= 1;
    jElement.addClass(quickFitSetClass).css("font-size", "" + fontSize + "px");

    return fontSize;
};

4
我的问题与缩放标题中的文本类似。我尝试了Fit Font,但需要切换压缩器才能得到任何结果,因为它解决的问题略有不同,Text Flow也是如此。
所以我编写了自己的小插件,将字体大小缩小到适合容器大小,假设您具有overflow: hidden和white-space: nowrap,即使将字体缩小到最小也无法显示完整的标题,它只会截断可以显示的部分。
(function($) {

  // Reduces the size of text in the element to fit the parent.
  $.fn.reduceTextSize = function(options) {
    options = $.extend({
      minFontSize: 10
    }, options);

    function checkWidth(em) {
      var $em = $(em);
      var oldPosition = $em.css('position');
      $em.css('position', 'absolute');
      var width = $em.width();
      $em.css('position', oldPosition);
      return width;
    }

    return this.each(function(){
      var $this = $(this);
      var $parent = $this.parent();
      var prevFontSize;
      while (checkWidth($this) > $parent.width()) {
        var currentFontSize = parseInt($this.css('font-size').replace('px', ''));
        // Stop looping if min font size reached, or font size did not change last iteration.
        if (isNaN(currentFontSize) || currentFontSize <= options.minFontSize ||
            prevFontSize && prevFontSize == currentFontSize) {
          break;
        }
        prevFontSize = currentFontSize;
        $this.css('font-size', (currentFontSize - 1) + 'px');
      }
    });
  };
})(jQuery);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接