I need to measure the pixel length of individual words (strings) in a container. I am shrinking each div's width so when the text wraps it is perfectly flush against its container, as there is a max-width that causes it to wrap. This solution (and its use case) have previously been answered in Jquery on this answer:
Shrink DIV to text that's wrapped to its max-width?
However, the above solution places each word in a span and uses Jquery's .width() method to calculate its physical size. As I am using React, I do not have this option.
While I have been successful in using the offsetWidth method to find the width of an item that has been rendered to the DOM, I have not found other viable solutions that don't involve rendering the item to the dom I can use to find the width of a single world.
Some solutions I have found online provide methods that factor in the font, but the font could change, so I need a method more like Jquery's .width().
Does React/JavaScript (not Jquery) have any means of determining the physical length of a word in pixels without having to render the item to the dom and without putting the font type into a function?
You can use measureText of canvas like below:
function getTextWidth(text, font) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = font || getComputedStyle(document.body).font;
return context.measureText(text).width;
}
You can just pass the font if you need to change it, it's basically a CSS font declaration.
function getTextWidth(text, font) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = font || getComputedStyle(document.body).font;
return context.measureText(text).width;
}
const elements = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
elements.forEach(element => {
const { font } = getComputedStyle(element);
element.insertAdjacentHTML('afterend', `
<p class="text-details sans-serif">
<span class="computed-font">${font}</span>
<span class="computed-width">${getTextWidth(element.innerText, font)}</span>
</p>
`);
});
h1, h2, h3, h4, h5, h6 {
font-family: serif;
margin: 0;
}
.sans-serif {
font-family: sans-serif;
}
.text-details {
font-size: 12px;
margin: 0 0 20px;
}
<h1>Hello, World</h1>
<h2>Hello, World</h2>
<h3>Hello, World</h3>
<h4>Hello, World</h4>
<h5>Hello, World</h5>
<h6>Hello, World</h6>
<h1 class="sans-serif">Hello, World</h1>
<h2 class="sans-serif">Hello, World</h2>
<h3 class="sans-serif">Hello, World</h3>
<h4 class="sans-serif">Hello, World</h4>
<h5 class="sans-serif">Hello, World</h5>
<h6 class="sans-serif">Hello, World</h6>
Please try the following solution.
var getWidthOfText = function(text, styles) {
var isObjectJSON = function(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj);
};
var element = document.createElement('div');
if (isObjectJSON(styles)) {
var styleKeys = Object.keys(styles);
for (var i = 0, n = styleKeys.length; i < n; ++i) {
element.style[styleKeys[i]] = styles[styleKeys[i]];
}
}
element.style.display = 'inline-block';
element.innerHTML = text;
document.body.appendChild(element);
var width = element.offsetWidth;
document.body.removeChild(element);
return width;
};
You need to pass the first argument as the text/HTML for which you want to check the width and second argument if you want to append any styles to the outer layer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With