1

I have an h1 element that changes its HTML dynamically and I want it to auto shrink itself for longer text but return to its fixed font size for shorter text.

Here is the markup:

   <div class="frame" dir="ltr">
      <div class="frame-view">
        <h1> //dynamic text </h1>
      </div>
    </div>

and the styling:

.frame {
  z-index: 2;
  position: relative;
  top: 100px;
}
.frame-view {
  text-align: center;
}

.frame-view h1 {
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-style: normal;
  font-variant: normal;
  font-weight: 200;
  font-size: 40px;
  color: white;
  padding: 0 20px;
}

Here's what the h1 looks like when a long text is in it, on a mobile screen:

enter image description here

rather than staying within the 20px left, right padding and just auto shrinking the text, it stretches past the HTML.

in landscape it looks fine of course because there is enough room to contain it:

enter image description here

So how do I make this h1 auto shrink for longer text and stay within the boundaries ?

UPDATE

to further understand what I am trying to achieve, think of it like this:

I want the container of the h1 to be static and the text adjust its size when it gets closer to the container edges. Imagine a Label being 50 px, now if you put the word "hello" in that label at 20px font size, it would be 20px font size with no problem.. but if you put the words "Hello how are you" it wouldnt fit within the boundaries at 20px font size so it would have to auto shrink itself to stay within the boundaries of the container.

John Jackson
  • 900
  • 2
  • 12
  • 28
  • There is http://fittextjs.com/ which scales text automatically in responsive surroundings/changing widths quite well. I haven't tried if it it also works the way you need it, but you might give it a try. – Johannes Mar 27 '16 at 00:00

2 Answers2

2

The easiest way to go about this is to use vw. vw is short for "viewport width". You would go about it kind of like this:

h1 {
font-size: 4vw;
}

In other words, one letter of your <h1> takes up 4% of the width of the screen, since 1vw = 1% of the screen's width.

You will need to play around with it and figure out what number you need to use to make it work for you. If you find that you simply cannot achieve your goal with vw, you may also try CSS3 calc() (see an example here: http://codepen.io/CrocoDillon/pen/fBJxu).

Warning #1:

There is a word of caution, however. Depending on how your elements are set up, it is possible that this will cause some undesirable side effects, since vw bases the size off of the screen's width, not the element (if any) that contains the <h1>.

Warning #2:

Not all browsers have adopted support for vw yet. Make sure to put a fallback (font-size:24px etc.), just in case.

  • but vw almost sets a static font size in a sense, because short text will be the same size and long text. I want the word "Hello" to appear larger because its rightly within the boundaries, however the word "SUBDERMATOGLYPHIC" to shrink but stay within the boundaries if that makes sense – John Jackson Mar 26 '16 at 23:08
  • Unfortunately, to my knowledge you cannot do that with CSS alone. You will need some kind of Javascript to accomplish that. –  Mar 26 '16 at 23:16
1

you should start with a given text width in pixels, then measure the width of the given text using the measuretext function. If width is approaching the width of your container, then shrink the font size and remeasure. You should obviously have a limit on how small the text can go before it becomes illegible. Once text gets too small, you have to truncate and add dots onto the end.

Here is a sample that shows roughly how to do it. You need javascript, and I have included jquery to make it easier. As you add more text, and the text starts getting near the edge of the box, the fontsize will shrink, down to a minimum of 10 pixels. After that text that is too long will be truncated.

You could also make the text grow again if it got shorter using similar functions but in reverse.. growing the font size till it just overflowed, then back one step. However I have not included code for that.

<!DOCTYPE html>
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</head>

<body>
  <br>Enter your text:
  <p></p>
  <input type=text id=input_id style='width: 300px'></input>
  <p></p>
  <canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.</canvas>
  <script>
    var txt = "Hello World more"
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");

    var fontsize = 30
     ctx.font = fontsize.toString() + "px Arial";
     // ctx.fillText("width:" + ctx.measureText(txt).width, 10, 50);
     // ctx.fillText(txt, 10, 100);

    $('#input_id').val(txt)
     ObserveInputValue('')
     ObserveInputValue(txt)

     // a bit crude but simple and it works: watch the input object every tenth sec
     setInterval(function() {
      ObserveInputValue($('#input_id').val());
    }, 100);

    function ObserveInputValue(iv) {
      if (iv != txt) {
        console.log('input value changed to: ' + iv)
        txt = iv
        ctx.clearRect(0, 0, 300, 150)

        textwid = ctx.measureText(txt).width.toFixed(0)

        // adjust font size so that text just fits
        var maxfont = 50
        var minfont = 10
        while (textwid > 290 && fontsize > minfont) {
          sizedecrease = Math.max(1, fontsize * 0.1).toFixed(0) // decrease by 10% or 1 pixel whichever is greater
          fontsize -= sizedecrease
          ctx.font = fontsize.toString() + "px Arial";

          textwid = ctx.measureText(txt).width.toFixed(0)
        }
        // if text at min and still too long truncate text
        while (textwid > 290 && fontsize <= minfont) {
          // chop off last characters of text
          txt = txt.substring(0, txt.length - 1)
          textwid = ctx.measureText(txt).width.toFixed(0)

          $('#input_id').val(txt)
        }

        // exercise to the reader.. increase font size again if user makes text shorter

        ctx.fillText("width:" + textwid, 10, 50);
        ctx.fillText("font:" + fontsize, 10, 100);
        ctx.fillText(txt, 10, 150);

      }
    }
  </script>


</body>

</html>
Paulus
  • 1,385
  • 16
  • 20
  • yes everything in your answer is what i am trying to accomplish. But can you actually show your code in a JSFiddle example? where i can see the text truncate and shrink as it approaches the containers edge? – John Jackson Mar 28 '16 at 17:11
  • 1
    I Have updated the snippet to show the measuring of the text and making the text smaller – Paulus Mar 30 '16 at 05:42