Scale font to size when text exceeds container?

Viewed 997

I want font size to be 54px if the text fits inside the container, otherwise it should be 36px.

I was considering whether I can achieve this with a pure CSS solution, using the scale function to collapse to either of the two. If the container can be assumed to be full with, I guess I could use vw as a base for a calculation?

But I am very much stuck on this. Could anyone give me a hint, as to how I can achieve this or something close to it.

5 Answers

If you would like to put some text inside a container and have it size itself to fill that container, then CSS Tricks has an article on Fitting Text to a Container that will cover your options.

You could also use Viewport Sized Typography which take advantage of viewport units such as:

  • 1vw = 1% of viewport width
  • 1vh = 1% of viewport height
  • 1vmin = 1vw or 1vh, whichever is smaller
  • 1vmax = 1vw or 1vh, whichever is larger

One unit of any v* is 1% of the viewport axis. Where the “Viewport” == browser window size == window object. If the viewport is 50cm wide, 1vw == 0.5cm. Using viewport units alone such as font-size: 4vw; can make the text appear too big or too small when varying the window width and bring accessibility issues (as the user preferences are not taken into account).

Lastly, you could use clamp() to achieve Simplified Fluid Typography. Clamp takes three values, a min, max, and a flexible unit in the middle that it will use in case the value is between the min and max.

If you want the font size to be a minimum of 36px and maximum 54px, you could use clamp() like this and vary the "flexible unit" to your liking. Here is an example of fluid typography for an <h1> element inside a container.

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>

Browser support for clamp() is pretty good, but you’d probably want to put a font-size declaration before it to set an acceptable fallback value.

In conclusion, if you needed to set an explicit width and height for said container, you might want to use media queries along with viewport units, calc(), or clamp() depending on the size of the content box in which the text resides.

i think it's nearly impossible to calculate it without js.

below is an code example how i would do it in jquery or you could use the following jquery plugin, but i never tested this plugin before: 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>

Not, Sure about CSS solution. But, My JS solution can resolve your problem.

Refer below code. Class class-54 and class-36 will change based on content:

// 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>

try word-break: break-all;, I think this will solve your problem

Try this

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

Related