Click here to Skip to main content
14,976,321 members
Articles / Web Development / Vue.js
Article
Posted 16 Jun 2018

Stats

21.3K views
139 downloads
6 bookmarked

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
WPF Viewbox style resizing of dynamic content to fit within the borders of a div.

Introduction

This is a simple demo of how to dynamically resize text contents of a div so they fit within its boundaries. Uses HTML/Javascript/CSS. 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!

License

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

Share

About the Author

Member 13875226
United States United States
No Biography provided

Comments and Discussions

 
PraiseGood job Pin
Yashar Mortazavi27-Jul-19 15:55
MemberYashar Mortazavi27-Jul-19 15:55 
GeneralMy vote of 1 Pin
Member 1370058918-Jun-18 9:04
MemberMember 1370058918-Jun-18 9:04 
GeneralRe: My vote of 1 Pin
Member 1387522624-Jun-18 15:29
MemberMember 1387522624-Jun-18 15:29 

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.