4

I have a 100vh flex container, direction column.

Below it I have a dynamic number of flex items with the same height. This flex items altogether take all vertical space:

<div>
  <ul class="container">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
</div>

and css:

ul {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
li {
  flex: 1 1 auto;
}

The items contain text. And I want to fit the text to the height of the item. So I use js, with viewport units to calculate the right font size:

var lis = document.querySelectorAll('li');
var fontsize = (100 / lis.length) * 0.8;
document.querySelector('.container').style.fontSize = fontsize + "vh";

Here is the full working fiddle I just described.

My problem is that if a flex item contains text enough that it wraps onto one or more new lines, the approach does not work anymore.

<div>
  <ul class="container">
   <li>1</li>
   <li>2</li>
   <li>multiline becomes a problem with this approach</li>
  </ul>
</div>

Here is the demonstration of the problem.

To calculate font-size for a multi line item, I need to know how many lines it occupies, but that in itself depends on font-size. So it is a problem that eats its own tail.

My approach

A possible approach I can think of would be the following:

1 Detect number of li's
2 Trigger font-size calculation as seen above and apply
3 Calculate if any lis text will wrap onto new lines and how many (how?)
  3.a. If no texts wrap into new lines stop here.
  3.b. If there is text that wraps into new lines 
    3.b.1. Sum number of li's + all new lines on all multiline li's
    3.b.2. Re-trigger font-size calculation with this number and apply
    3.b.3. Calculate again if any li's text will wrap onto how many new lines, and compare with before font-size change.
      3.b.4.a. If there are the same number of new lines, stop here.
      3.b.4.b. If there are more new lines, repeat from step 3.b.1

But this approach seems dirty, and can lead to many steps of font size calculation and adjustment. Plus I am not sure how could I perform step 3.

So, how to approach this problem?

This question has been flagged as possible duplicate of this other question. But that question specifically asks for fitting the text into one line, which is a very different matter.

That said I could be taking some hints out of some of the answers, as they attempt to guess if a text overflows a div. In particular I am curious about this answer as @Hoffmann specifically says to attempt to avoid the loop problem I mention in my approach. I'll attempt to understand the code of his plugin, now maintained by someone else here: https://github.com/BrOrlandi/big-text.js/blob/master/big-text.js

Thank you

isherwood
  • 58,414
  • 16
  • 114
  • 157
Jaume Mal
  • 546
  • 5
  • 21
  • 1
    Please provide an [mcve] – zer00ne Mar 16 '19 at 16:58
  • One lazy-ish option would be to perform binary search for the font size. – Etheryte Mar 16 '19 at 20:33
  • @Nit could you please expand your suggestion ? – Jaume Mal Mar 16 '19 at 20:35
  • Do you need all text to be the same size, or all the same row than text should fit based on number of line into the row ? Also "number of line" can be a problem because updating text size will update the number of line. – Arthur Mar 16 '19 at 21:11
  • @Arthur I need all text across al flex items to be the same size. On font size to rule them all. And yes, updating font size may create more new lines on multi line flex items. That is one of the problems I describe in my approach. Thanks – Jaume Mal Mar 16 '19 at 21:42
  • Possible duplicate of [JavaScript Scale Text to Fit in Fixed Div](https://stackoverflow.com/questions/4165836/javascript-scale-text-to-fit-in-fixed-div) – Etheryte Mar 16 '19 at 22:28

1 Answers1

0

Using a monospaced font, intrinsic units (vh only not vw), justify-content: spaced evenly, line-height are major factors used in demo.


/* Reset */
* {
  margin: 0;
  padding: 0;
}
/* 
- Serif and Sans Serif fonts vary greatly, monospaced   
  fonts are a lot easier to use. 
- Assign the primary font on :root so if an explicit font-
  size is set elsewhere rem units reference font-size on 
  :root directly. 
- The font shorthand is as follows:
    font: font-weight, font-size/line-height, font-family
  line-height set at 10vh fits 100vh high <ul> well.
*/
:root {
  font: 400 6vh/10vh Consolas;
}
html, body {
  width: 100%;
  height: 100%;
}
body {
  overflow-x: hidden;
  overflow-y: scroll;
  margin: 5vh 15vh 0 10vh;
}
/*
Assign max-height: 100vh to the element containing the <ul>
*/
main {
  width: 96%;
  max-height: 100vh;
}
/* 
justify-content: space-evenly is exactly what it says 
*/
ul {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  height: 100vh;
}
li {
  flex: 1 1 auto;
}
<main>
  <ul>
    <li>One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.</li>
    <li>He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.</li>
    <li>The bedding was hardly able to cover it and seemed ready to slide off any moment.</li> 
    <li>His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.</li>
    <li>"What's happened to me?" he thought. It wasn't a dream.</li>
  </ul>
</main>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • Thanks . Correct me if I am wrong, but this would not adapt if the number of li's change, is that correct? I am specifically asking for a solution for any dynamic number of li's. – Jaume Mal Mar 17 '19 at 14:44