Google Fonts - variable fonts not working in Windows browsers - css

I have a simple Next.js app that I am developing on macOS (chrome) and have only noticed something is wrong when testing on Windows (chrome, and others too).
I use the font Inter from Google Fonts, nextjs + tailwind takes care of injecting needed css in <head>:
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet" />
which after build translates to:
<style data-href="https://fonts.googleapis.com/css2?family=Inter&display=swap">
#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfMZs.woff) format('woff')}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhjp-Ek-_EeAmM.woff) format('woff');unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZthjp-Ek-_EeAmM.woff) format('woff');unicode-range:U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZNhjp-Ek-_EeAmM.woff) format('woff');unicode-range:U+1F00-1FFF}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZxhjp-Ek-_EeAmM.woff) format('woff');unicode-range:U+0370-03FF}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZBhjp-Ek-_EeAmM.woff) format('woff');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+1EA0-1EF9,U+20AB}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZFhjp-Ek-_EeAmM.woff) format('woff');unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}#font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v7/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hjp-Ek-_EeA.woff) format('woff');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
</style>
and tailwind config:
theme: {
extend: {
fontFamily: {
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
},
},
},
which then after build, in browsers sets following declaration to <html> tag:
font-family:
Inter var,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji
The "Inter var" works perfectly on macOS browsers, doesn't work on Windows - it falls back to next option. When I change it to "Inter" only, it works on Windows too, but obviously, the variable font stuff is gone and everything is too thin. Rather than changing all CSS to reflect to this, why does the variable font not work on Windows? I already spend about a whole day on this and other SO posts didn't seem to work for me. Am I doing something wrong?

Update: google font API might return static font files
Due to user-agent detection, you might get static rules in some browsers – even though they support variable fonts flawlessly (e.g. chromium/blink based Opera browser). Firefox or Chrome should work perfectly.
Use the '..' range delimiter and open the css URL in firefox
https://fonts.googleapis.com/css2?family=Inter:wght#100..900
The desired variable #font-face rules should look like this:
#font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
}
Note the font-weight: 100 900 property using two values to specify a weight range – Bingo! we got the correct variable font css.
Example1: retrieve #font-face via API css URL
let fontWeight = document.querySelector('#fontWeight');
let fontVariation = document.querySelector('#fontVariation');
let fontSamples = document.querySelectorAll('.fontSample');
fontWeight.addEventListener('change', function(e){
let value = e.target.value;
fontSamples.forEach(function(item, i){
fontSamples[i].setAttribute('style', 'font-weight:'+value);
} )
} );
fontVariation.addEventListener('change', function(e){
let value = e.target.value;
fontSamples.forEach(function(item, i){
fontSamples[i].setAttribute('style', 'font-variation-settings: \'wght\' '+value);
} )
} )
body{
font-family: georgia
}
#font-face {
src: url('https://mdn.github.io/css-examples/variable-fonts/fonts/AmstelvarAlpha-VF.woff2') format('woff2-variations');
font-family:'Amstelvar';
font-style: normal;
}
.amstelvar{
font-family: 'Amstelvar', serif;
}
.inter{
font-family: 'Inter', 'Open Sans', sans-serif;
}
h1{
font-weight: 500;
transition: 0.3s;
}
<link href="https://fonts.googleapis.com/css2?family=Inter:wght#100..900&display=swap" rel="stylesheet">
<h1 class="fontSample inter">Hamburglefonstiv (Inter)</h1>
<h1 class="fontSample amstelvar">Hamburglefonstiv (Amstelvar)</h1>
<p>
<label>Font weight</label>
<input id="fontWeight" type="range" min="100" max="900" step="1">
</p>
<p>
<label>font-variation-settings</label>
<input id="fontVariation" type="range" min="100" max="900" step="1">
</p>
As mentioned before, this won't work in Opera (and maybe other browsers). So the above css URL
https://fonts.googleapis.com/css2?family=Inter:wght#100..900
will return the same result as:
https://fonts.googleapis.com/css2?family=Inter:wght#100;200;300;400;500;600;700;800;900
containing rules for each font-weight.
Example 2: workaround for Opera #font-face
We can copy the correct variable font-face rule to our css.
let fontWeight = document.querySelector('#fontWeight');
let fontVariation = document.querySelector('#fontVariation');
let fontSamples = document.querySelectorAll('.fontSample');
fontWeight.addEventListener('change', function(e) {
let value = e.target.value;
fontSamples.forEach(function(item, i) {
fontSamples[i].setAttribute('style', 'font-weight:' + value);
})
});
fontVariation.addEventListener('change', function(e) {
let value = e.target.value;
fontSamples.forEach(function(item, i) {
fontSamples[i].setAttribute('style', 'font-variation-settings: \'wght\' ' + value);
})
})
body {
font-family: georgia
}
#font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2) format('woff2');
}
#font-face {
src: url('https://mdn.github.io/css-examples/variable-fonts/fonts/AmstelvarAlpha-VF.woff2') format('woff2-variations');
font-family: 'Amstelvar';
font-style: normal;
}
.amstelvar {
font-family: 'Amstelvar', serif;
}
.inter {
font-family: 'Inter', 'Open Sans', sans-serif;
}
h1 {
font-weight: 500;
transition: 0.3s;
}
<h1 class="fontSample inter">Hamburglefonstiv (Inter)</h1>
<h1 class="fontSample amstelvar">Hamburglefonstiv (Amstelvar)</h1>
<p>
<label>Font weight</label>
<input id="fontWeight" type="range" min="100" max="900" step="1">
</p>
<p>
<label>font-variation-settings</label>
<input id="fontVariation" type="range" min="100" max="900" step="1">
</p>
Since the font-family name is defined just as "Inter" (without "var") in the retrieved #font-face declaration you should also refer to it using this name:
theme: {
extend: {
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
},
},
},
google font UI
Theres is currently no intuitive way to retrieve the correct parameters since the the UI is more focused on static file output.
Selecting multiple styles in the UI will create a static css URL like:
<link href="https://fonts.googleapis.com/css2?family=Inter:wght#100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
Seemless weight interpolation won't work with these files.
To retrieve all supported design axis (e.g Inter supports weight and slant) you can use the "type tester" tab.
Still not perfect. So you're better off concatenating the URL query parameters manually:
https://fonts.googleapis.com/css2?family= +
Inter +
: + slnt + , + wght (design axis names)+
# + -10..0 + , + 100..900 (design axis range values)
Example 3: Inter slant+weight
let fontWeight = document.querySelector('#fontWeight');
let fontVariation = document.querySelector('#fontVariation');
let fontSamples = document.querySelectorAll('.fontSample');
fontWeight.addEventListener('change', function(e) {
let value = e.target.value;
fontSamples.forEach(function(item, i) {
fontSamples[i].setAttribute('style', 'font-weight:' + value);
})
});
fontVariation.addEventListener('change', function(e) {
let value = e.target.value;
fontSamples.forEach(function(item, i) {
fontSamples[i].setAttribute('style', 'font-variation-settings: \'slnt\' ' + value);
})
})
/* latin */
#font-face {
font-family: "Inter";
font-style: oblique 0deg 10deg;
font-weight: 100 900;
src: url(https://fonts.gstatic.com/s/inter/v12/UcCo3FwrK3iLTcviYwY.woff2) format("woff2");
}
body {
font-family: Inter;
}
.inter {
font-family: "Inter", "Open Sans", sans-serif;
}
h1 {
font-weight: 500;
transition: 0.3s;
}
<h1 class="fontSample inter">Hamburglefonstiv (Inter)</h1>
<p>
<label>Font weight</label>
<input id="fontWeight" type="range" min="100" max="900" step="1">
</p>
<p>
<label>font-slant</label>
<input id="fontVariation" type="range" min="-10" max="0" step="1" value="0">
</p>
Worth noting:
You can also style your text via font-variation-settings property.
To change the boldness we would use:
.black{
font-variation-settings: wght 900
}
See also css-tricks.com: Getting the Most Out of Variable Fonts on Google Fonts

You can download the ttf file of the font and just include the file in css.
#font-face{
font-family: rocksalt;
src: url('../font/RockSalt-Regular.ttf');
}
here RockSalt is a downloaded font from google fonts and imported to folder named font and use keyword "rocksalt" to add it.

Related

Inlining fonts and images inside CSS files with Webpack5?

I need to import into my project some CSS files with Webpack 5 and I need to inline all these resources (it's a requirement sadly). Inside the CSS there are some fonts and images with relative URI, like this:
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Regular.ttf) format("truetype"); font-weight: normal;}
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Bold.ttf) format("truetype"); font-weight: bold;}
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Italic.ttf) format("truetype"); font-weight: normal; font-style: italic;}
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-BoldItalic.ttf) format("truetype"); font-weight: bold; font-style: italic;}
#font-face { font-family: 'Material Icons'; font-style: normal; font-weight: 400; src: url(./fonts/material-icons.woff2) format('woff2'); }
#font-face { font-family: 'Material Icons Outlined'; font-style: normal; font-weight: 400; src: url(./fonts/material-icons-outlined.woff2) format('woff2'); }
* { font-family: "MyFont", "Roboto-Light", "Noto Sans CJK SC", "DejaVu Sans"; }
.UICheckbox { width:80px; height:89px; background-image:url("img/checkboxOFF.png"); background-repeat:no-repeat; }
.UICheckbox.checked { background-image:url("img/checkboxON.png"); }
Since I need to import as base64 the CSS files I cannot actually process automatically the resources found inside of them (contrary to how it is done with PostCSS or similiars).
My current webpack configuration is the following but it just ignores the url() statements:
{
test: /\.(png|jpg|gif)$/i,
type: "asset/inline",
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/inline",
},
{
test: /\.css$/i,
type: "asset/inline",
},
Is there a better way to handle this?
I found a solution that is not really generic or solid but does the job, at least in my case scenario.
The imports are relatives to a fixed source path so the idea is to read the resources found inside the url() rules and process it as DataURI in base64 encoding.
I found quite useful the use of datauri which provides a way to include data in-line as if they were external resources and manages the mimetypes automatically.
npm install datauri --save
Then I had to modify the generator handler inside webpack.config.js to process the resources manually exploiting the datauri package.
const path = require("path");
const Datauri = require("datauri/sync");
const EXTERNAL_ROOT_PATH = "./src/external/dev/";
module.exports = {
...
module: {
rules: [
{
test: /\.css$/i,
type: "asset/inline",
generator: {
dataUrl: (content) => {
content = content.toString();
// Get the resource paths inside the CSS url() rules
let asset_urls = [];
let match,
regex = /url\((.*?)\)/gi;
while ((match = regex.exec(content))) {
asset_urls.push(match[1]);
}
// console.log(asset_urls);
// Convert the resource to a DataURI and replace it inside url()
asset_urls.forEach((file_path) => {
// Sanitize the file path first
sanitized_file_path = file_path.replace(/[\"\']/g, "").replace(/^(?:\.\.\/)+/, "");
const data_uri = Datauri(path.join(EXTERNAL_ROOT_PATH, sanitized_file_path));
// console.log(data_uri.content); //=> "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
// console.log(data_uri.mimetype); //=> "image/png"
// console.log(data_uri.base64); //=> "iVBORw0KGgoAAAANSUhEUgAA..."
// console.log(data_uri.buffer); //=> file buffer
content = content.replace(file_path, data_uri.content);
});
return "data:text/css;base64," + Buffer.from(content).toString("base64");
},
},
},
],
},
};

Custom fonts with L.divIcon Leaflet not showing

Using the icomoon internet service to create custom icon-fonts, having trouble to make them visible on Leaflet map. Somehow I can not fetch the icons, what have I missed!? I have the data on the map as I can open up the popup, the problem is there is no icons visible....
I have the fonts folder in the correct place and stylesheet is loaded
This is part of the CSS from icomoon I have in a custom-style.css
#font-face {
font-family: 'icomoon';
src: url('myplace/customer/fonts/icomoon.eot?bf4cat');
src: url('myplace/customer/fonts/icomoon.eot?bf4cat#iefix') format('embedded-opentype'),
url('myplace/customer/fonts/icomoon.ttf?bf4cat') format('truetype'),
url('myplace/customer/fonts/icomoon.woff?bf4cat') format('woff'),
url('myplace/customer/fonts/icomoon.svg?bf4cat#icomoon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icomoon' !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-bb .path1:before {
content: "\e900";
color: rgb(35, 31, 32);
}
.icon-bb .path2:before {
content: "\e901";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-bb .path3:before {
content: "\e902";
margin-left: -1em;
color: rgb(0, 0, 0);
} etc....
Then I created a function to look for customer name and give them a className
function getCustomer(x){
x === 'customerBB' ? 'icon- icon-bb' :
x === 'customerCA' ? 'icon- icon-ca' :
x === 'customerCE' ? 'icon- icon-ce' :
'leaflet-div-icon'; //default blue icon if no match
Then a function to return className depending on the results found in feature.properties.customer_name
var setDivIcon = function(feature){
return {
className: getCustomer(feature.properties.customer_name)
};
}
var customerIcon = L.divIcon(setDivIcon);
Later on I use the pointToLayer to add the GeoJSON to the map
customerLayer = L.geoJson(json, {
pointToLayer: function(feature, latlng) {
var time = feature.properties.timeMean_numb;
var point
if (time < 0.167){
point = L.marker(latlng, {icon: L.divIcon(setDivIcon(feature)) }).addTo(time_1);
}
else if (time >= 0.167 && time <= 0.334){
point = L.marker(latlng, {icon: L.divIcon(setDivIcon(feature)) }).addTo(time_2);
}
In your fontface rule you are missing some src:? This could explain them not being fetched

How to declare multiple font-face and assign each of them to a variable and access them in styled-components

I am using font-face in index.css and accessing these font-family in other places of my application.
My requirement is to assign each of these font-face to different variables. And use these variables in my applications. I want to name these variables generically as 'regular', 'medium' because if I change it from OpenSans to other font-family I need not change font-family as OpenSans to other in other parts of my application.
I am using styled-components for stylings .
#font-face{
font-family: 'OpenSans';
font-style: normal;
font-weight: 400;
src: url(./assets/Fonts/OpenSans-Regular.ttf)
}
#font-face{
font-family:'OpenSans-SemiBold';
font-style: normal;
font-weight: 400;
src:url(./assets/Fonts/OpenSans-SemiBold.ttf)
}
#font-face{
font-family:'OpenSans-SemiBoldItalic';
font-style: normal;
font-weight: 400;
src:url(./assets/Fonts/OpenSans-SemiBoldItalic.ttf)
}
#font-face{
font-family: 'Proxima Nova';
font-style: normal;
font-weight: 400;
src: url(./assets/Fonts/ProximaNova-Regular.ttf);
}
#font-face{
font-family: 'Proxima Nova Medium';
font-style: normal;
font-weight: 400;
src: url(./assets/Fonts/proxima-nova-medium.ttf);
}
Also, once these font-faces are assigned to different variables how can I access in styled-components of other components
eg:
const p = styled.p`
font-family: ??? --> is it using ${variable_name} ?
`
my requirement in index.css :
var Medium-font = {
#font-face{
font-family: 'Proxima Nova Medium';
font-style: normal;
font-weight: 400;
src: url(./assets/Fonts/proxima-nova-medium.ttf);
}
};
var Regulat-font = {
#font-face{
font-family: 'Proxima Nova';
font-style: normal;
font-weight: 400;
src: url(./assets/Fonts/ProximaNova-Regular.ttf);
}
};
and so on..
You don't need to assign the whole font-face to a variable. Fonts are NOT something that you change often. But even if you do for some reason... the font-face will still need to be changed like url and the name of the font itself in the index.css but the only change in actual css will be the font-family property.
You can just assign the font-family to a variable in styled-components and then use it everywhere. This way you'll only need to change it in one place in your theme.
You can use ThemeProvider to achieve this.
// Some component
const Para = styled.p`
font-family: ${props => props.theme.fontFamily1};
`;
const Para2 = styled.p`
font-family: ${props => props.theme.fontFamily2};
`;
// Define what props.theme will look like
const theme = {
fontFamily1: "OpenSans",
fontFamily2: " Proxima Nova"
};
//render method of App.jsx or root app file
render(
<div>
<ThemeProvider theme={theme}>
<Para>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Para>
<Para2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Para2>
</ThemeProvider>
</div>
);
<Para> compoent will now have the font OpenSans and <Para2> Proxima Nova.
If you decide to change the font, just change the fontFamily1/fontFamily2 prop in theme accordingly and it'll reflect in all the components using the theme.
Refer this for more info: https://styled-components.com/docs/advanced#theming
Hope this helps !

Declare variable for different classes

I'm using SCSS and I have a variable $arial: 'Arial', serif;
Now I want to do something like that:
.english{
$arial: 'Arial', serif;
font-family: $arial;
}
.japan{
$arial: 'Noto Sans';
font-family: $arial;
}
Because from the beginning, my customer wants to display $arial as 'Arial', but now they're separating it to 2 pages, (English page and Japanese page).
You could use a newer CSS feature called CSS variables to accomplish this. Simple define what variables need to change in what context, and then import them in the definitions themselves. You can find the docs here: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
Here is an example (using very easily distinguishable fonts):
document.querySelector( 'h1' ).addEventListener( 'click', e => document.body.classList.toggle( 'japanese' ) )
body {
--font: 'Comic Sans MS', monospace;
font-family: var(--font, cursive);
}
body.japanese {
--font: 'Impact';
}
<h1>Lorem Ipsum Dolor Sit Amet</h1>
With a simple class toggle, the variable is updated and the definition only needs to be made once.
I suggest you to make use of CSS Vars as above. To accomplish this in sassy way you can make use of sass map
$map:("english":"'Arial',serif","japan":"'Nato Sans'");
#each $key , $value in $map{
.#{$key}{
font-family:unquote($value);
}
}
output
.english {
font-family: 'Arial',serif;
}
.japan {
font-family: 'Nato Sans';
}

WebEngineView: Set custom font to html content

How to apply custom font (font is in qrc) to some part of html content in WebEngineView?
I figured out how to use my custom font (but I'm not sure how safe is this):
Add custom font to qrc: ://res/font/myfont.ttf;
Create style.css in qrc with this content:
#font-face {
font-family: myfont;
src: url('qrc:/res/font/myfont.ttf');
font-weight: bold;
}
body {
font-family: 'myfont';
text-align: justify;
line-height: 25px;
}
In QML when content loaded to WebEngineView add your style.css to HTML:
WebEngineView {
id: webEngineView
onLoadingChanged: {
if (loadRequest.status == WebEngineView.LoadSucceededStatus) {
webEngineView.runJavaScript(
"var headHTML = document.documentElement.getElementsByTagName('head')[0].innerHTML;" +
"headHTML += '<link rel=\"stylesheet\" href=\"qrc:/css/styles.css\">';" +
"document.documentElement.getElementsByTagName('head')[0].innerHTML = headHTML;"
);
}
}
}
And last, run your app with this command line argument --disable-web-security

Resources