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 Viewbox
es 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 div
s 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>
<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