HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<main>
<h1>Variable Font Demo</h1>
<p>
This expirement is meant to allow a reader to play around with assorted settings for a typeface to potentially make it easier to read. In particular, I am using this as the first step in exploring the kinds of font traits an author can tweak to make content easier to read for users with dyslexia.
</p>
<p>
This pen is for my post <cite><a href="http://adrianroselli.com/2018/08/variable-fonts-and-dyslexia.html">Variable Fonts and Dyslexia</a></cite>. Go read it to understand how it can help users with dyslexia.
</p>
<p>
The font is <a href="https://github.com/Manuel87/NobotoFlex">Noboto Flex</a>. I am not using all the features of the font as some of them do not appear to contribute directly to readability. Chrome/Blink, Edge browsers only.
</p>
<h2>Generic Text from Wikipedia</h2>
<p>
OpenType variable fonts are an adaptation of Apple's TrueType GX font variations to OpenType, with integration into key aspects of the OpenType format including OpenType Layout tables and both TrueType and CFF glyph outline formats. It also surpasses
TrueType GX by providing better interoperability between different fonts and between variable fonts and font-formatting specification such as are found in Cascading Style Sheets. The technology allows software to access any design instance for a continuous
range of designs defined within the font. When a specific design instance has been selected, the glyph outlines or other data values for that design instance are computed as font data is being processed during text layout and rasterization.
</p>
<p>
The technology uses interpolation and extrapolation mechanisms that have been supported in font-development tools and used by font designers for many years. In that paradigm, the font designer creates a variable design, but then chooses specific instances
to generate as static, non-variable fonts that get distributed to customers. With variable fonts, however, the font produced and distributed by the font designer can have built-in variability, and the interpolation mechanisms can now be built into
operating systems and Web browsers or other applications, with specific design instances selected at time of use.
</p>
<p>
One of the key benefits of the technology is that it can significantly reduce the combined size of font data whenever multiple styles are in use. On the Web, this may allow a site to use more font styles while at the same time reducing page load times.
A further benefit is that it give access to a continuous range of style variations, which can provide benefits for responsive design.
</p>
<p>
The technology has been compared to Adobe's multiple master fonts (MM fonts) technology, also from the 1990s, which used on-the-fly generation of font designs from master files by interpolation and extrapolation. Multiple master fonts, however, required
the user to generate a specific "instance" of the font for particular variation-axis values before it could be used. This is not required for OpenType variable fonts, however: named or arbitrary design instances can be selected and used on demand.
</p>
</main>
<aside>
<form id="FontToggle">
<h2>Font Settings <button type="button" aria-label="Reset all." onclick="changeAxis('WGHT','140','wght',1);changeAxis('SPAC','80','SPAC',1);changeAxis('HEIG','400','HEIG',1);changeAxis('ASCE','600','ASCE',1);changeAxis('DESC','600','DESC',1);changeAxis('DIAC','0','DIAC',1);changeAxis('MONO','0','MONO',1);changeAxis('CURV','0','CURV',1);this.focus();">↺</button></h2>
<p>
<label for="WGHT">Weight <span aria-hidden="true">(currently <output for="WGHT" form="FontToggle" id="WGHTVal">140</output>)</span>:</label>
<span>
<span>54</span>
<input type="range" id="WGHT" step="1" min="54" max="322" value="140" aria-valuemin="54" aria-valuemax="322" aria-valuenow="140" oninput="changeAxis(this.id,value,'wght');">
<span>322</span>
<span><button type="button" aria-label="Reset weight." onclick="changeAxis('WGHT','140','wght',1);">↺</button></span>
</span>
</p>
<p>
<label for="SPAC">Spacing / tracking <span aria-hidden="true">(currently <output for="SPAC" form="FontToggle" id="SPACVal">80</output>)</span>:</label>
<span>
<span>0</span>
<input type="range" id="SPAC" step="1" min="0" max="200" value="80" aria-valuemin="0" aria-valuemax="200" aria-valuenow="80" oninput="changeAxis(this.id,value,'SPAC');">
<span>200</span>
<span><button type="button" aria-label="Reset spacing / tracking." onclick="changeAxis('SPAC','80','SPAC',1);">↺</button></span>
</span>
</p>
<p>
<label for="HEIG">Height <span aria-hidden="true">(currently <output for="HEIG" form="FontToggle" id="HEIGVal">400</output>)</span>:</label>
<span>
<span>165</span>
<input type="range" id="HEIG" step="1" min="165" max="456" value="400" aria-valuemin="165" aria-valuemax="456" aria-valuenow="400" oninput="changeAxis(this.id,value,'HEIG');">
<span>456</span>
<span><button type="button" aria-label="Reset height." onclick="changeAxis('HEIG','400','HEIG',1);">↺</button></span>
</span>
</p>
<p>
<label for="ASCE">Ascenders <span aria-hidden="true">(currently <output for="ASCE" form="FontToggle" id="ASCEVal">600</output>)</span>:</label>
<span>
<span>456</span>
<input type="range" id="ASCE" step="1" min="456" max="1000" value="600" aria-valuemin="456" aria-valuemax="1000" aria-valuenow="600" oninput="changeAxis(this.id,value,'ASCE');">
<span>1000</span>
<span><button type="button" aria-label="Reset ascenders." onclick="changeAxis('ASCE','600','ASCE',1);">↺</button></span>
</span>
</p>
<p>
<label for="DESC">Descenders <span aria-hidden="true">(currently <output for="DESC" form="FontToggle" id="DESCVal">600</output>)</span>:</label>
<span>
<span>456</span>
<input type="range" id="DESC" step="1" min="456" max="1000" value="600" aria-valuemin="456" aria-valuemax="1000" aria-valuenow="600" oninput="changeAxis(this.id,value,'DESC');">
<span>1000</span>
<span><button type="button" aria-label="Reset descenders." onclick="changeAxis('DESC','600','DESC',1);">↺</button></span>
</span>
</p>
<p>
<label for="DIAC">Diacritics distance <span aria-hidden="true">(currently <output for="DIAC" form="FontToggle" id="DIACVal">0</output>)</span>:</label>
<span>
<span>0</span>
<input type="range" id="DIAC" step="1" min="0" max="100" value="0" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" oninput="changeAxis(this.id,value,'DIAC');">
<span>100</span>
<span><button type="button" aria-label="Reset diacritics distance." onclick="changeAxis('DIAC','0','DIAC',1);">↺</button></span>
</span>
</p>
<p>
<label for="MONO">Monospace <span aria-hidden="true">(currently <output for="MONO" form="FontToggle" id="MONOVal">0</output>)</span>:</label>
<span>
<span>0</span>
<input type="range" id="MONO" step="1" min="0" max="100" value="0" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" oninput="changeAxis(this.id,value,'MONO');">
<span>100</span>
<span><button type="button" aria-label="Reset monospace." onclick="changeAxis('MONO','0','MONO',1);">↺</button></span>
</span>
</p>
<p>
<label for="CURV">Curvature <span aria-hidden="true">(currently <output for="CURV" form="FontToggle" id="CURVVal">0</output>)</span>:</label>
<span>
<span>0</span>
<input type="range" id="CURV" step="1" min="0" max="100" value="0" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" oninput="changeAxis(this.id,value,'CURV');">
<span>100</span>
<span><button type="button" aria-label="Reset curvature." onclick="changeAxis('CURV','0','CURV',1);">↺</button></span>
</span>
</p>
<p>
<a href="https://s.codepen.io/aardrian/debug/yEZvpr" target="_top">Variable Font Demo Using Amstelvar Alpha</a>
</p>
</form>
</aside>
:root {
--page-bg: #eee;
}
/* FF Meta Variable Demo Font */
@font-face {
font-family: "Noboto Flex";
src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/2729/NobotoFlex-VF.ttf")
format("truetype");
}
body {
background-color: var(--page-bg);
font-size: 125%;
color: #333;
font-family: "Noboto Flex", sans-serif;
padding: 0;
margin: 0;
}
main, aside {
display: block;
box-sizing: border-box;
width: 90%;
max-width: 38em;
margin: 1em auto;
padding: 1em 2em;
line-height: 1.5;
color: #333;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 0.5em;
/* font-variation-settings: "wght" 400, "ital" 1; */
}
aside {
max-width: 20em;
padding: 0;
background-color: transparent;
}
h1, h2 {
font-weight: 600;
}
form {
font-family: sans-serif;
font-size: 90%;
background-color: rgba(255, 255, 255, 0.7);
/* background-color: var(--page-bg); */
/* background-image: linear-gradient(to bottom, #f0f0f0, var(--page-bg)); */
border-radius: 0.2em;
padding: 1em;
}
input,
button,
textarea,
select {
font-size: 100%;
color: #333;
font-family: "FF Meta VF", sans-serif;
}
form > h2 {
display: flex;
align-items: flex-start
}
input[type="range"] {
width: calc(100% - 4.3em);
width: 80%;
}
form p {
margin-top: 2em;
}
form p:first-child {
margin-top: 0;
}
form p:last-child {
margin-bottom: 0;
}
form p > span {
display: flex;
justify-content: space-between;
}
form p > span > span {
font-size: 85%;
}
form button {
background-color: transparent;
padding: 0.25em 0.5em;
margin-left: 0.5em;
border: none;
border-radius: 50%;
}
form button:focus,
form button:hover {
color: #eee;
background-color: #333;
outline: none;
}
@media screen and (min-width: 50em) {
body {
display: grid;
grid-template-columns: 2fr 1fr;
grid-gap: 0;
}
}
/* The animation */
@keyframes TOOLTIP {
from {
bottom: 1em;
background-color: rgba(0,0,0,0);
border: .05em solid rgba(255,255,255,0);
color: rgba(255,255,255,0);
box-shadow: 0 0 0 rgba(0,0,0,1);
}
to {
bottom: 2em;
background-color: rgba(0,0,0,.85);
border: .05em solid rgba(255,255,255,1);
color: rgba(255,255,255,1);
box-shadow: .15em .15em .5em rgba(0,0,0,1);
}
}
/* Style for the tool-tip */
button[aria-label] {
position: relative;
}
button[aria-label]:focus::after,
button[aria-label]:hover::after {
position: absolute;
display: block;
z-index: 1;
bottom: 2em;
right: 0;
width: 6em;
max-width: 12em;
padding: .5em .75em;
border: .05em solid rgba(255,255,255,1);
border-radius: .2em;
box-shadow: .15em .15em .5em rgba(0,0,0,1);
content: attr(aria-label);
background-color: rgba(0,0,0,.85);
color: rgba(255,255,255,1);
font-size: .8rem;
text-align: left;
animation: TOOLTIP .1s ease-out 1;
}
var pageMain = document.querySelector('main');
var wghtVal = '"wght" 140';
var spacVal = '"SPAC" 80';
var heigVal = '"HEIG" 400';
var asceVal = '"ASCE" 600';
var descVal = '"DESC" 600';
var diacVal = '"DIAC" 0';
var monoVal = '"MONO" 0';
var curvVal = '"CURV" 0';
setStyles();
function setStyles() {
pageMain.setAttribute('style','font-variation-settings: ' + wghtVal + ', ' + spacVal + ', ' + heigVal + ', ' + asceVal + ', ' + descVal + ', ' + diacVal + ', ' + monoVal + ', ' + curvVal + ';');
}
function changeAxis(eID,num,axis,fldReset) {
document.querySelector('#' + eID + 'Val').value = num;
document.querySelector('#' + eID).setAttribute('aria-valuenow',num);
tmpVal = '"' + axis + '" ' + num;
// Open to another approach that allows me to dump eval
// eval(axis.toLowerCase() +"Val = tmpVal");
// Thanks to Aaron Smith for the non-eval fix
// https://twitter.com/basiphobe/status/1013801568360189952
new Function(axis.toLowerCase() +"Val = tmpVal")();
setStyles();
if (fldReset == '1') {
document.querySelector('#' + eID).value = num;
document.getElementById(eID).focus();
}
}
Also see: Tab Triggers