当文本超出容器大小时,如何将字体按比例缩放?

7

如果文本适合容器,则我希望字体大小为54px,否则应该为36px。

我正在考虑是否可以使用纯CSS解决方案通过缩放函数来实现其中之一。如果假定容器是满的,我猜我可以使用vw作为计算基础?

但我非常困在这里。有人能给我一些提示吗,如何实现这个或者接近它。


您可以检查哪个屏幕分辨率容器文本超出,并使用媒体查询更改以下分辨率的字体大小。 - Guruling Kumbhar
6个回答

3

这个回答并不完全符合我的需求,所以我提供了一个解决方案:如果文本超出父容器的大小,可以通过缩小文本的大小来使其适应容器。

for(const element of document.getElementsByClassName("shrink"))
{
        var size = parseInt(getComputedStyle(element).getPropertyValue('font-size'));
        const parent_width = parseInt(getComputedStyle(element.parentElement).getPropertyValue('width'))
        while(element.offsetWidth > parent_width)
        {
            element.style.fontSize = size + "px"
            size -= 1
        }
}
.container{
  border:1px dashed #ccc;
  display:flex;
  align-items:center;
  justify-content:center;
  width:200px;
  height:50px;
  margin:10px;
}
.shrink{
    white-space: nowrap;
    font-size:80px;
}
<div class="container"><span class="shrink">long text to shrink</span></div>
<div class="container"><span class="shrink">small text</span></div>


1
如果您想将一些文本放在容器内,并使其自适应填充该容器,则 CSS Tricks 上有一篇关于 将文本适配到容器大小 的文章,其中涵盖了您的选项。
您还可以使用 视口尺寸的排版,利用视口单位,例如:
- 1vw = 视口宽度的 1% - 1vh = 视口高度的 1% - 1vmin = 1vw1vh 中较小的那个 - 1vmax = 1vw1vh 中较大的那个
任何v*的一个单位都是视口轴的1%。其中“Viewport”==浏览器窗口大小==窗口对象。如果视口宽度为50厘米,则1vw == 0.5厘米。仅使用视口单位,例如font-size: 4vw;,当改变窗口宽度时,文本可能会显得太大或太小,并带来可访问性问题(因为未考虑用户首选项)。
最后,您可以使用clamp()实现Simplified Fluid Typography。Clamp需要三个值,一个最小值,一个最大值和一个中间的灵活单位,如果该值介于最小值和最大值之间,它将使用该单位。
如果您希望字体大小最小为36px,最大为54px,则可以像这样使用clamp()并根据您的喜好更改“灵活单位”。以下是在容器内部为<h1>元素设计流体排版的示例。

body {
  font-size: 1rem;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.container {
  border: .2rem solid #f06;
  padding: .5rem;
  height: 100%;
  width: auto;
}

.container h1 {
  font-size: 36px; /* fallback */
  font-size: clamp(36px, 10vw, 54px);
}
<body>
  <div class="container">
    <h1>Heading text</h1>
  </div>
</body>

浏览器对于clamp()的支持非常好,但您可能需要在其之前设置font-size声明以设置可接受的回退值。
总之,如果您需要为容器设置明确的widthheight,则可能需要根据文本所在的内容框的大小,结合视口单位、calc()clamp()使用媒体查询。

我很好奇,为什么这个答案被踩了?此外,这些信息中有没有任何对你完成任务有帮助的内容?@Luhmann - Tanner Dolby
1
在我看来,这似乎是这里唯一可行的CSS解决方案。 - TehSphinX

0

我认为没有使用 JavaScript 几乎不可能计算它。

以下是一个代码示例,展示了我如何在 jQuery 中实现它,或者您可以使用以下 jQuery 插件,但我以前从未测试过这个插件:FitText.js

for (let container of $('.text-container')){
    container = $(container);
    let textInner = $(container).find('.text-inner');

    console.log(container.width());
    console.log(textInner.width());

    if (container.width()<textInner.width()){
        textInner.addClass('fs-36');
        textInner.removeClass('fs-54');
    } else {
        textInner.addClass('fs-54');
        textInner.removeClass('fs-36');
    }
}
.text-container,
.text-container-before{
    position: relative;
    width: 250px;
    height: 60px;
    background: #333;
    color: #090;
    overflow: visible;
    margin: 20px 0;
}
.text-inner,
.text-before{
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    background: #0399;
    word-break: keep-all;
    white-space: nowrap;
}
.fs-54{
    font-size: 54px;
}
.fs-36{
    font-size: 36px;
}

/* just added because console window is hiding running code snipped */
.spacer{
    height: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<h1>before</h1>
<div class="text-container-before">
    <div class="text-before fs-54">a bit longer text</div>
</div>

<div class="text-container-before">
    <div class="text-before fs-54">shorter text</div>
</div>

<h1>after</h1>
<div class="text-container">
    <div class="text-inner fs-54">a bit longer text</div>
</div>

<div class="text-container">
    <div class="text-inner fs-54">shorter text</div>
</div>

<div class="spacer"></div>


-1

关于 CSS 解决方案我不确定,但是我的 JS 解决方案可以解决你的问题。

请参考下面的代码。类名 class-54class-36 将根据内容进行更改:

// creating node
function createNode(element) {
  return document.createElement(element);
}

// creating append
function append(parent, el) {
  return parent.appendChild(el);
}

var getPageTitle = document.getElementById("pageTitle"),
  textLengthWidth = 0;
const getPageTitleText = getPageTitle.textContent;
getPageTitle.innerHTML = "";
for (let index = 0; index < getPageTitleText.length; index++) {
  const span = createNode("span");
  span.innerHTML = getPageTitleText.charAt(index);
  append(getPageTitle, span);
  if (index == getPageTitleText.length - 1) {
    calcFontSize();
  }
}

function calcFontSize() {
  var listOfSpan = document.querySelectorAll("#pageTitle span");
  listOfSpan.forEach(element => {
    textLengthWidth += element.offsetWidth;
  });
  console.log("total DIV width: " + getPageTitle.offsetWidth);
  console.log("total Content width: " + textLengthWidth);
  getPageTitle.offsetWidth < textLengthWidth ? getPageTitle.classList.add("class-36") : getPageTitle.classList.add("class-54");
}
 * {
            padding: 0;
            margin: 0;
            font-size: 14px;
        }

        .title {
            display: block;
            width: 100vw;
        }

        h1, h1 span {
            font-size: 54px;
        }

        .class-54 span {
            font-size: 54px;
        }

        .class-36 span {
            font-size: 36px;
        }
    <div class="title">
        <h1 id="pageTitle">Hello World! Hello World!</h1>
    </div>


这个支持在 SO 窗口中直接使用吗? - LarryBud
无法使用。文本大小从未改变。内容宽度不准确。 - LarryBud
@LarryBud,请查看我的更新代码和这个jsfiddle https://jsfiddle.net/hardyrajput/h0n3tu5c/56/ - Hardik Solanki
仍然不起作用。当我改变窗口的大小时,类永远不会被应用。请参见屏幕录像:https://www.youtube.com/watch?v=4w7UTFVz3BE&feature=youtu.be - LarryBud

-1
尝试使用word-break: break-all;,我认为这将解决你的问题。

-3

试试这个

.thingy {
font-size:54px;
overflow-wrap: break-word;
}
<h1 class="thingy">Hel000000000000000000ooo</h1>


请说明为什么它有效。h1标签也不会因为单个单词而换行。 - Han

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