x-height calculator
by Robert Mohns
HTML
<form action="" id="xHeightCalculator" onsubmit="return false;">
<fieldset>
<legend>x-height Readability Calculator</legend>
<label for="fontPointSize">Font size (points):</label>
<input type="number" step="1" id="fontPointSize" name="fontPointSize" value="16" max="360" min="1" />
<br />
<label for="fontXHeightRatio">x-height of your font (ratio):</label>
<input type="number" step="0.01" id="fontXHeightRatio" name="fontXHeightRatio" value=".45" max="1" min="0" />
<br />
<label for="screenResActual">Actual screen resolution (ppi):</label>
<input type="number" step="1" id="screenResActual" name="screenResActual" value="131" max="500" min="1" />
<br />
<label for="distanceFromScreen">Distance from Screen (inches):</label>
<input type="number" step="1" id="distanceFromScreen" name="distanceFromScreen" value="16" max="240" min="1" />
<br />
<p>
<input id='submit' type='submit' value='Calculate' />
</p>
<p id="resultpara">
<span id="resultLabel">Visual Arc:</span>
<span id="perceivedSize">result</span> <span id="adviceTextHere"></span>
</p>
</fieldset>
</form>
CSS
* {
font-family: 'Hind', sans-serif;
}
body {
font-size: 1em;
background-color: #ff675b;
color: #fefefe;
}
label,
span#resultLabel {
display: inline-block;
width: 16em;
}
#fontPointSize,
#fontXHeightRatio,
#screenResActual,
#distanceFromScreen {
width: 4em;
text-align: right;
}
fieldset {
margin: 0.5em 0.5em 0.5em 0;
}
legend {
padding: 0em 0.5em 0 0.5em;
font-weight: 600;
border-radius: 4px;
}
input[type=number] {
font-size: 1.1em;
height: 1.3em;
}
.subtotal {
font-size: smaller;
color: grey;
}
#resultpara {
font-weight: 600;
}
#perceivedSize {
font-size: large;
font-weight: bold;
}
#totalHours {
font-weight: bold;
font-size: 1.5em;
text-align: right;
padding: 0.5em;
border-radius: 4px;
}
@keyframes noticeThisThing {
0% {
transform: scale(1)
}
25% {
color: #41322f;
background-color: #fbce78;
}
100% {
transform: scale(1)
}
}
.noticeMe {
-webkit-animation: noticeThisThing 0.4s infinite ease;
-moz-animation: noticeThisThing 0.4s infinite ease;
-o-animation: noticeThisThing 0.4s infinite ease;
animation: noticeThisThing 0.4s infinite ease;
}
JavaScript
var theForm = document.forms.xHeightCalculator;
function toggleAnimation(onOffState) {
if (onOffState === "on") {
document.getElementById("perceivedSize").classList.add("noticeMe");
return true;
} else {
document.getElementById("perceivedSize").classList.remove("noticeMe");
return false;
}
}
function getValue(lineItem) {
var theValue = theForm.elements[lineItem];
if (theValue.value !== "") {
return parseFloat(theValue.value);
} else {
return null;
}
}
function updateForm() {
// get the values
var fontPointSize = getValue("fontPointSize");
var fontXHeightRatio = getValue("fontXHeightRatio");
var screenResActual = getValue("screenResActual");
var distanceFromScreen = getValue("distanceFromScreen");
// do the math
var pixelRatio = 96 / screenResActual; // OS assumed resolution vs reality
var distanceFromScreenPoint = distanceFromScreen * 72; // 72 points per inch
var actualXheightPointSize = fontPointSize * fontXHeightRatio * pixelRatio;
var perceivedSizeArctan = Math.atan2(actualXheightPointSize, distanceFromScreenPoint);
var perceivedSizeDegrees = perceivedSizeArctan / (Math.PI / 180);
var prettyDegrees = perceivedSizeDegrees.toPrecision(2);
// update the result
document.getElementById('perceivedSize').innerHTML = prettyDegrees + "º";
// Now for some commentary on the result
var adviceText = "And the verdict is…";
if(perceivedSizeDegrees < 0.2) {
adviceText = "Too small!"
}
if(perceivedSizeDegrees > 0.2 && perceivedSizeDegrees < 0.24) {
adviceText = "A little small, but serviceable."
}
if(perceivedSizeDegrees >= 0.24 && perceivedSizeDegrees < 0.27) {
adviceText = "Not bad."
}
if(perceivedSizeDegrees >= 0.27 && perceivedSizeDegrees < .31 ) {
adviceText = "Nicely readable."
}
if(perceivedSizeDegrees >= 0.31) {
adviceText = "Very, very readable. Nice!"
}
if(perceivedSizeDegrees >= 0.5) {
adviceText = "Now you're just getting silly."
}
if(perceivedSizeDegrees...