基于容器大小的字体缩放

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个回答

4

3
尝试使用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' });

3
这是一个纯CSS解决方案,理解您需要断点但同时需要文本缩放的要求:

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

这里提供一种方法:
  1. 自定义属性
  2. 媒体查询用于断点
  3. clamp()(2022年2月浏览器支持率高达93%)
  4. calc()
如果在每个屏幕max-width内使用一种常见的缩放因子来控制容器中所有文本的缩放,则只需针对每个max-width缩放自定义属性,然后将此因子应用于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() */
      }
    }
  }
}

这样可以减少你的媒体查询标记。

优点

  1. 一个自定义属性控制所有缩放,无需在每个媒体断点上添加多个声明。
  2. 使用clamp()设置了font-size应该是多少,从而确保您的文本永远不会太小(这里的底部是父元素font-size的60%)。

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


2
这对我有用:
我尝试根据从设置 "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 元素或者比其父元素小的元素,否则如果子元素和父元素都具有相同的宽度/高度,函数将会失败。


2

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>


2

始终在此属性中包含您的元素:

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

或者

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

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

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

它只需少量代码即可很好地运行。

2

请看一下我的代码。它使得字体大小变小以适应所在位置。

但是我认为这样做不会对用户产生好的体验。

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

如果有帮助的话,本主题中大部分解决方案都是将文本换行成多行,例如:

但是我找到了这个方法,它起作用了:

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

使用示例:

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


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

1

使用纯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 rule设置元素的内容,可以是图像的URL,包括SVG图像。 SVG图像可以包含文本,因此您可以获得带有文本的背景图像,其大小根据其父级的大小调整。 您还可以使用background-image属性,但与content不同,它不会影响元素的布局,因此您需要定义父级的大小。

这种方法的问题在于,您需要定义SVG内部文本的颜色、大小和位置。 它们不会从父级继承。 但是您可以使用Sass和Less进行巧妙处理。 这种解决方案也可能存在可访问性问题。

我不建议在所有地方都使用它。 但在某些情况下应该非常有用。


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