我很难理解字体缩放。

我目前有一个字体大小为100%的网站。但这是100%的吗?这似乎是在16个像素处计算出来的。

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

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

我的理由是,当你调整大小时,像我的菜单这样的东西会变得压扁,所以我需要减少.menuItem等元素相对于容器宽度的px字体大小。(例如,在大型桌面上的菜单中,22px的效果非常好。向下移动到平板电脑宽度,16px更合适。)

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


当前回答

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

.自动调整文本大小{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'>这里是调整大小的文本</text></svg>“);背景色:rgba(0,0,0,0.06);动画:成长2s无限交替两者;}@关键帧增长{来自{width:100px;}到{width:300px;}}<div class=“自动调整文本大小”></div>

解释

内容规则设置元素的内容,它可以是图像的URL,包括SVG图像。SVG图像可以包含文本,因此基本上您有一个带有文本的背景图像,该图像根据其父图像的大小调整大小。您也可以使用background image属性,但与内容不同,它不会影响元素的布局,因此您需要定义父元素的大小。

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

我不建议在任何地方使用。但它在某些情况下应该相当有用。

其他回答

这可能不太实用,但如果您希望字体是父级的直接函数,而不需要任何JavaScript侦听/循环(interval)来读取div/页面的大小,那么有一种方法可以做到。Iframes。

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

抛开视口单位不能与文本的父单位一起出现的限制(如中所示,具有与其他所有单位相同的%大小),视口单位确实提供了一个非常强大的工具:能够获得最小/最大尺寸。你不能在其他地方这样做-你不能说。。。使这个div的高度等于父对象的宽度。

也就是说,诀窍是使用vmin,并设置iframe大小,当高度是限制维度时,[fract]*总高度是一个好的字体大小,而当宽度是限制维度的时候,[fract]*总宽度。这就是为什么高度必须是宽度和纵横比的乘积。

对于我的特定示例

.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都是我自定义的点击拖动功能。

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

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

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像素的p元素。根据你的想法,它将变成一个300像素宽的容器,字体大小为4像素。必须有一个下限。

其他解决方案是媒体查询,这样您就可以为不同的宽度设置字体。

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

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

font-size: calc(
      ${minFontSizeInPixel} *
        (
          1px -
            clamp(
              0px,
              (100vw - ${minWindowWidth}px) /
                (${maxWindowWidth} - ${minWindowWidth}),
              1px
            )
        ) + ${maxFontSizeInPixel} *
        clamp(
          0px,
          (100vw - ${minWindowWidth}px) /
            (${maxWindowWidth} - ${minWindowWidth}),
          1px
        )
    );

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

所以我写了我自己的小插件,它减小了字体大小以适应容器,假设你有溢出:隐藏和空白: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);

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

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

以下是一种方法:

自定义财产媒体查询断点clamp()(2022年2月的浏览器支持率为93%)计算()

如果可以使用一个通用的缩放因子来控制每个屏幕最大宽度容器内的所有文本缩放,则只需按最大宽度缩放自定义属性,并将此因子应用于1计算。

基本设置如下所示:

: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() */
      }
    }
  }
}

这将最小化媒体查询标记。

优势

一个自定义属性控制所有缩放。。。无需为每个媒体断点添加多个声明使用clamp()设置了字体大小的下限,这样可以确保文本永远不会太小(这里的下限是父字体大小的60%)

请查看此JSFiddle演示。调整窗口大小,直到宽度最小,段落的字体大小都相同。