How can I change input blink caret style with easy css, js - css

I wonder how can I use css/javascript to adjust the blinking cursor inside the search box with CSS?
Is it possible to replace default blinkig caret to horizontal blinking icon

I don't think it is so hard. I made a quick example, which works in most modern browsers except Safari.
It draws the caret on a canvas, and sets it as a background of the input, on a position calculated from the browsers caret position.
It checks if the browser supports the caret-color css property, and if it doesn't it doesn't do anything, because both the system caret, and our caret will be visible in the same time. From the browsers I tested, only Safari doesn't support it.
$("input").on('change blur mouseup focus keydown keyup', function(evt) {
var $el = $(evt.target);
//check if the carret can be hidden
//AFAIK from the modern mainstream browsers
//only Safari doesn't support caret-color
if (!$el.css("caret-color")) return;
var caretIndex = $el[0].selectionStart;
var textBeforeCarret = $el.val().substring(0, caretIndex);
var bgr = getBackgroundStyle($el, textBeforeCarret);
$el.css("background", bgr);
clearInterval(window.blinkInterval);
//just an examplethis should be in a module scope, not on window level
window.blinkInterval = setInterval(blink, 600);
})
function blink() {
$("input").each((index, el) => {
var $el = $(el);
if ($el.css("background-blend-mode") != "normal") {
$el.css("background-blend-mode", "normal");
} else {
$el.css("background-blend-mode", "color-burn");
}
});
}
function getBackgroundStyle($el, text) {
var fontSize = $el.css("font-size");
var fontFamily = $el.css("font-family");
var font = fontSize + " " + fontFamily;
var canvas = $el.data("carretCanvas");
//cache the canvas for performance reasons
//it is a good idea to invalidate if the input size changes because of the browser text resize/zoom)
if (canvas == null) {
canvas = document.createElement("canvas");
$el.data("carretCanvas", canvas);
var ctx = canvas.getContext("2d");
ctx.font = font;
ctx.strokeStyle = $el.css("color");
ctx.lineWidth = Math.ceil(parseInt(fontSize) / 5);
ctx.beginPath();
ctx.moveTo(0, 0);
//aproximate width of the caret
ctx.lineTo(parseInt(fontSize) / 2, 0);
ctx.stroke();
}
var offsetLeft = canvas.getContext("2d").measureText(text).width + parseInt($el.css("padding-left"));
return "#fff url(" + canvas.toDataURL() + ") no-repeat " +
(offsetLeft - $el.scrollLeft()) + "px " +
($el.height() + parseInt($el.css("padding-top"))) + "px";
}
input {
caret-color: transparent;
padding: 3px;
font-size: 15px;
color: #2795EE;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
If there is interest, I can clean it a bit and wrap it in a jQuery plugin.
Edit: forgot about the blinking, so I added it. A better way will be to add it as css animation, in this case the caret should be in a separate html element positioned over the input.

Changing the color of the caret is supported by the latest standards. But not changing its width is not, which I think is a shame because it is a question of accessibility for vision-impaired people.
One approach for implementing such a change yourself is first trying to figure out what is the position the caret is blinking at, then overlaying it with an element that looks like the caret but is perhaps wider etc.
Here's an article on how to go about doing such a thing. It's a good article but the end-solution is kind of complicated as a whole. But see if it solves your problem:
https://medium.com/#jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
Here is perhaps a simpler explanation for how to find the care x-y position:
How do I get the (x, y) pixel coordinates of the caret in text boxes?

Related

Variable font weight on HTML canvas capped at 999?

I'm working on an variable type test for a project with a variable font i created.
The 'wght' axis contains a range of between 0-6600.
I had no problems animating the full range of values above as a DOM element with HTML and CSS.
But while trying out the same thing on HTML canvas, i realised the font weight resets itself to 0 once its passes 1000.
Is there a way to get around this? I tried looking into P5.js but the examples i found still manipulates DOM elements instead of using a canvas.
An excerpt of my code below, but i cant quite share the working demo with the font as the font is meant to be a proprietary font eventually.
#font-face {
font-family: 'TestFont';
src: url('/assets/TestFont_v2.ttf') format('truetype-variations');
font-weight: 0 6600;
}
<canvas id="canvas-text" width="1000" height="500"> </canvas>
/*** js***/
var c = document.getElementById('canvas-text');
var ctx = c.getContext('2d');
function drawCanvas() {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = 'white';
ctx.font = (scroll_percentage * 6600) + ' ' + '20px TestFont';
const string_ = 'Lorem ipsum';
ctx.fillText(string_, 20, 20);
}
let scroll_percentage = 0
function updateScrollProgress() {
// get percentage of total scroll
var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
scroll_percentage = winScroll / height;
// update canvas on scroll
drawCanvas()
}

Zooming createjs canvas prevents button click

When the canvas that contains a createjs is zoomed using a zoom style (e.g. zoom: 0.5) buttons on the canvas have a different click target that is either on only one side of the button or no target at all.
var stage, label;
function init() {
stage = new createjs.Stage("demoCanvas");
stage.name = "stage";
var background = new createjs.Shape();
background.name = "background";
background.graphics.beginFill("red").drawRoundRect(0, 0, 150, 60, 10);
label = new createjs.Text("foo", "bold 24px Arial", "#FFFFFF");
label.name = "label";
label.textAlign = "center";
label.textBaseline = "middle";
label.x = 150/2;
label.y = 60/2;
var button = new createjs.Container();
button.name = "button";
button.x = 75;
button.y = 40;
button.addChild(background, label);
stage.addChild(button);
// listeners
var targets = [stage,button,label,background];
for (var i=0; i<targets.length; i++) {
var target = targets[i];
target.on("click", toggleText, null, false, null, false);
}
stage.update();
}
function toggleText(evt) {
label.text = (label.text == 'foo') ? 'bar' : 'foo';
stage.update();
}
body{
margin: 0;
text-align: center;
}
#demoCanvas{
background: tan;
width: 500px;
height: 300px;
transform-origin: 0 0;
transform: scale(0.2); // Firefox = This does not cause problem with button clicking
zoom: 0.2; // Other browsers = This causes a problem with button clicking in Chrome
}
<html>
<head>
<script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>
</head>
<body onload="init();">
<canvas id="demoCanvas"></canvas>
</body>
</html>
Note that this will not fail in the SO snippet so I have also made this available as a Pen.
This behaviour presents itself in Chrome but not in Firefox (which recognises the transform: scale() style instead).
If the canvas needs to be scaled in the DOM how can this be done in Chrome without causing buttons to fail?
The zoom css style is considered non-standard so for Chrome and other Browsers you can use transform : scale() as well. I can confirm that zoom does break CreateJS - if you wanted to, you could add an issue to their EaselJS GitHub - not sure if it is worth fixing when transform : scale() can be used. Cheers.
CSS ZOOM: "Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future."

Scaling a canvas nicely with css

I'm trying to draw an image on a canvas, then use css to fit the canvas within a certain size. It turns out that many browsers don't scale the canvas down very nicely. Firefox on OS X seems to be one of the worst, but I haven't tested very many. Here is a minimal example of the problem:
HTML
<img>
<canvas></canvas>
CSS
img, canvas {
width: 125px;
}
JS
var image = document.getElementsByTagName('img')[0],
canvas = document.getElementsByTagName('canvas')[0];
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
Running in a codepen: http://codepen.io/ford/pen/GgMzJd
Here's the result in Firefox (screenshot from a retina display):
What's happening is that both the <img> and <canvas> start at the same size and are scaled down by the browser with css (the image width is 783px). Apparently, the browser does some nice smoothing/interpolation on the <img>, but not on the <canvas>.
I've tried:
image-rendering, but the defaults seem to already be what I want.
Hacky solutions like scaling the image down in steps, but this didn't help: http://codepen.io/ford/pen/emGxrd.
Context2D.imageSmoothingEnabled, but once again, the defaults describe what I want.
How can I make the image on the right look like the image on the left? Preferably in as little code as possible (I'd rather not implement bicubic interpolation myself, for example).
You can fix the pixelation issue by scaling the canvas's backing store by the window.devicePixelRatio value. Unfortunately, the shoddy image filtering seems to be a browser limitation at this time, and the only reliable fix is to roll your own.
Replace your current onload with:
image.onload = function() {
var dpr = window.devicePixelRatio;
canvas.width = image.width * dpr;
canvas.height = image.height * dpr;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
Results:
Tested on Firefox 35.0.1 on Windows 8.1. Note that your current code doesn't handle browser zoom events, which could reintroduce pixelation. You can fix this by handling the resize event.
Canvas is not quite meant to be css zoomed : Try over-sampling : use twice the required canvas size, and css scaling will do a fine job in down-scaling the canvas.
On hi-dpi devices you should double yet another time the resolution to reach the
same quality.
(even on a standard display, X4 shines a bit more).
(Image, canvas 1X, 2X and 4X)
var $ = document.getElementById.bind(document);
var image = $('fntimg');
image.onload = function() {
drawAllImages();
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
function drawAllImages() {
drawImage(1);
drawImage(2);
drawImage(4);
}
function drawImage(x) {
console.log('cv' + x + 'X');
var canvas = $('cv' + x + 'X');
canvas.width = x * image.width;
canvas.height = x * image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
img,
canvas {
width: 125px;
}
<br>
<img id='fntimg'>
<canvas id='cv1X'></canvas>
<canvas id='cv2X'></canvas>
<canvas id='cv4X'></canvas>
<br>
It's not good idea to scale canvas and think that you solved the image scale problem.you can pass your dynamic value to canvas,and then draw with that size whatever you want.
here is link of canvas doc: http://www.w3docs.com/learn-javascript/canvas.html
Simple answer, you can't do it. The canvas is just like a bitmap, nothing more.
My idea:
You should redraw the whole surface on zooming, and make sure you scale the image you're drawing to the canvas. As it is a vector graphic, this should work. But you're going to have to redraw the canvas for sure.

Is there a way to position page content UNDERNEATH or ON TOP OF a scrollbar?

I'm trying to emulate the CTRL+F functionality from Chrome that highlights matches on the page in the scrollbar, but for certain fields in a form. Using page offsets and percentages, I have blocks of color which correspond to the relative locations of those fields on the page.
In my prototype, the blocks of color sit to the left of the scrollbar. Ideally, they'd sit UNDERNEATH the scrollbar, and the scrollbar's track would be transparent so that it looks like they're part of the scrollbar track.
Can the default scrollbar be set to allow for overflow content to show underneath it (or allow page content to go over it)? I know this could be accomplished if I just rolled my own scroll, but I'd like to use the default ones provided by the browser if at all possible.
It's clearest if you just look at this Prototype.
CSS:
::-webkit-scrollbar {
width: 14px;
height: 18px;
background-color:transparent;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-track-piece {
background:none;
}
::-webkit-scrollbar-thumb {
height: 6px;
border: 4px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
-webkit-border-radius: 7px;
background-color: #333
}
::-webkit-scrollbar-button {
width: 0;
height: 0;
display: none;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
I thought of rendering the matches on the trackbar similarly to what browsers do today before. The idea is simple by using linear-gradient background for the ::-webkit-scrollbar-track. However I did not try implementing this. Right after reading your question, I've tried it and looks like it's not such easy.
You can use the linear-gradient background OK, but if you try rendering more than 1 match (a line), it sometimes can't be rendered (especially when the window's size is changed) and the line is not rendered smoothly. Such as this seems to be OK:
//render 2 lines, one is at 50px and the other is at 100px
background: linear-gradient(transparent 50px, red 50px, red 51px, transparent 51px,
transparent 100px, red 100px, red 101px, transparent 101px);
but it's not stable, as I said when you try resizing the window, at some size, some line won't be rendered (at least I tried on Opera). When the window's height is large, the line even becomes blurred (not sharp) and thicker. I don't really understand this, because the color stops are set fixedly (by px, not by %). This issue is even worse when the number of lines is larger. You have a linear-gradient with many corresponding color stops. That seems to be a neat way to solve the problem. Just because of the undesired issue, we can't use that approach.
The new approach: So I tried using multi-backgrounds feature instead. Each background just renders 1 line, the background-size is the same for all the background is just about 2px height and the background-position should be different. Here is the equivalent code (to the above clean code) using this approach:
background: linear-gradient(red, red), linear-gradient(red, red);
background-repeat: no-repeat;
background-size: 100% 2px;
background-position: 0 50px, 0 100px;
The new approach of course requires that the browser has to support multi-backgrounds features (looks like just IE8- do not support this cool feature).
So that's almost what you need to solve this problem. Now we need to find how to apply that style using script. We can't select a pseudo-element (or something like that) via script. We can just use the window.getComputedStyle() method to get the read-only style of a pseudo-element. However we always have a way to modify the CSS directly. That's is by using pure JS with the help of document.styleSheets and cssRules. They allow us to insert/remove/modify a rule.
That looks great. But there is still another issue. When changing the style using that method, the style is not applied right (at least it happens to the ::-webkit-scrollbar-track, it may not happen to other elements). Only when you move the mouse over the scrollbar, the new style is applied. I've just found a simple way to invalidate that scrollbar by setting the overflow of document.documentElement (the html) to hidden and set it back to auto. That works almost well.
Here is the code:
var requiredTb = $(".required input");
var invalids = requiredTb;
var offsets = [];
//init offsets to highlight on the trackbar later
requiredTb.each(function() {
offsets.push(($(this).offset().top)/document.body.scrollHeight * 100);
});
//find the rule styling the -webkit-scrollbar-track
//we added in the CSS stylesheet, this is done just 1 time
var sheets = document.styleSheets;
var trackRule;
for(var i = 0; i < sheets.length; i++){
var rules = sheets[i].cssRules || sheets[i].rules;
for(var j = 0; j < rules.length; j++){
var rule = rules[j];
if(rule.selectorText == "::-webkit-scrollbar-track:vertical"){
trackRule = rule; break;
}
}
}
//define an invalidate() method, we need to use this method
//to refresh the scrollbars, otherwise the newly applied style is not affected
window.invalidate = function(){
$(document.documentElement).css('overflow','hidden');
setTimeout(function(e){
$(document.documentElement).css('overflow','auto');
},1);
};
//this is the main function to set style for the scrollbar track.
function setTrackHighlights(positions, color){
positions.sort();//ensure that the input array should be ascendingly sorted.
trackRule.style.cssText = "";
var gradient = "background: ", backPos = "background-position: ";
var winHeight = $(window).height();
$.each(positions, function(i,pos){
gradient += "linear-gradient(" + color + ", " + color + "),";
backPos += "0 " + pos + "%,"
});
gradient = gradient.substr(0,gradient.length-1) + ";";
backPos = backPos.substr(0,backPos.length -1) + ";";
trackRule.style.cssText += gradient + backPos + "background-repeat:no-repeat; background-size:100% 2px";
invalidate();
}
//initially set the highlights on the trackbar
setTrackHighlights(offsets,'red');
//handle the oninput event to update the highlights accordingly
requiredTb.on('input', function(e){
var required = $(this).closest('.required');
var refreshHighlights = false;
if(this.value && !required.is('.ok')) {
required.addClass('ok');
refreshHighlights = true;
invalids = invalids.not(this);
}
if(!this.value && required.is('.ok')) {
required.removeClass('ok');
refreshHighlights = true;
invalids = invalids.add(this);
}
if(refreshHighlights){
offsets.splice(0);
invalids.each(function() {
offsets.push(($(this).offset().top)/document.body.scrollHeight * 100);
});
setTrackHighlights(offsets,'red');
}
});
You have to add an empty ::-webkit-scrollbar-track:vertical rule (we need to deal only with the vertical scrollbar) in the CSS code, it should be appended at the last to override any similar rule before. We can in fact use the insertRule() method (of a CSSRuleList which can be accessed via cssRules property) to add a new rule instead of looping through the styleSheets, and through the cssRules (of each sheet) to find the empty rule ::-webkit-scrollbar-track:vertical.
The code I posted here can be improved, such as you can add another method setTrackHighlights to allow to add more lines (instead of rendering all the lines each time we need to add/remove just 1 line)...
Note that by using the term line, I mean the rendering representation of a match on the trackbar.
Demo

Resize font depending on string length

I have a vertical menu and i want to make it localizable, but localized strings in menu elements often goes out off the edge.
So the question is how to make font resizable depending on the string length in CSS. And if possible, without JavaScript.
Thanks!
UPD: JQuery isn't acceptable. Any way in Pure JS?
You should make familiar with using plugins, they save you much time and of course they're very reliable (they are written by experienced scripters/programmers and have been tested by community). However looks like you want some pure JS solution. I've just made this code for you. It works fairly OK (although I'm not sure if it's as good as some plugins). The only requirement is the element (which you want to adjust the font-size accordingly to the text length) should contain plain text, not some HTML code.
The idea to implement it using pure JS is simple, you need some dummy element created using script, this dummy element is used to measure the size of the text. We need to adjust the font-size of the dummy element until the size of the text (as well as of the dummy element) should be confined to the size of the element (whose font-size you want to adjust). I made the code very clearly, hope you understand it better after reading the code:
//we just need 1 dummy element for the whole page.
var dummy = document.createElement('div');
dummy.className = 'dummy';
var inSingleLineMode, inMultilineMode;
//function used to adjust the font-size of the element
//so that the width is fixed (single-line mode) or both the width and height are
//fixed (multi-line mode), of course the text should be contained within
//the fixed width and height.
function adjustFontSize(element, singleLine){
if(!element.innerHTML) return;
var elementStyle = getComputedStyle(element);
dummy.style.font = elementStyle.font;
initMode(singleLine, function(){ dummy.style.width = elementStyle.width });
dummy.style.padding = elementStyle.padding;
dummy.style.boxSizing = elementStyle.boxSizing;
dummy.innerHTML = element.innerHTML;
document.body.appendChild(dummy);
var dummyStyle = getComputedStyle(dummy);
while(singleLine ? parseInt(dummyStyle.width) < parseInt(elementStyle.width) :
parseInt(dummyStyle.height) < parseInt(elementStyle.height)){
dummy.style.fontSize = parseFloat(dummyStyle.fontSize) + 1 + 'px';
dummyStyle = getComputedStyle(dummy);
}
while(singleLine ? parseInt(dummyStyle.width) > parseInt(elementStyle.width) :
parseInt(dummyStyle.height) > parseInt(elementStyle.height)){
dummy.style.fontSize = parseFloat(dummyStyle.fontSize) - 1 + 'px';
dummyStyle = getComputedStyle(dummy);
}
element.style.fontSize = dummyStyle.fontSize;
document.body.removeChild(dummy);
}
function initMode(singleLine, callback){
if(!dummy) return;
if(singleLine&&!inSingleLineMode) {
dummy.style.whiteSpace = 'nowrap';
dummy.style.width = 'auto';
dummy.style.display = "inline-block";
inSingleLineMode = true;
inMultiLineMode = false;
} else if(!singleLine&&!inMultilineMode) {
if(callback) callback();
dummy.style.whiteSpace = 'initial';
dummy.style.display = "block";
dummy.style.wordWrap = 'break-word';
inMultilineMode = true;
inSingleLineMode = false;
}
}
Demo.
In the demo, you can see that the first menu #menu1 is the Vietnamese word meaning Chrysanthemum while the second menu #menu2 is of course the English word Chrysanthemum. They have much different length, however both are supposed to have fixed width of 100px, hence the second menu #menu2 should have smaller font-size to fit the space.
You can use jQuery Text Fill like this.
Load up the plugin: <script src="jquery.textfill.js" ></script>
Put an id <input type="text" id="dyntext" value="e=mc²"></input>
Use the code to do magic. Preferably put this in <script> tags:
The end result will look something like this:
function update() {
var size = parseInt($('#maxsize').val(), 10);
if (!isNaN(size)) {
$('.dyntextval').html($('#dyntext').val());
$('.jtextfill').textfill({debug: true, maxFontPixels: size});
}
}
$(function () {
$('#maxsize').keyup(update);
$('#dyntext').keyup(update);
update()
});
This is not possible without Javascript. Using Javascript, you can use one of the many libraries, like FitText.
So you could use a Javascript library for this, but that would also mean that various labels have different font sizes.
I think the best approach would be to style the menu in such a way that it gracefully handles multi-line captions. That way, the length doesn't really matter much.
Because some language are 'longer' than others (for instance French labels are on avarage 1.5 to 2 times as long as English, it's a good idea to test your interface with one of those languages.
And for the font size, you could add a modifier on server side, for instace if you know the current language is French, you can add a class 'gui-captions-very-long' to the html tag and apply your CSS based on that class. That way, you can have a generic modifier which you can configure per language. I think that's a better solution than making all labels fit on a single line.
Keep in mind though, that smaller sizes are harder to read. You cannot just make the fonts half the size if the text is twice as long. You'll have to tune your design (or its implementation) to make longer texts possible.
I did look for that in the past then found an answer that really did the trick for me, but cannot remember were exactly... :(
But since it does answer the question using pure javascript and no plugins/libraries (did some optimisations since though), here it is! (with a working example):
// First we add a new function to the String prototype,
// this will be used to get the length of current string according
// to its font-family and font-size
String.prototype.textWidth = function(fontFamily, fontSize) {
var container = document.createElement('div');
container.style.visibility = 'hidden';
container.style.fontFamily = fontFamily;
container.style.fontSize = fontSize + 'px';
container.style.display = 'inline';
document.body.appendChild(container);
container.innerHTML = this;
var pxLength = container.offsetWidth;
container.parentNode.removeChild(container);
return pxLength;
};
// this is the function that will resize our text if it's too long
// classNameTarget (String) = the className of the element we need to resize e a
// tag or an id but you'll need to make modification to this function!
// maxWidth (int) = the max width (in px) of your final string
// fontFamily (String) = the family currently used by your string(wrong one might lead
// to wrong result!)
// fontSize (int) = the initial font-size of your string
var testWidth = function(classNameTarget, maxWidth, fontFamily, fontSize) {
maxWidth = maxWidth || 100;
// first we get all targets
var containers = document.getElementsByClassName(classNameTarget);
for (var i = 0; i < containers.length; i++) {
// for each of them we fetch their current length
var length = containers[i].innerHTML.textWidth(fontFamily, fontSize);
if (length > maxWidth){
// if the current length is bigger then we resize it by using a span styling with
// the new font-size
containers[i].innerHTML = "<span style=\"font-size:" + Math.floor(parseInt(fontSize) / (length / maxWidth)) + "px;\">" + containers[i].innerHTML + "</span>";
}
}
};
// we want our cell to have text no longer than 75px while having them starting at 50px
// font-size in arial
testWidth("firstname", 75, "arial", 50);
testWidth("lastname", 75, "arial", 50);
<table>
<thead>
<tr>
<th>firstname</th>
<th>lastname</th>
</tr>
</thead>
<tbody style="font-size: 50px; font-family: arial;">
<tr>
<td class="firstname">Bob</td>
<td class="lastname">Tomysonorubia</td>
</tr>
<tr>
<td class="firstname">John</td>
<td class="lastname">Doe</td>
</tr>
<tr>
<td class="firstname">François-Xavier</td>
<td class="lastname">De la nouvelle Orléan</td>
</tr>
</tbody>
</table>
the testWidth method might need some adjustements regarding your currents needs, perhaps you'ld like to look into querySelector or querySelectorAll to make it quite generic
I suggest an tiny example. On a pure JavaScript.
https://gist.github.com/dejurin/9bef02be6876e068ee276bee31cb3bcb
"use strict";
(function(w, d) {
var fit = d.getElementById("fit");
var wrap = d.getElementById("wrap");
fontFitResize(fit, wrap);
function fontFitResize(fit, wrap, step = 0.5) {
var currentSize;
while(fit.offsetWidth < wrap.offsetWidth) {
currentSize = parseFloat(w.getComputedStyle(wrap, null).getPropertyValue('font-size'));
wrap.style.fontSize = (currentSize - step) + 'px';
console.log(wrap.style.fontSize);
}
}
})(window, document);
.fit {
border: 1px solid #ff0000;
white-space:nowrap;
font-size:24px;
width:200px;
}
<div id="fit" class="fit">
<span id="wrap">Resize font depending on string length</span>
</div>

Resources