unjs / fontaine Goto Github PK
View Code? Open in Web Editor NEWAutomatic font fallback based on font metrics
License: MIT License
Automatic font fallback based on font metrics
License: MIT License
Update README to show usage with tailwind.
This is how I got it to work. The module adds the fallback fonts correctly but we need to tell tailwind the fallback font family name in order to actually use it.
// tailwind.config
module.exports = {
theme: {
extend: {
fontFamily: {
// For every font, provide another string in `${fontName} fallback` format
plex: ["IBM Plex Sans Arabic", "IBM Plex Sans Arabic fallback"],
},
},
},
};
No response
I'd make a PR if the solution sounds good
There are some packages, for example, the inter-ui NPM package (which is recommended by the official inter GH readme for NPM) which, very unfortunately, have parens in some of the folder names.
For example from the inter-ui package the fonts are under folders with parens in their names.
Example font file: inter-ui/Inter (web)/Inter-Regular.woff2
The URL_RE
that fontaine is using is defined as
const URL_RE = createRegExp(
exactly("url(").and(charNotIn(")").times.any().as("url")).and(")"),
["g"]
);
So no matter what it breaks with these URLs.
The problem is that source URL would get regex'd out as inter-ui/Inter (web
and then the next check is to see if the source ends with one of the supported extensions (and since the regex mangled the URL, the extension was lost).
https://stackblitz.com/edit/github-hdufeg?file=index.css
Parsing of the source url should support any valid URL characters
No response
I was loading this through nuxt-fontaine, and then through nuxt-fonts and it seems like CLS is actually worse using this package. We're using Plus Jakarta Sans from Bunny Fonts. The fallback font is loading, but the sizing seems to be off and it's actually causing more CLS than not using this.
When this package is not used, it falls back to Helvetica, which is fairly close and has a similar number of lines in most places. When this is in use, even if Helvetica is set as the fallback font (instead of Arial, which it defaults to) the sizing is just generally worse everywhere.
I've manually set the fallback font to be Helvetica. I've also tried using both nuxt-fontaine and nuxt-fonts to make sure I wasn't configuring things in an odd way.
I also tried Roboto, which is used in some of the examples. I saw similar CLS issues, though not as severe.
Is this particular font just hard to size or something? Generally, nuxt-fonts worked pretty well, but the sizing of the fallback font was definitely a problem.
For platforms supporting postcss, it would be reasonable to benefit from postcss parsing rather than the current regexp based solution (which could remain fallback)
Sometimes we have this setup:
@font-face {
font-family: 'Biennale';
font-weight: 400;
font-style: normal;
font-display: swap;
src: url('~/assets/fonts/Biennale-Book.woff2') format('woff2'),
url('~/assets/fonts/Biennale-Book.woff') format('woff');
}
@font-face {
font-family: 'Biennale';
font-weight: 500;
font-display: swap;
src: url('~/assets/fonts/Biennale-Medium.woff2') format('woff2'),
url('~/assets/fonts/Biennale-Medium.woff') format('woff');
}
When fontaine is parsing the font-face it creates the override/fallback font-face without accounting for the weight.
@font-face {
font-family: "Biennale override";
src: local("BlinkMacSystemFont"),local("Segoe UI"),local("Roboto"),local("Helvetica Neue"),local("Arial"),local("Noto Sans");
ascent-override: 94.4%;
descent-override: 24.5%;
line-gap-override: 0%;
}
@font-face {
font-family: 'Biennale';
font-weight: 400;
font-style: normal;
font-display: swap;
src: url('/_nuxt/assets/fonts/Biennale-Book.woff2') format('woff2'),
url('/_nuxt/assets/fonts/Biennale-Book.woff') format('woff');
}
@font-face {
font-family: "Biennale override";
src: local("BlinkMacSystemFont"),local("Segoe UI"),local("Roboto"),local("Helvetica Neue"),local("Arial"),local("Noto Sans");
ascent-override: 96.7%;
descent-override: 26.5%;
line-gap-override: 0%;
}
@font-face {
font-family: 'Biennale';
font-weight: 500;
font-display: swap;
src: url('/_nuxt/assets/fonts/Biennale-Medium.woff2') format('woff2'),
url('/_nuxt/assets/fonts/Biennale-Medium.woff') format('woff');
}
We should probably add weight parsing, we should just probably parse it with regexp and add it on the created weight/override.
Expected result would be:
@font-face {
font-family: "Biennale override";
font-weight: 400;
font-style: normal;
src: local("BlinkMacSystemFont"),local("Segoe UI"),local("Roboto"),local("Helvetica Neue"),local("Arial"),local("Noto Sans");
ascent-override: 94.4%;
descent-override: 24.5%;
line-gap-override: 0%;
}
@font-face {
font-family: 'Biennale';
font-weight: 400;
font-style: normal;
font-display: swap;
src: url('/_nuxt/assets/fonts/Biennale-Book.woff2') format('woff2'),
url('/_nuxt/assets/fonts/Biennale-Book.woff') format('woff');
}
@font-face {
font-family: "Biennale override";
font-weight: 500;
font-display: swap;
src: local("BlinkMacSystemFont"),local("Segoe UI"),local("Roboto"),local("Helvetica Neue"),local("Arial"),local("Noto Sans");
ascent-override: 96.7%;
descent-override: 26.5%;
line-gap-override: 0%;
}
@font-face {
font-family: 'Biennale';
font-weight: 500;
font-display: swap;
src: url('/_nuxt/assets/fonts/Biennale-Medium.woff2') format('woff2'),
url('/_nuxt/assets/fonts/Biennale-Medium.woff') format('woff');
}
No response
No response
It would be good to add some sandboxes or example configurations so it's easy for people to get up-and-running with (at least):
Thanks for trying Maige.
Running GPT-based services is pricey. At this point, we ask you to add payment info to continue using Maige.
Feel free to close this issue.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are awaiting their schedule. Click on a checkbox to get an update now.
@vitest/coverage-v8
, vitest
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, eslint
)These updates are currently rate-limited. Click on a checkbox below to force their creation now.
@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
.github/workflows/ci.yml
actions/checkout v4
actions/setup-node v4
actions/checkout v4
actions/setup-node v4
codecov/codecov-action v4
.github/workflows/release.yml
actions/checkout v4
actions/setup-node v4
package.json
@capsizecss/metrics ^2.1.1
@capsizecss/unpack ^2.0.1
magic-regexp ^0.8.0
magic-string ^0.30.10
pathe ^1.1.2
ufo ^1.5.3
unplugin ^1.11.0
@antfu/eslint-config 2.22.3
@types/node 20.16.0
@types/serve-handler 6.1.4
@typescript-eslint/eslint-plugin 7.16.1
@typescript-eslint/parser 7.16.1
@vitest/coverage-v8 2.0.2
bumpp 9.4.1
eslint 9.7.0
eslint-config-prettier 9.1.0
execa 9.3.0
get-port-please 3.1.2
lint-staged 15.2.7
serve-handler 6.1.5
simple-git-hooks 2.11.1
typescript 5.5.4
vite 5.3.5
vitest 2.0.2
pnpm 9.5.0
playground/package.json
vite ^5.1.5
Currently we include metrics for lots of fonts, which adds to install size. This is only in development, of course, but for users who know their font metrics it would be nice to offer a minimal option.
When attaching fonts via Fontsource (4k stars on Github), a fallback font is added to font-family
, but @font-face
is not created for it.
https://stackblitz.com/edit/github-xyllwv?file=index.css
The Roboto font in the demo should have a fallback font, but it doesn't.
https://github.com/Serator/fontaine-with-fontsource - additional example with SvelteKit.
Only reproducible on [email protected]
. May have regressed with the changes in c0f6483. To reproduce, clone the repo I created below, run npm install
, and then node index.js
.
Invoking getMetricsForFamily
returns null
for any legitimate font. Only reproducible in other packages that install fontaine
, but not in fontaine itself in the test environment.
https://github.com/AleksandrHovhannisyan/fontaine-131
The function should not return null
. It's unclear why tests pass locally, but when I tried using [email protected] locally in my project, I was getting null
no matter what I tried.
No response
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: Cannot find preset's package (:automergeEarlyMondays). Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
Probably in some case, we won't have that override name in the font name.
I would like to suggest to customize the overridden name.
I probably not understand well, so let me know if I'm wrong.
No response
Added as a regular webpack plugin in my config, when building (with or without the watch flag) the bundle, the font faces and the font-family
are all untouched.
https://stackblitz.com/edit/webpack-webpack-js-org-7bs3qn?file=webpack.config.js
It should apply the expected transformation per font.
The config uses the following loaders for SCSS and CSS:
It also uses stylelint to lint the files.
The postcss config is pretty straight forward as it consists of the default configurations of the following plugins:
Fonts are processed using Webpack 5's asset/module system (instead of file-loader
for instance). "Static" fonts that aren't meant to change are not touched by webpack, but referenced in URLs (pointing to the correct file from the main css file's perspective).
NB: I've also tried with file-loader
instead, the result is the same
I would like to see guidance on how to use fontaine with Gatsby.
We're using a pretty standard set up of Gatsby and Sass. I've installed fontaine
using the below code in gatsby-node.js
. However the override
font-face rules aren't created and the font-family
isn't being changed.
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
const config = getConfig();
config.plugins.push(
FontaineTransform.webpack({
fallbacks: ['BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Arial', 'Noto Sans']
})
);
actions.replaceWebpackConfig(config);
};
Ideally README.md
No response
Hello, first of all, thank you for this project! I am getting started and was wondering if you could help me get off the ground.
I have a webpage that uses a custom font, GraphikCondensed, and it has significant CLS on Chrome for Android.
The fallback font is Roboto, but I am on a Mac, so Roboto has been installed on the Mac. The woff2 file for the custom font, GraphikCondensed, has been placed under the fonts directory in the playground.
In vite.config.mjs
, I am not sure about what needs to be in the options.
This is what index.css
looks like...
@font-face {
font-family: 'GraphikCondensed';
src: local('GraphikCondensed'), url(/fonts/GraphikXXCondensed-Bold-Web.992f2cf.woff2)
format('woff2');
font-display: swap;
font-weight: 400;
font-style: normal;
}
h1 {
font-family: 'GraphikCondensed';
font-size: 3rem;
line-height: 1.1;
}
What should the configuration for vite.config.mjs be? This is what I currently have...
import { defineConfig } from 'vite'
import { FontaineTransform } from 'fontaine'
export default defineConfig({
plugins: [
FontaineTransform.vite({
fallbacks: ['Roboto'],
// resolve absolute URL -> file
resolvePath: (id) => 'file:///Library/fonts/Roboto-Regular.ttf',
}),
],
})
Also, these changes were made in the /playground directory, then pnpm demo:dev
was run. However, when opening the css file, the file has not been changed, and the font metrics for the override are not present. I do not see any error messages, so am wondering if I should be running another command.
readme
No response
I'm trying to read the font metrics for IBM Plex Mono (this issue is actually reproducible with any typeface that has more than one space in its family name), but getMetricsForFamily
is returning null
. This is because of the following line of code:
Which should do a global replacement for spaces:
const name = camelCase(family).replace(/ /g, '')
N/A (invoke getMetricsForFamily with IBM Plex Mono or any other font family with multiple spaces in its name)
Current behavior: IBM Plex Mono
becomes iBMPlex Mono
Expected behavior: IBM Plex Mono
becomes iBMPlexMono
, allowing us to key in here correctly:
No response
Any way of using this in a CLI? Maybe analyzing a URL and returning the generated font overrides? I guess you'd also need to provide the local files.
Currently we can use metrics to adjust vertical height accurately. There's still a horizontal mismatch though, even if slight, and we can likely solve this by applying the right metrics to size-adjust
.
Thanks for trying Maige.
Running GPT-based services is pricey. At this point, we ask you to add payment info to continue using Maige.
Feel free to close this issue.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.