Click here to Skip to main content
15,867,453 members
Articles / Web Development / Vue.js

Dynamically Resize Text to Fit in a div

Rate me:
Please Sign up or sign in to vote.
2.39/5 (8 votes)
25 Jun 2018CPOL2 min read 31K   161   6   3
WPF Viewbox style resizing of dynamic content to fit within the borders of a div.
In this article, you will see a demo of how to dynamically resize text contents of a div to make it fit within its boundaries.

Introduction

This is a simple demo of how to dynamically resize text contents of a div so they fit within its boundaries. It uses HTML/Javascript/CSS, and optionally uses Vue for binding.

Background

We are migrating a line-of-business app from UWP to HTML5. In UWP and WPF, there is a control called the Viewbox which very conveniently resizes its contents to fit. Due to the large amount of variably-sized information displayed in this app, it uses Viewboxes extensively. We couldn't replicate it in HTML5 without finding a way to replicate Viewbox functionality for text.

We found a lot of examples on resizing images to fit a div and on resizing divs so that their content fits, but we could not find an example of dynamically resizing text to fit inside a given div. Here's our approach to the problem.

EDIT: A commenter suggested using a CSS rule of 'font-size: .5vw'. This works great for static content or content that is dynamic server-side. In our case, we're updating the DOM directly with JavaScript. That CSS rule doesn't change the text size in response to dynamic client-side changes to the content.

Using the Code

For simplicity, we consolidated the solution into a single HTML file. Because we're using Vue in this project, one of the demos also shows how to use this approach with that framework. It should be pretty easy to adapt to any popular framework.

HTML
<html>
<head>
<style>
.resizable {
    border: 1px gray solid;
    width: 50%;
    height: 10%;
    background-color: aliceblue;
    text-align: center;
    align-items: center;
    justify-content: center;
    display: flex;
    font-family: sans-serif;
}
</style>
</head>

<body onresize="resizeContents()" onload="resizeContents()">
<h1>Dynamic Font Resize Demos</h1>

<h2>Demo 1: Set the content then resize it</h2>

Input:

<input id='demoInput1' onkeyup="demo1()" />
<br /> Output:
<div id='demoDiv1' class='resizable' style='height: 10%;'>

Please Enter Input
</div>

<h2>Demo 2: Resizing with Vue</h2>

Input:
<input id='demoInput2' onkeyup="demo2()" />
<br /> Output:
<div id='demoDiv2' class='resizable'>
{{ content }}
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
function demo1() {
    var div = document.getElementById('demoDiv1');
    var input = document.getElementById('demoInput1');
    
    div.innerText = input.value;

    resizeContents();
}

var demoVue2 = new Vue({
    el: '#demoDiv2',
    data: {
        content: "Please Enter Input"
    },
    updated: function () { resizeContents(); }
})

function demo2() {
    var input = document.getElementById('demoInput2');

    demoVue2.content = input.value;
}

function resizeContents() {
    var resizableDivs = document.getElementsByClassName('resizable');
    for (index = 0; index < resizableDivs.length; ++index) {
        var div = resizableDivs[index];
        if (div.innerText != '') {
            var divWidth = div.clientWidth;
            var divHeight = div.clientHeight;

            var contentWidth = div.scrollWidth;
            var contentHeight = div.scrollHeight;

            var fontSize = div.style.fontSize;
            fontSize = Number(fontSize.substring(0, fontSize.length - 2));

            while (contentWidth <= divWidth && contentHeight <= divHeight) {
                fontSize += 1;
                div.style.fontSize = fontSize + 'px';
                contentWidth = div.scrollWidth;
                contentHeight = div.scrollHeight;
            }

             while (contentWidth > divWidth || contentHeight > divHeight) {
                 fontSize -= 1;
                 div.style.fontSize = fontSize + 'px';

                 contentWidth = div.scrollWidth;
                 contentHeight = div.scrollHeight;
             }
        }
    }
}

</script>
</body>
</html

Points of Interest

This approach is superior to Viewbox in at least one respect: unlike Viewbox, the browser automatically takes care of text wrapping. You can resize the window, add or remove text, etc. and the text wrapping will ensure that the div is constantly filled to capacity.

We've only found a couple of flaws with this solution:

  • The character 'f' kerns such that it can intersect with the border of the div. Meh.
  • The vertical centering relies on CSS Flexbox which isn't supported in older browsers.

Thanks to the whole community for the help over the years! Hopefully, this article pays that forward in some small way.

Happy coding!

History

  • 16th June, 2018: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseGood job Pin
Yashar Mortazavi27-Jul-19 15:55
Yashar Mortazavi27-Jul-19 15:55 
GeneralMy vote of 1 Pin
Member 1370058918-Jun-18 9:04
Member 1370058918-Jun-18 9:04 
GeneralRe: My vote of 1 Pin
Member 1387522624-Jun-18 15:29
Member 1387522624-Jun-18 15:29 
Your CSS idea works great for static content. But the font size doesn't adjust as the text is dynamically changed.

Thanks!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.