Web authors have requested the ability to know which variation axes and font features are available in the fonts on the page.
This is clearly out of scope for CSS (although I know next to nothing about CSSOM and Houdini).
Additional or changed descriptors for @font-face
would be a different thing. Authors wouldn’t _know_ about available features, but _declare_ what to do if they exist.
Using a media query for this wouldn't work because media queries have no concept of a specific font face to investigate. Instead, it seems that such a mechanism would have to be in JavaScript.
The canvas text metrics API and the forthcoming Houdini text metrics API expose some other font-driven information. However, these APIs give you information about a line (or lines) of text, and would include things like fallback fonts. Variation axes and features are font-specific, so including fallback fonts isn't the right level of abstraction for solving this problem.
A natural place to put this would be to build off of the CSS Font Loading API. This API already has the concept of an object which represents a font face. In addition, a FontFace even already has a "status" enum property which has a relationship to a specific url() inside the FontFace (so there is precedent for this idea already). Maybe a function can be added to FontFace which returns a new object which has a bunch of properties including font info. Calling the function on an in-flight download would result in an exception or something.
Any thoughts? @tabatkins @bramstein @nattokirai @SergeyMalkin @drott @heycam
P.S. According to caniuse, Edge hasn't implemented the CSS Font Loading API, so they would probably have to implement at least some of it in order to go with this proposal.
I agree that extending Font Loading API seems like a natural way to get this discoverability. Although it would be nice to be able to code up a test page in HTML/CSS to explore what some font provides.
Ultimately fonts need to have better documentation.
We probably would want something similar for font color palettes.
The canvas text metrics API and the forthcoming Houdini text metrics API expose some other font-driven information. However, these APIs give you information about a line (or lines) of text, and would include things like fallback fonts.
Yes. At the early Houdini meetings the assumption was that Houdini would produce a font metrics API, to query features of a particular font (and with the advent of variation fonts, a particular instance). However, over time that was seen as less important for pollyfiller-writers than metrics on fonts used together in a text segment, which eventually became the text metrics API.
There is still a need to query an individual font instance.
Consider the following CSS:
@supports (font-feature-settings: "subs" 1) {
sub, sup { vertical-align: baseline; font-size: 100% }
sub {
font-feature-settings: "subs" 1
}
sup {
font-feature-settings: "sups" 1
}
}
Basically, I want to use have the font position/size the superscripts and subscripts if it supports those features. Otherwise, I want to use the default positioning/sizing. However, this doesn't work, because the browser does support font-feature-settings: "sups" 1
but the font itself is missing the feature.
Right. Thus the earlier conclusion of "this belongs in JS, probably attached to the FontFace API defined in Font Loading".
Right. Thus the earlier conclusion of "this belongs in JS, probably attached to the FontFace API defined in Font Loading".
Why should one have to write JS for these things? I don't think one should. And why should one have to use the font loading API if they aren't even loading any fonts, but instead using only the browsers preloaded fonts?
In any case, it seems like font-variant-position is intended to handle my specific issue, though it doesn't seem to work in practice (yet).
Why should one have to write JS for these things?
Because there's no reasonable way to talk about a single individual font file in CSS, but there is in JS. CSS just has a concept of a font stack, composed of family names, each of which is composed of 1 or more composite font faces, each of which is composed of one or more individual font faces/files (you can combine multiple faces into one composite face via unicode-range
). It's the individual faces that you need to know about to tell if a variation axis exists.
And why should one have to use the font loading API if they aren't even loading any fonts, but instead using only the browsers preloaded fonts?
I didn't say you'd use the font loading API. I said you'd use the FontFace API, which happens to be defined in the spec called Font Loading. Nothing needs to be "loaded" to use this. It's just the right API location for this sort of ability to live.
I really want this feature in JS. It would be super useful in building any type of text formatting tool and creating an interface to allow these features to be adjusted if they are available
How about something like this:
interface FontFaceFeature {
readonly DOMString featureTag;
}
interface FontFaceFeatures {
readonly setlike<FontFaceFeature>;
readonly record<FontFaceFeature, long> namedInstances;
}
interface FontFaceVariationAxis {
readonly DOMString name;
readonly DOMString axisTag;
readonly double minimumValue;
readonly double maximumValue;
readonly double defaultValue;
}
interface FontFaceVariations {
readonly setlike<FontFaceVariationAxis>;
}
interface FontFacePaletteValue {
readonly DOMString color;
}
interface FontFacePalette {
readonly maplike<unsigned long, FontFacePaletteValue>
readonly bool usableWithLightBackground;
readonly bool usableWithDarkBackground;
}
interface FontFacePalettes {
readonly maplike<unsigned long, FontFacePalette>;
}
dictionary FontFaceDetails {
readonly FontFaceFeatures features;
readonly FontFaceVariations variations;
readonly FontFacePalettes palettes;
}
partial interface FontFace {
readonly attribute FontFaceDetails details;
}
Looks like a good first draft to me, thanks for writing this up. I would perhaps take the namedInstances
out of FontFaceFeature
s and add them to FontFaceDetails
as a separate field to stay closer to the structure in OpenType? Would the idea be to list all FontFaceFeature
s for all scripts, or query them per script, or for DFLT script?
This looks great! Nitpick: something about the word details
bothers me, but I can't quite put my finger on it.
@drott @bramstein In font design programs this type of information is usually in the Info
panel if that helps with labeling
Pinging @tabatkins
That does look good. Time to put it into an unofficial draft?
This has a lot more indirection than I think is needed. Maybe:
interface FontFaceFeatures {
maplike<DOMString, (long or null)>;
/* null for the name-only features like ss01 */
};
interface FontFaceVariationAxis {
readonly DOMString name;
readonly DOMString axisTag;
readonly double minimumValue;
readonly double maximumValue;
readonly double defaultValue;
};
interface FontFaceVariations {
readonly setlike<FontFaceVariationAxis>;
};
interface FontFacePalette {
iterable<DOMString>;
readonly attribute unsigned long length;
getter DOMString (unsigned long index);
/* arraylike! using the TypedOM pattern, which seems to be right */
readonly bool usableWithLightBackground;
readonly bool usableWithDarkBackground;
};
interface FontFacePalettes {
iterable<FontFacePalette>;
readonly attribute unsigned long length;
getter FontFacePalette (unsigned long index);
};
partial interface FontFace {
readonly FontFaceFeatures features;
readonly FontFaceVariations variations;
readonly FontFacePalettes palettes;
};
Should the things on FontFace
be methods returning the objects instead? That way browsers don't have to initialize them immediately and allocate objects (or do trickery to late-create them on request).
The Working Group just discussed Variation axes not discoverable
, and agreed to the following:
RESOLVED: css-font-loading, level TBD
The full IRC log of that discussion
<fantasai> Topic: Variation axes not discoverable
<fantasai> github: https://github.com/w3c/csswg-drafts/issues/520
<fantasai> myles: One of the requests we got from ppl who make websites who like typography
<fantasai> myles: There's no way for them to know what to put in their font-feature-settings and font-variant-settings properties
<fantasai> myles: Right now they are parsing the font with JS to pull out the tables
<fantasai> myles: So trying to think of ways that a browser could make this data available to web content
<fantasai> myles: Best way I could think of was to hang off of Tab’s fontFace object
<fantasai> myles: defined in font loading spec
<fantasai> myles: New attribute on existing object
<fantasai> myles: That gives a bunch of info about the font
<TabAtkins> My proposal for the IDL for this https://github.com/w3c/csswg-drafts/issues/520#issuecomment-386153230
<fantasai> myles: Just wanted to check on general idea of extending fontFace like this
<fantasai> astearns: Well I like the idea
<fantasai> TabAtkins: I'm for it
<fantasai> TabAtkins: I think this is the right place to put it, good approach for it
<fantasai> myles: Tab's better at writing APIs, so we can use his suggestion if we think it's a good idea
<fantasai> astearns: Any concerns about adding all this info?
<fantasai> astearns: Instead of new UD, maybe another level?
<fantasai> myles: ...
<fantasai> TabAtkins: Let me see how mature the css-font-loading spec actually is, and then we'll decide
<fantasai> fantasai: So, proposal is add it to css-font-loading, level TBD?
<fantasai> astearns: Any objections?
<fantasai> RESOLVED: css-font-loading, level TBD
Would it be possible to extend this to include access to the OpenType 'MATH' tables?
Some math-aware fonts include metric information in these tables which are necessary in order to do proper mathematical layout (i.e. to correctly position arguments on display operators such as integrals or to use the correct line thickness for fraction bar or square root over bar).
Software libraries doing math layout such as MathJax or MathLive have to manually parse font files in JS or, more realistically, hardcode these metrics for a specific font.
Some more thoughts,
There are times when I want to query features and axis of a font but I don’t know _what_ font is loaded. For example, I might have a font stack with San Francisco in it and this will only be available on Apple devices. I want to query the features available to me on any given element. If I want to make a rich text editor, the opentype and variable font menus will be different depending on what font is activated in the font stack. In this scenario I don’t know of a feature or axis to test for but I want to query a menu of all possible features and axis.
Another scenario is if I want to accommodate for making text strong via a combination of weight and width axis I might want to use something more like @supports
, but focused on what any particular element can support instead of globally what the browser or a particular font can support.
FWIW, I get asked once or twice a week about how to find variable axes and OpenType features for a font through JavaScript or CSS on my Wakamai Fondue mail.
@RoelN why isn't https://github.com/Monotype/variableFont.js sufficient for your need?
Would variableFont.js work for system fonts though?
@davelab6 Because it needs ~ 50KB of JavaScript to work and doesn't support WOFF/WOFF2 or system fonts.
would love to see this exposed in js! it will super-boost a lot of web developmet project we do!
It is also helpful if browser dev tool can expose this
I think that exposing it in JS and in dev tools is a good way to make a font's capabilities known, though as @svgeesus points out, the font should come with documentation and a sample page that shows it all off, but that's on the font vendor, not the browser.
As a designer, I would be ok with reliably being able to use browser dev tools or a JS library to figure out what's possible, so I can then make decisions about how I want to use those capabilities. My current workflow tends to be 'get font, drag on to wakamaifondue.com, copy axes and values into my CSS as a set of comments for reference' - rinse, and repeat for every font I encounter. Having a way to do that more natively integrated in a browser or editor (VS Code plugin anyone?) would be really helpful.
(While my comments above are focused on variable font axes, the same would be true for OpenType features)
I would like to see something like this:
element.font
would return
info: {
postScriptName: 'my font italic',
fullName: 'my font italic',
familyName: 'my font',
style: 'italic',
kind: 'opentype',
language: 'English',
version: '6.0.2',
copyright: 'copyright 2019 Acme Inc.'
},
metric: {
ascender: 82,
capHeight: 70,
xHight: 41.6,
descender: -25,
italicAngle: 18,
},
setting: {
smcp: true,
c2sc: true,
hist: true,
tnum: true,
frac: true,
swsh: true,
ss01: true,
ss02: true,
ss03: true,
ss04: true
},
variant: {
wght: {
min: 200,
default: 400,
max: 800
},
opsz: {
min: 8,
default: 16,
max: 72
}
}
}
This allows me to either query the whole object, or target a specific value
element.font.variant.wght.min
I also added font info and metrics, because it seemed like a good thing to throw in there as well.
edit: added defaults to variants thanks to @wentin for identifying that.
“element.font” isn’t quite right because of font fallback. It could be that none of the text in the element is rendered with the primary font. The set of available features will be different depending on which font in the fallback list is used.
@litherum This is the behavior I was expecting. I’d want to query what font features the loaded font on that element supports, not what features does the primary font in the font stack have.
This brings up the edge case of multiple subsetted fonts being loaded at once. In that case maybe just the one first one in the stack that is loaded? Or we could get an array of these objects for each font in the stack, null if it does not exist? So element.font[0]
would be the first in the stack?
If the object could also exposed named instances and named OpenType features (e.g. names of stylistic sets), that'd be useful too.
Real world use cases
@scottkellum These are great - my only comment is under typesetting->weight axis, you should still use font weight, but you can use an explicit value rather than keyword or hundred-limited integers (100, 200, 300, etc) - and this is supported in all browsers now (same for font-stretch with percentage width values)
I believe https://wicg.github.io/local-font-access/ provides this.
It seems that https://wicg.github.io/local-font-access/ is limited to providing information about local fonts (see https://github.com/slightlyoff/local_font_access/issues/1). Having access to font information of fonts that have been downloaded is important as well.
Specific use case: a mathematical formula editor that needs detailed font information (e.g. the OpenType 'math' table) in order to do proper layout. Without access to this information for downloaded fonts, the information needs to be duplicated and provided by an sideband channel (currently I extract it from the font, turn it into a JSON object, and download the JSON with the font. This is redundant information which is already in the font).
Most helpful comment
I would like to see something like this:
would return
This allows me to either query the whole object, or target a specific value
I also added font info and metrics, because it seemed like a good thing to throw in there as well.
edit: added defaults to variants thanks to @wentin for identifying that.