基于容器大小的字体缩放

Font scaling based on size of container

提问人:Francesca 提问时间:4/17/2013 最后编辑:TylerHFrancesca 更新时间:8/15/2023 访问量:2084287

问:

我很难弄清楚字体缩放。

我目前有一个网站,正文是 100%。100%的呢?这似乎是在 16 像素处计算出来的。font-size

我的印象是 100% 会以某种方式指浏览器窗口的大小,但显然不是,因为无论窗口大小调整为移动宽度还是成熟的宽屏桌面,它始终是 16 像素。

如何使网站上的文本与其容器相关?我尝试使用 ,但这也无法扩展。em

我的理由是,当你调整大小时,像我的菜单这样的东西会被压扁,所以我需要减少与容器宽度相关的其他元素。(例如,在大桌面上的菜单中,可以完美运行。向下移动到平板电脑宽度,更合适。pxfont-size.menuItem22px16px

我知道我可以添加断点,但我真的希望文本能够缩放并具有额外的断点,否则,我最终会因为宽度每减少 100 像素而产生数百个断点来控制文本。

CSS 响应式设计 字体大小

评论

51赞 gearsdigital 4/17/2013
您要查找的称为响应式或视口大小的排版。css-tricks.com/viewport-sized-typography
12赞 Patsy Issa 11/6/2013
看看 FitText
4赞 Janosh 1/30/2023
使用 CSS 容器查询
0赞 Syed M. Sannan 10/7/2023
@PatsyIssa fittext 有 react 版本吗?

答:

7赞 scottlimmer 4/17/2013 #1

100% 是相对于基本字体大小的,如果您尚未设置,则该字体大小将是浏览器的用户代理默认值。

为了获得您想要的效果,我会使用一段 JavaScript 代码来调整相对于窗口尺寸的基本字体大小。

6赞 Chunky 8/1/2013 #2

在你的CSS中,试着在底部添加这个,改变320像素的宽度,以适应你的设计开始中断的地方。

@media only screen and (max-width: 320px) {
  body { font-size: 1em; }
}

然后根据需要在“px”或“em”中给出字体大小。

1853赞 2507rkt3 11/6/2013 #3

容器查询现在可能是最佳选择,具体取决于您的用例,并且支持所有主要浏览器。在此处查看支持级别:https://caniuse.com/mdn-css_properties_container

现在非常容易控制

.module h2 {
  font-size: 1em;
  container-name: sidebar
}

@container sidebar (min-width: 700px) {
  .module h2 {
    font-size: 2em;
  }
}

请查看 MDN 文章 容器查询 了解更多详情: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries

您可以完成的任务的更多示例: https://css-tricks.com/a-few-times-container-size-queries-would-have-helped-me-out/

=========================

旧答案

如果容器不是正文,则 CSS Tricks 涵盖了 Fitting Text to a Container 中的所有选项。

如果容器是正文,则要查找的是视口百分比长度

视口百分比长度初始包含块的大小有关。当初始包含块的高度或宽度发生变化时,它们会相应地缩放。但是,当根元素上的溢出值为 auto 时,假定任何滚动条都不存在。

这些值为:

  • vw(视口宽度的百分比)
  • vh(视口高度的百分比)
  • vi(根元素内联轴方向的视口大小的 1%)
  • vb(根元素块轴方向上视口大小的 1%)
  • vmin(或vwvh)
  • vmax(以较大者或 或vwvh)

1 v* 等于初始包含块的 1%。

使用它看起来像这样:

p {
    font-size: 4vw;
}

如您所见,当视口宽度增加时,,font-size

这些值是一个大小调整单位,就像 或 一样,因此它们也可用于调整其他元素的大小,例如宽度、边距或填充。pxem

浏览器支持相当不错,但您可能需要回退,例如:

p {
    font-size: 16px;
    font-size: 4vw;
}

查看支持统计信息:http://caniuse.com/#feat=viewport-units

另外,请查看 CSS-Tricks 以获得更广泛的了解: 视口大小的排版

这是一篇关于设置最小/最大尺寸和对尺寸进行更多控制的好文章: 精确控制响应式排版

这是一篇关于使用 calc() 设置大小以使文本填充视口的文章: http://codepen.io/CrocoDillon/pen/fBJxu

另外,请查看这篇文章,该文章也使用一种称为“熔融引导”的技术来调整行高。熔融在CSS中的领先地位

评论

4赞 Simon East 1/1/2023
有时你不希望缩放如此戏剧性,而是更微妙 - 例如针对移动设备稍微缩小字体大小,但不要太小以至于难以阅读。在这种情况下,您可以使用 or 来设置基本大小,然后将视口的百分比添加到该基本大小。玩弄数字以获得所需的适当缩放量。font-size: calc(1rem + 2vw)
0赞 Joshua Robison 1/28/2023
容器查询现在就是答案。这个答案已经过时了
1赞 OOPS Studio 4/6/2023
容器查询似乎还没有很好的工具支持。Visual Studio Code 告诉我 , , 和 是无法识别的 CSS 属性,它也无法识别 at 规则。使用查询也会导致 SvelteKit 出错,告诉我这是不正确的语法。我不会说容器查询在任何地方都使这个答案过时了。也许再给它几年时间,让它们在工具社区中被正确采用。container-typecontainer-namecontainer@container@container
419赞 ScottS 11/7/2013 #4

但是,如果容器不是视口(正文)呢?

Alex2507rkt3 的回答下的评论中提出了这个问题。

这一事实并不意味着不能在某种程度上用于该容器的大小。现在,要看到任何变化,必须假设容器在某种程度上是灵活的。无论是通过直接百分比还是通过 100% 减去利润。如果容器始终设置为宽,那么这一点就变得“没有意义”了,那么只需设置一个适用于该宽度的容器即可。vwwidth200pxfont-size

示例 1

但是,对于灵活宽度的容器,必须意识到容器在某种程度上仍会根据视口调整大小。因此,需要根据视口的大小差异百分比来调整设置,这意味着要考虑父包装器的大小。举个例子vw

div {
    width: 50%;
    border: 1px solid black;
    margin: 20px;
    font-size: 16px;
    /* 100 = viewport width, as 1vw = 1/100th of that
       So if the container is 50% of viewport (as here)
       then factor that into how you want it to size.
       Let's say you like 5vw if it were the whole width,
       then for this container, size it at 2.5vw (5 * .5 [i.e. 50%])
    */
    font-size: 2.5vw;
}

假设这里 是 的子项,它的宽度是这个基本情况下的视口大小。基本上,你想设置一个对你来说看起来不错的。正如你在上面的CSS内容中的评论中看到的那样,你可以从数学上“思考”整个视口的大小,但你不需要这样做。文本将与容器一起“弯曲”,因为容器会随着视口大小的调整而弯曲。下面是两个不同大小的容器的示例divbody50%100%vw

示例 2

您可以通过强制基于视口进行计算来帮助确保视口大小。请看这个例子

html {width: 100%;} /* Force 'html' to be viewport width */
body {width: 150%; } /* Overflow the body */

div {
    width: 50%;
    border: 1px solid black;
    margin: 20px;
    font-size: 16px;
    /* 100 = viewport width, as 1vw = 1/100th of that
       Here, the body is 150% of viewport, but the container is 50%
       of viewport, so both parents factor  into how you want it to size.
       Let's say you like 5vw if it were the whole width,
       then for this container, size it at 3.75vw
       (5 * 1.5 [i.e. 150%]) * .5 [i.e. 50%]
    */
    font-size: 3.75vw;
}

大小调整仍然基于视口,但实质上是基于容器大小本身设置的。

如果容器的大小动态变化...

如果容器元素的大小最终通过断点或 JavaScript 动态更改其百分比关系,那么无论基本“目标”是什么,都需要重新计算以保持文本大小的相同“关系”。@media

以上面的 #1 为例。如果 通过 或 JavaScript 将 切换到 width,则同时需要在媒体查询或 JavaScript 中调整为 .这将使文本大小与原始容器的“宽度”从视口大小减少一半时的大小相同,但现在由于其自身百分比计算的更改而减小。div25%@mediafont-size5vw * .25 = 1.2550%

挑战

使用 CSS calc() 函数时,动态调整将变得困难,因为该函数目前不适用于目的。因此,如果您的宽度正在更改,则无法进行纯粹的CSS调整。当然,对边距宽度的微小调整可能不足以保证 的任何更改,因此这可能无关紧要。font-sizecalc()font-size

评论

36赞 Himmators 11/14/2014
很好的答案,但是,如果包含元素具有最大宽度,它将不起作用。
4赞 Pixel Reaper 11/9/2013 #5

试 http://simplefocus.com/flowtype/。这是我用于我的网站的,它运行良好。

6赞 Sijav 11/10/2013 #6

您可能正在寻找这样的东西:


http://jsfiddle.net/sijav/dGsC9/4/ http://fiddle.jshell.net/sijav/dGsC9/4/show/

我使用了 flowtype,它运行良好(但它是 JavaScript 而不是纯粹的 CSS 解决方案):

$('body').flowtype({
    minFont: 10,
    maxFont: 40,
    minimum: 500,
    maximum: 1200,
    fontRatio: 70
});
29赞 Dan Ovidiu Boncut 11/11/2013 #7

这个问题有一个很大的哲学。

最简单的方法是给 body 指定一定的字体大小(我建议 10),然后所有其他元素的字体都在 or 中。 我举个例子来理解这些单位。 始终相对于其父级:emremEm

body{font-size: 10px;}
.menu{font-size: 2em;} /* That means 2*10 pixels  = 20 pixels */
.menu li{font-size: 1.5em;} /* That means 1.5*20 pixels = 30 pixels */

Rem始终相对于身体:

body{font-size: 10px;}
.menu{font-size: 2rem;} /* That means 2*10 pixels = 20 pixels */
.menu li{font-size: 1.5rem;} /* that means 1.5*10 pixels = 15 pixels */

然后,您可以创建一个脚本,该脚本将修改相对于容器宽度的字体大小。 但这不是我推荐的。因为例如,在一个 900 像素宽的容器中,你会有一个字体大小为 12 像素的元素。根据你的想法,这将成为一个 300 像素宽的容器,字体大小为 4 像素。必须有一个下限。p

其他解决方案是使用媒体查询,以便您可以设置不同宽度的字体。

但我推荐的解决方案是使用一个 JavaScript 库来帮助您解决这个问题。还有到目前为止我找到的 fittext.js

27赞 tnt-rox 1/7/2014 #8

功能如下:

document.body.setScaledFont = function(f) {
  var s = this.offsetWidth, fs = s * f;
  this.style.fontSize = fs + '%';
  return this
};

然后将所有文档子元素字体大小转换为 's 或 .em%

然后将类似这样的内容添加到代码中以设置基本字体大小。

document.body.setScaledFont(0.35);
window.onresize = function() {
    document.body.setScaledFont(0.35);
}

http://jsfiddle.net/0tpvccjt/

5赞 Vincent 3/27/2015 #9

我自己的解决方案,基于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;
};
14赞 Roman Rekhler 4/13/2015 #10

这可能不是非常实用,但如果你想让字体成为父字体的直接函数,而没有任何 JavaScript 来侦听/循环(间隔)来读取 div/page 的大小,有一种方法可以做到这一点。iframe。

iframe 中的任何内容都会将 iframe 的大小视为视口的大小。因此,诀窍是制作一个 iframe,其宽度是您希望文本的最大宽度,并且其高度等于最大高度 * 特定文本的纵横比。

撇开视口单位不能与文本的父单位并列的限制不谈(例如,让 % 大小的行为与其他所有人一样),视口单位确实提供了一个非常强大的工具:能够获得最小/最大尺寸。你不能在其他任何地方这样做——你不能说......使此 div 的高度为父级 * 的宽度。

话虽如此,诀窍是使用 vmin,并设置 iframe 大小,以便当高度为限制尺寸时,[fraction] * total height 是一个好的字体大小,而当宽度是限制尺寸时,[fraction] * total width。这就是为什么高度必须是宽度和纵横比的乘积。

对于我的具体例子,你有

.main iframe{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  height: calc(3.5 * 100%);
  background: rgba(0, 0, 0, 0);
  border-style: none;
  transform: translate3d(-50%, -50%, 0);
}

这种方法的小麻烦是你必须手动设置 iframe 的 CSS。如果附加整个CSS文件,则会占用许多文本区域的大量带宽。所以,我要做的是直接从我的CSS中附加我想要的规则。

var rule = document.styleSheets[1].rules[4];
var iDoc = document.querySelector('iframe').contentDocument;
iDoc.styleSheets[0].insertRule(rule.cssText);

您可以编写获取 CSS 规则/所有会影响文本区域的 CSS 规则的小函数。

我想不出另一种方法,如果没有一些循环/收听 JavaScript。真正的解决方案是让浏览器提供一种方法来缩放文本作为父容器的函数,并提供相同的 vmin/vmax 类型功能。

JSFiddle:https://jsfiddle.net/0jr7rrgm/3/(单击一次将红色方块锁定到鼠标上,再次单击可松开)

小提琴中的大多数 JavaScript 只是我的自定义点击拖动功能。

155赞 Dantio 6/19/2015 #11

SVG 解决方案:

.resizeme {
  resize: both;
  margin: 0;
  padding: 0;
  height: 75px;
  width: 500px;
  background-color: lightblue;
  overflow: hidden;
}
<div class="resizeme">
  <svg
    width="100%"
    height="100%"
    viewBox="0 0 500 75"
    preserveAspectRatio="xMinYMid meet"
    style="background-color:green"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
  >
        <text
          x="0"
          y="75"
          font-size="75"
          fill="black"
        >█Resize This█</text>
      </svg>
</div>

SVG和文本换行的解决方案,使用:foreignObject

.resizeme {
  resize: both;
  margin: 0;
  padding: 0;
  height: 200px;
  width: 500px;
  background-color: lightblue;
  overflow: hidden;
}
<div class="resizeme">
  <svg
    width="100%"
    height="100%"
    viewBox="0 0 500 200"
    preserveAspectRatio="xMinYMin meet"
  >
      <foreignObject width="100%" height="100%" xmlns="http://www.w3.org/1999/xhtml">
        <div xmlns="http://www.w3.org/1999/xhtml" style="background-color:lightgreen;">
          <h1>heading</h1>
          <p>Resize the blue box.</p>
        </div>
      </foreignObject>
    </svg>
</div>

4赞 Aram Kocharyan 12/19/2015 #12

我的问题与此类似,但与缩放标题内的文本有关。我尝试了 Fit Font,但我需要切换压缩器才能获得任何结果,因为它解决了一个略有不同的问题,就像 Text Flow 一样。

所以我写了我自己的小插件,减小字体大小以适应容器,假设你有,这样即使将字体减小到最小不允许显示完整的标题,它也只是切断了它可以显示的内容。overflow: hiddenwhite-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);
56赞 lsblsb 3/11/2016 #13

在我的一个项目中,我使用 vw 和 vh 之间的“混合”来调整字体大小以满足我的需要,例如:

font-size: calc(3vw + 3vh);

我知道这并不能回答 OP 的问题,但也许它可以成为其他任何人的解决方案。

-1赞 Xeridea 6/28/2016 #14

如果问题是字体在宽屏桌面上变得太大,我认为最简单的 CSS 方法是这样的(假设包装器最大宽度为 1000 像素)

.specialText{
    font-size: 2.4vw;
}

@media only screen and (min-width: 1000px) {
    .specialText {
        width: 24px;
    }
}

因此,对于任何小于容器最大宽度的屏幕,它都会自动调整大小,当屏幕较宽时,它会固定大小(就像几乎所有台式机和笔记本电脑一样)。

55赞 hegez 9/1/2016 #15

具有 、 CSS 单位和数学的纯 CSS 解决方案calc()

这恰恰不是 OP 所要求的,但可能会让某人开心。这个答案并不容易,需要开发人员进行一些研究。

我终于得到了一个纯CSS解决方案,用于不同的单元。您将需要对公式有一些基本的数学理解才能计算出 的表达式。calc()calc()

当我解决这个问题时,我必须得到一个全页宽度的响应式标题,并在 DOM 中填充一些父级。我将在这里使用我的值,用你自己的值替换它们。

到数学

您将需要:

  • 在某些视口中很好地调整了比例。我使用了 320 像素,因此我得到了 24 像素高和 224 像素宽,所以比例是 9.333......或 28 / 3
  • 容器宽度,我有和全宽,所以这得到了padding: 3em100wv - 2 * 3em

X 是容器的宽度,因此请将其替换为您自己的表达式或调整值以获得整页文本。 是您将拥有的比率。您可以通过调整某些视口中的值、检查元素宽度和高度并将它们替换为您自己的值来获得它。此外,它是Rwidth / heigth ;)

x = 100vw - 2 * 3em = 100vw - 6em
r = 224px/24px = 9.333... = 28 / 3

y = x / r
  = (100vw - 6em) / (28 / 3)
  = (100vw - 6em) * 3 / 28
  = (300vw - 18em) / 28
  = (75vw - 4.5rem) / 7

砰!成功了!我写了

font-size: calc((75vw - 4.5rem) / 7)

到我的标题,它在每个视口中都很好地调整了。

但它是如何工作的呢?

我们需要一些常量。 表示视口的全宽,我的目标是建立带有一些填充的全宽标题。100vw

比率。在一个视口中获取宽度和高度可以让我使用比率,并且通过比率,我知道其他视口宽度的高度应该是多少。手动计算它们需要花费大量时间,并且至少需要大量带宽,因此这不是一个好的答案。

结论

我想知道为什么没有人弄清楚这一点,有些人甚至说这不可能修补CSS。我不喜欢使用 JavaScript 来调整元素,所以我不接受 JavaScript(并且忘记 jQuery)答案,而无需深入挖掘。总而言之,这很好,这是在网站设计中实现纯CSS的一个步骤。

对于我的文本中任何不寻常的约定,我深表歉意,我的母语不是英语,而且对编写 Stack Overflow 答案也很陌生。

还应该注意的是,我们在某些浏览器中有邪恶的滚动条。例如,在使用Firefox时,我注意到这意味着视口的整个宽度,延伸到滚动条下(内容无法扩展!),因此全角文本必须仔细留边距,最好在许多浏览器和设备上进行测试。100vw

评论

30赞 Andrei Volgin 11/18/2016
仅当 (1) 您知道字体,(2) 字体在用户设备上可用,并且 (3) 文本始终相同时,此解决方案才有效。这使得它成为一个非常有限的用例。
2赞 Bobort 2/15/2022
滚动条不是邪恶的。我个人鄙视隐藏滚动条的新简单设计,直到你把鼠标悬停在它原来的位置。可访问性和所有。
2赞 marirena 9/20/2016 #16

始终使元素具有以下属性:

JavaScript的:element.style.fontSize = "100%";

CSS:style = "font-size: 100%;"

当您进入全屏模式时,您应该已经计算出一个比例变量(比例 > 1 或比例 = 1)。然后,在全屏模式下:

document.body.style.fontSize = (scale * 100) + "%";

它只需很少的代码即可很好地工作。

6赞 pomber 10/30/2016 #17

此 Web 组件更改字体大小,使内部文本宽度与容器宽度匹配。查看演示

你可以像这样使用它:

<full-width-text>Lorem Ipsum</full-width-text>
1赞 thdoan 1/5/2017 #18

作为 JavaScript 后备(或您的唯一解决方案),您可以使用我的 jQuery Scalem 插件,它允许您通过传递选项来相对于父元素(容器)进行缩放。reference

6赞 Maciej Korsan 3/7/2017 #19

我准备了一个简单的缩放函数,使用 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赞 m02ph3u5 3/7/2017
我认为OP正在寻找CSS解决方案。
2赞 Basheer AL-MOMANI 3/16/2017 #20

看看我的代码。它使那里的任何东西。font size smallerfit

但我认为这并不能带来良好的用户体验

var containerWidth = $("#ui-id-2").width();
var items = $(".quickSearchAutocomplete .ui-menu-item");
var fontSize = 16;

items.each(function(){
    // Displaying a value depends sometimes on your case. You may make it block or inline-table instead of inline-block or whatever value that make the div take overflow width.
    $(this).css({"whiteSpace": "nowrap", "display": "inline-block"});
    while ($(this).width() > containerWidth){
         console.log("$(this).width()" + $(this).width() + "containerWidth" + containerWidth)
         $(this).css("font-size", fontSize -= 0.5);
    }
});

Result

1赞 pk1557 6/14/2017 #21

如果它对任何人都有帮助,此线程中的大多数解决方案都是将文本包装成多行,形式为 e。

但后来我发现了这一点,它奏效了:

https://github.com/chunksnbits/jquery-quickfit

用法示例:

$('.someText').quickfit({max:50,tolerance:.4})

3赞 krolovolk 7/6/2017 #22

尝试使用 fitText 插件,因为视口大小不是这个问题的解决方案。

只需添加库:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

并通过设置文本系数来更改字体大小以使其正确:

$("#text_div").fitText(0.8);

您可以设置文本的最大值和最小值:

$("#text_div").fitText(0.8, { minFontSize: '12px', maxFontSize: '36px' });
8赞 WoodrowShigeru 8/6/2017 #23

使用 , & co. 肯定有效,但 IMO 它总是需要人工的触摸来微调。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>

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

JSFiddle

1赞 pajouk 10/17/2017 #24

对于动态文本,这个插件非常有用:

http://freqdec.github.io/slabText/

只需添加 CSS:

.slabtexted .slabtext
{
    display: -moz-inline-box;
    display: inline-block;
    white-space: nowrap;
}
.slabtextinactive .slabtext
{
    display: inline;
    white-space: normal;
    font-size: 1em !important;
    letter-spacing: inherit !important;
    word-spacing: inherit !important;
    *letter-spacing: normal !important;
    *word-spacing: normal !important;
}
.slabtextdone .slabtext
{
    display: block;
}

还有脚本:

$('#mydiv').slabText();
-1赞 Muckee 11/8/2017 #25

为了使 font-size 适合其容器,而不是窗口,请参阅我在此问题中分享的功能(其他答案的组合,其中大部分已经链接在这里)。它是使用 触发的。resizeFont()window.addEventListener('resize', resizeFont);

Vanilla JavaScript:调整 font-awesome 的大小以适合容器

JavaScript的:

function resizeFont() {
  var elements  = document.getElementsByClassName('resize');
  console.log(elements);
  if (elements.length < 0) {
    return;
  }
  _len = elements.length;
  for (_i = 0; _i < _len; _i++) {
    var el = elements[_i];
    el.style.fontSize = "100%";
    for (var size = 100; el.scrollHeight > el.clientHeight; size -= 10) {
      el.style.fontSize = size + '%';
    }
  }
}

您也许可以使用 vw/vh 作为后备,因此您可以使用 JavaScript 动态分配 or 单位,确保在禁用 JavaScript 时字体确实会缩放到窗口。emrem

将该类应用于包含要缩放的文本的所有元素。.resize

在添加窗口调整大小事件侦听器之前触发该函数。然后,任何不适合其容器的文本都将在页面加载时以及调整其大小时缩小。

注意:默认值必须设置为 ,或 才能获得正确的结果。font-sizeemrem%

2赞 Maurizio Ricci 1/13/2018 #26

这对我有用:

我尝试根据设置“font-size: 10px”获得的宽度/高度来估算字体大小。基本上,这个想法是“如果我有 20 像素宽度和 11 像素高度,并且'font-size: 10px',那么计算一个 50 像素宽度和 30 像素高度的容器的最大字体大小是多少?

答案是双比例系统:

{ 20:10=50:X, 11:10=30:Y } = { X= (10*50)/20, Y= (10*30)/11 }

现在 X 是与宽度匹配的字体大小,Y 是与高度匹配的字体大小;取最小值

function getMaxFontSizeApprox(el){
    var fontSize = 10;
    var p = el.parentNode;

    var parent_h = p.offsetHeight ? p.offsetHeight : p.style.pixelHeight;
    if(!parent_h)
        parent_h = 0;

    var parent_w = p.offsetHeight ? p.offsetWidth : p.style.pixelWidth;
    if(!parent_w)
        parent_w = 0;

    el.style.fontSize = fontSize + "px";

    var el_h = el.offsetHeight ? el.offsetHeight : el.style.pixelHeight;
    if(!el_h)
        el_h = 0;

    var el_w = el.offsetHeight ? el.offsetWidth : el.style.pixelWidth;
    if(!el_w)
        el_w = 0;

    // 0.5 is the error on the measure that JavaScript does
    // if the real measure had been 12.49 px => JavaScript would have said 12px
    // so we think about the worst case when could have, we add 0.5 to 
    // compensate the round error
    var fs1 = (fontSize*(parent_w + 0.5))/(el_w + 0.5);
    var fs2 = (fontSize*(parent_h) + 0.5)/(el_h + 0.5);

    fontSize = Math.floor(Math.min(fs1,fs2));
    el.style.fontSize = fontSize + "px";
    return fontSize;
}

注意:函数的参数必须是 span 元素或小于其父元素的元素,否则如果子元素和父元素具有相同的宽度/高度函数将失败。

29赞 user1816910 3/13/2018 #27

有一种方法可以在没有 JavaScript 的情况下做到这一点!

您可以使用内联 SVG 图像。如果 SVG 是内联的,则可以在 SVG 上使用 CSS。您必须记住,使用此方法意味着您的 SVG 图像将响应其容器大小。

尝试使用以下解决方案...

[HTML全文]

<div>
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360.96 358.98" >
      <text>SAVE $500</text>
  </svg>
</div>

CSS的

div {
  width: 50%; /* Set your container width */
  height: 50%; /* Set your container height */

}

svg {
  width: 100%;
  height: auto;

}

text {
  transform: translate(40px, 202px);
  font-size: 62px;
  fill: #000;
}

示例:https://jsfiddle.net/k8L4xLLa/32/

想要更华丽的东西吗?

SVG 图像还允许您使用形状和垃圾做一些很酷的事情。看看这个可扩展文本的好用例......

https://jsfiddle.net/k8L4xLLa/14/

评论

0赞 isick 1/21/2023
要求您在 svg 中对文本位置进行编码(如果内容发生变化,该位置将发生变化),但如果内容不是动态的,则会产生很好的结果!谢谢!
-1赞 Smart Coder 7/28/2018 #28

我没有看到任何关于CSS flex属性的答案,但它也非常有用。

评论

8赞 Peter Mortensen 8/31/2019
你能详细说明一下吗?
0赞 Smart Coder 1/2/2023
你可以谷歌它的教程。
0赞 Justin 9/11/2018 #29

直接媒体查询似乎是一种更简单、更易于理解的解决方案,可以根据可能是动态的容器大小调整字体大小。

下面将字体大小调整为容器的大小,无论容器是否缩放到视口的大小,或者它是否已达到其最大值。如果您有非 100% 宽的容器,则可以相应地进行调整。vw

.container {
    width: 100%;
    max-width: 600px;
}
.headline {
    font-size: 20vw;
}
.subhead {
    font-size: 5vw;
}
@media (min-width:600px) {
    .headline {
        font-size: 120px;
    }
    .subhead {
        font-size: 32px;
    }
}
9赞 user993683 10/9/2018 #30

使用 CSS 变量

还没有人提到CSS变量,这种方法最适合我,所以:

假设您的页面上有一列,其宽度为移动用户屏幕宽度的 100%,但像素为 800 像素,因此在桌面上,该列的两侧都有一些空间。把它放在页面的顶部:max-width

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

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

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

这不是一种纯粹的CSS方法,但它非常接近。

评论

0赞 Mladen Mihajlovic 2/25/2021
如果您需要从 js 操作它,这实际上是一个很好的解决方案 - 谢谢!
0赞 BjornW 6/17/2021
这很酷,但我认为它不能响应式工作,setProperty 只会运行一次,对吧?
0赞 LuckyLuke Skywalker 4/16/2022
@BjornW 你可以简单地把它放在一个监听器里。例如,当页面调整大小时的侦听器。
-1赞 Crystal 11/3/2018 #31

但是,如果容器不是视口(正文)呢?

真正的答案在于 transform 属性允许您通过倾斜、旋转、平移或缩放来直观地操作元素:

https://css-tricks.com/almanac/properties/t/transform/

评论

3赞 Samuel Liew 11/3/2018
欢迎提供解决方案的链接,但请确保您的答案在没有它的情况下是有用的:在链接周围添加上下文,以便您的其他用户知道它是什么以及为什么它在那里,然后引用您链接到的页面中最相关的部分,以防目标页面不可用。只不过是链接的答案可能会被删除。
2赞 Ramil Gilfanov 8/21/2019 #32

let textElement = document.getElementById('text1');
let parentElement = textElement.parentElement;
const parentClientHeight = parentElement.clientHeight;
const parentClientWidth = parentElement.clientWidth;
textElement.style.padding = "unset";
textElement.style.margin = "auto";
let fontSize = parentClientHeight;
let minFS = 3,
  maxFS = fontSize;
while (fontSize != minFS) {
  textElement.style.fontSize = `${fontSize}px`;
  if (
    parentElement.scrollHeight <= parentClientHeight &&
    parentElement.scrollWidth <= parentClientWidth
  ) {
    minFS = fontSize;
  } else {
    maxFS = fontSize;
  }
  fontSize = Math.floor((minFS + maxFS) / 2);
}
textElement.style.fontSize = `${minFS}px`;
<div style="height:200px; width:300px;">
  <div id='text1'>
    test
  </div>
</div>

8赞 Redu 12/3/2019 #33

从艺术上讲,如果您需要在相同的宽度内容纳两行或多行文本,而不管它们的字符数如何,那么您有不错的选择。

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

让我们看看我们该如何接近。

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].clientWidthparseFloat(window.getComputedStyle(els[0],null).getPropertyValue("font-size"))

0赞 elixon 7/6/2020 #34

我刚刚创建了一个演示如何做到这一点。它用于通过一些监视元素调整大小的 JS 来实现这一点。很好地满足了我的需求。transform:scale()

1赞 Gokhan Kurt 9/16/2021 #35

在某种程度上,纯CSS是可能的。

.auto-sized-text {
    content:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='1.3em' width='10em'><text x='0' y='0.9em' fill='red'>Here is a resizing text</text></svg>");
    
    background-color: rgba(0,0,0,0.06);
    animation: grow 2s infinite alternate both;
}

@keyframes grow {
  from { width: 100px; }
  to { width: 300px; }
}
<div class="auto-sized-text">
</div>

解释

content 规则设置元素的内容,它可以是图像的 URL,包括 SVG 图像。SVG 图像可以包含文本,因此基本上您有一个背景图像,其中包含根据其父级大小调整大小的文本。您也可以使用属性,但与此不同的是,它对元素的布局没有贡献,因此您需要定义父元素的大小。background-imagecontent

这种方法的问题是,您需要定义 SVG 中文本的颜色、大小和位置。它们不会从父母那里继承。但是你可以用 Sass 和 Less 变得聪明。此解决方案还可能存在辅助功能问题。

我不建议到处使用它。但在某些情况下,它应该相当有用。

-1赞 Shahriar 1/2/2022 #36

这又如何呢?
将父级的字体大小设置为等于其宽度,然后对文本元素字体大小使用百分比。

.element {
    width: 400px;
    font-size: 400px; /* equal to width */
}

.text {
    width: 10%;  /* will be 40px */
}

我发现这真的很容易,特别是当你处理图标时,但也适用于文本。

/* start of styling */

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.box {
  display: block;
  background: cornflowerblue;
  height: max-content;
  margin-bottom: 32px;
}


/* end of styling */

.box p {
  font-size: 20%;
}
<div class="box" style="width: 400px; font-size: 400px">
  <p>Text</p>
</div>

<div class="box" style="width: 128px; font-size: 128px">
  <p>Text</p>
</div>


<div class="box" style="width: 10vw; font-size: 10vw">
  <p>Text</p>
</div>

<div class="box" style="width: 64px; font-size: 64px">
  <p>Text</p>
</div>

3赞 CSSBurner 3/1/2022 #37

这是一个纯 CSS 解决方案,您承认断点是必要的,但也希望文本缩放:

我知道我可以添加断点,但我真的希望文本缩放 以及有额外的断点,否则......

下面是一种使用的方法:

  1. 自定义属性
  2. 断点的媒体查询
  3. clamp()(2022 年 2 月的浏览器支持率相当不错,达到 93%)
  4. calc()

如果可以使用一个通用的缩放因子来控制每个屏幕容器内的所有文本缩放,那么您需要做的就是按 缩放自定义属性,并将此因子应用于 1 个计算max-widthmax-width

基本设置是这样开始的:

:root {
  --scaling-factor: 1
}

.parent {
  font-size: 30px
}

.largest {
  font-size: clamp(60%, calc(var(--scaling-factor) * 100%), 100%); 
}

.middle {
  font-size: clamp(60%, calc(var(--scaling-factor) * 85%), 100%); 
}

.smallest {
  font-size: clamp(60%, calc(var(--scaling-factor) * 70%), 100%); 
}

然后嵌套你的媒体查询,像这样的东西(或你需要的断点的任何内容):

@media (max-width: 1200px) {
  :root {
    --scaling-factor: 0.9
  }
  @media (max-width: 800px) {
    :root {
      --scaling-factor: 0.8
    }
    @media (max-width: 600px) {
      :root {
        --scaling-factor: 0.5 /* nope, because the font-size is floored at 60% thanks to clamp() */
      }
    }
  }
}

这样可以最大程度地减少媒体查询标记。

优势

  1. 一个自定义属性控制所有缩放...无需为每个媒体断点添加多个声明
  2. 使用 of 设置了应该是什么的下限,因此您可以确保文本永远不会太小(此处的下限是父级的 60%clamp()font-sizefont-size)

请参阅此 JSFiddle 的演示。调整窗口大小,直到以最小的宽度,段落都相同。font-size

1赞 EliuX 7/13/2022 #38

如果要将其放入特定容器(如 div)中,请使用:

width: max-content;

调整也有很大帮助,例如.font-sizefont-size: 75%

0赞 Stan 8/21/2022 #39

您可以插入窗口宽度的字体大小:

font-size: calc(
      ${minFontSizeInPixel} *
        (
          1px -
            clamp(
              0px,
              (100vw - ${minWindowWidth}px) /
                (${maxWindowWidth} - ${minWindowWidth}),
              1px
            )
        ) + ${maxFontSizeInPixel} *
        clamp(
          0px,
          (100vw - ${minWindowWidth}px) /
            (${maxWindowWidth} - ${minWindowWidth}),
          1px
        )
    );
0赞 Kyle Baker 9/23/2022 #40

我想喜欢公认的答案,但从根本上说,符合我标准的答案都使用了库。我没有熟悉另一个库,然后弄清楚如何使用它并准备调试它,如果它不起作用,我决定编写一个对我来说非常有效的简单函数。

理论:

  • 传入需要适合的字符串
  • 传入要从中继承文本样式的父级
  • (可选)传入自定义属性(例如,您将从中继承字体和其他属性的类/ID,或者仅传递自定义内联样式)
  • 函数将在屏幕外创建一个文本元素,其中包含该文本、该父项和这些属性,字体大小为 1px,并对其进行测量
  • 然后,在一个循环中,它将逐个像素地增加字体大小,直到超过宽度限制;一旦完成此操作,它将返回最后一个适合的
  • 然后,它删除测试元素
  • 当然,这一切都发生在眨眼之间

局限性:

  • 我不在乎动态调整屏幕大小,因为这与我的上下文无关。在生成文本时,我只关心运行时的屏幕大小。
  • 我依赖于一个小的辅助函数,我也在代码的其他地方使用,它基本上作为 mithril.js 的单函数版本存在;老实说,我几乎在每个项目中都使用这个小函数,它本身就值得学习。
  function findMaxFontSize(
    string="a string", 
    parent=document.body, 
    attributes={id:'font-size-finder',class:'some-class-with-font'}
  ) {
    // by using parent, we can infer the same font inheritance;
    // you can also manually specify fonts or relevant classes/id with attributes if preferred/needed
    attributes.style = 'position:absolute; left:-10000; font-size:1px;' + (attributes.style || "");
    let testFontEl = createEl('p', attributes, string);
    parent.appendChild(testFontEl);
    let currentWidth = testFontEl.offsetWidth;
    let workingFontSize = 1;
    let i = 0;
    while (currentWidth < maxWidth && i < 1000) {
      testFontEl.style.fontSize = Number(testFontEl.style.fontSize.split("px")[0]) + 1 + "px";
      currentWidth = testFontEl.offsetWidth;
      if (currentWidth < maxWidth) {
        workingFontSize = testFontEl.style.fontSize;
      }
      i++; // safety to prevent infinite loops
    }
    console.log("determined maximum font size:",workingFontSize,'one larger would produce',currentWidth,'max width allowed is',maxWidth,'parent is',parent);
    parent.removeChild(testFontEl);
    return workingFontSize.split("px")[0];
  }
// utility function, though you could easily modify the function above to work without this.
  // normally these have no default values specified, but adding them here
  // to make usage clearer.
  function createEl(tag="div", attrs={class:'some-class'}, children=[]) {
    let el = document.createElement(tag);
    if (attrs) {
      Object.keys(attrs).forEach(attr => {
        el.setAttribute(attr, attrs[attr])
      })
    }
    if (children) {
      children = Array.isArray(children) ? children : [children];
      for (let child of children) {
        if (typeof child === "number") child = ""+child;
        if (typeof child === "string") {
          el.insertAdjacentText("afterbegin", child);
        }
        else {
          try {
            el.appendChild(child)
          } catch (e) {
            debugger
          }
        }
      }
    }
    return el;
  };

用:

    const getUsername = () => "MrHarry";
    const username = getUsername();
    const anchor = document.querySelector('.container');
    const titleFontSize = findMaxFontSize(`Welcome, ${username}`, anchor, {style:'font-weight:900;'});
    const titleFontStyle = `font-size:${titleFontSize}px;`;  
129赞 Janosh 1/2/2023 #41

CSS 容器查询

2022 年末对 CSS 功能集的添加使使用容器缩放字体大小变得简单明了。

容器查询带有一组新的 CSS 单元 / (container query width/height)。要使用它们,您需要在要使用其大小的父元素上设置属性(不必是直接父元素)。最小示例:cqwcqhcontainer-type

<div>
  <p>Lorem ipsum dolor sit amet</p>
</div>

<style>
  div {
    container-type: inline-size;
  }
  p {
    font-size: 5cqw;
  }
</style>

字体大小将随着容器的增长而平滑增加。在 1000px 容器宽度时,字体大小将为 .p1000px / 100 * 5 = 50px

container-type可以是 或 . 跟踪容器的高度和宽度,允许您同时使用 和 。 在网络上,大多数时候,高度是根据内容计算的,您只需指定宽度。为了节省浏览器的一些工作,您通常希望设置浏览器仅跟踪内联尺寸,该尺寸通常是宽度(除非您将书写模式设置为垂直)。sizeinline-sizesizecqwcqhcontainer-type: inline-size;

浏览器对容器查询的支持正在迅速增长:

  • 2023-01-01: 75%
  • 2023-04-03: 83%
  • 2023-11-24: 90%

评论

5赞 oelna 1/6/2023
虽然不是一个详尽的答案,但这值得在 2022+ 年获得更多的赞成票
5赞 Joshua Robison 1/28/2023
这就是答案。我们如何标记此问题以引起注意。我差点错过了这个,因为这没有被标记为答案。
5赞 Christian 2/1/2023
这种方法和大多数其他方法的问题在于,当文本发生更改时,需要调整值。这意味着 5cqw(或 vw 或其他)在第一次设置时取决于文本,当文本是可变的或本地化的时,这是一个很大的不行。