Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spacing characters inside input equally over it's entire width

I have an input field and maxLength value, I want to divide input field into equal virtual boxes of maxLength so that each box contains a single letter.

For e.g if my maxLength value is 10 and input width is 100px, I want to spread these 10 characters over entire width of input, desired result is as shown below


| H | e | l | l | o | w | o | r | l | d |

I decided to calculate letter spacing based on character W (as it is the widest character) using below code and adding css letterSpacing property, but that's not giving me the accurate result

enter code here

function calculateLetterSpacing(fontInfo, width, maxLength) {
  const inputWidth = width;
  const span = document.createElement('span');
  span.innerText = "W";
  span.style.fontSize = fontInfo.fontSize;
  span.style.fontFamily = fontInfo.fontName;
  document.body.appendChild(span);
  const charMaxWidth = span.offsetWidth;
  return (inputWidth - charMaxWidth*maxLength)/maxLength;
}

Is there any direct css property that can allow me to do that.

P.S font can be anything, it's not monospaced.

like image 547
Rohit Saini Avatar asked Feb 27 '19 14:02

Rohit Saini


2 Answers

There's no direct css property that will do that, but I got your function to work. Click "Run code snippet" at bottom and see comments in code for explanation.

var inputfield = document.getElementById("inputfield"); // the input field
var temp = document.getElementById("temphidden"); // the hidden span
var fontsizeOption = document.getElementById("fontsize"); // dropdown for font-size
var fontnameOption = document.getElementById("fontname"); // dropdown for font-name
var widthOption = document.getElementById("inputwidth"); // dropdown for input field's width
var lengthOption = document.getElementById("maxlength"); // dropdown for maxLength

// for demo purposes get the initial values from the dropdowns
var w = parseInt(widthOption.options[widthOption.selectedIndex].value); // initialize width
var m = parseInt(lengthOption.options[lengthOption.selectedIndex].value); // initialize maxLength
var f = { // initialize the fontInfo object
	fontSize : fontsizeOption.options[fontsizeOption.selectedIndex].value,
	fontName : fontnameOption.options[fontnameOption.selectedIndex].value
}; 

calculateLetterSpacing(f, w, m); // initialize the attributes

function calculateLetterSpacing(fontInfo, width, maxLength) {
	var inputWidth = width;
	
	// set the width of the input field
	inputfield.style.width = inputWidth + "px";
	
	// set the font-size of the input field and in the hidden span
	inputfield.style.fontSize = temp.style.fontSize = fontInfo.fontSize;
	
	// set the font name - both locations
	inputfield.style.fontFamily = temp.style.fontFamily = fontInfo.fontName;
	
	// set the max number of chars allowed in the input field
	inputfield.maxLength = maxLength;
	
	// copy the content of input field into the hidden span
	temp.innerHTML = inputfield.value;
	
	// the hidden span's size grows as each character is typed in,
	// therefore the width in pixels of the span == width in pixels
	// of the input string; calculate whiteSpace
	var whiteSpace = parseInt(inputfield.style.width) - temp.clientWidth;
	
	// before text is typed in the length is 0, so check for this
	if (temp.innerHTML.length == 0) { return; }
	
	// divide whiteSpace by numChars to get the amount of letter-spacing
	inputfield.style.letterSpacing = (whiteSpace / temp.innerHTML.length) + "px";
	
	// focus back to the input field
	inputfield.focus();
}
body {font:14px arial;text-align:center;}

#inputfield {
	padding-left:1px;
	text-align:center;
	display:block;
	margin:0 auto 20px auto;
	line-height:30px;
}

.selectwrapper { /* select boxes are for example purposes */
	display:block;
	margin:10px auto;
	width:110px;
}

.selectwrapper select {
	width:100%;
	font:18px arial;
	height:30px;
}
<!-- The input field -->
<p>Type something in ...</p>
<input id="inputfield" type="text" onkeyup="calculateLetterSpacing(f, w, m)">

<!-- The span below is hidden. When a character is entered, it is also copied to this 
	hidden span ("temphidden"). The span's growing width provides the width in 
	pixels of the character string regardless of the font type or size. Access the 
	width of the hidden span using [element].clientWidth -->
	
<span id="temphidden" style="position:absolute;visibility:hidden;white-space:nowrap;padding:1px;"></span> 

<!-- The dropdowns are for demonstration purposes, see "Run code snippet" -->

<div class="selectwrapper">font-size
<select id="fontsize" onchange="{f.fontSize=this.value; calculateLetterSpacing(f, w, m)}">
	<option value="8px">8px</option>
	<option value="12px" selected="selected">12px</option>
	<option value="18px">18px</option>
	<option value="24px">24px</option>
</select>
</div>

<div class="selectwrapper">font name
<select id="fontname" onchange="{f.fontName=this.value; calculateLetterSpacing(f, w, m)}">
	<option value="times">Times</option>
	<option value="arial" selected="selected">Arial</option>
	<option value="Verdana">Verdana</option>
	<option value="Courier">Courier</option>
</select>
</div>

<div class="selectwrapper">width
<select id="inputwidth" onchange="{w=this.value; calculateLetterSpacing(f, w, m)}">
	<option value="80">80px</option>
	<option value="100" selected="selected">100px</option>
	<option value="150">150px</option>
	<option value="220">220px</option>
</select>
</div>

<div class="selectwrapper">max length
<select id="maxlength" onchange="{m=this.value; calculateLetterSpacing(f, w, m)}">
	<option value="7">7</option>
	<option value="10" selected="selected">10</option>
	<option value="15">15</option>
	<option value="24">24</option>
</select>
</div>
like image 125
Steve Lage Avatar answered Nov 01 '22 07:11

Steve Lage


This is a simpler solution that works perfectly, just tested it. Let flexbox do the work for you, it is a CSS tool as you asked. Paste this in a HTML file and save and open in your browser, it will space however many letters you put into the word variable equally across the screen

let lettersHTML = "";

//define the word
let word = "thing";

//split it
let split = word.split('');

//this splits your word into ["t","h","i","n","g"]
//iterate with for loop - over each letter
for (let i=0; i<split.length; i++) {
  let para = document.createElement("P");
  para.innerHTML = `${split[i]}`;
  document.getElementById("container").appendChild(para);
}
#container {
  margin: 0;
  padding: 0;
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
}
<!DOCTYPE html>
<html>
  <body>
<div id="container">
</div>
  </body>
</html>
like image 45
sao Avatar answered Nov 01 '22 05:11

sao