Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-fonts-4] [varfont] Supported variation font axes and font features are not discoverable #520

Closed
litherum opened this issue Sep 21, 2016 · 39 comments

Comments

@litherum
Copy link
Contributor

Web authors have requested the ability to know which variation axes and font features are available in the fonts on the page.

@Crissov
Copy link
Contributor

Crissov commented Oct 6, 2016

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.

@litherum
Copy link
Contributor Author

litherum commented Dec 2, 2016

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.

@svgeesus
Copy link
Contributor

svgeesus commented Dec 7, 2016

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.

@litherum
Copy link
Contributor Author

We probably would want something similar for font color palettes.

@svgeesus
Copy link
Contributor

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.

@briansmith
Copy link

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.

@tabatkins
Copy link
Member

Right. Thus the earlier conclusion of "this belongs in JS, probably attached to the FontFace API defined in Font Loading".

@briansmith
Copy link

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).

@tabatkins
Copy link
Member

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.

@scottkellum
Copy link

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

@litherum
Copy link
Contributor Author

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;
}

@drott
Copy link
Collaborator

drott commented Mar 14, 2018

Looks like a good first draft to me, thanks for writing this up. I would perhaps take the namedInstances out of FontFaceFeatures and add them to FontFaceDetails as a separate field to stay closer to the structure in OpenType? Would the idea be to list all FontFaceFeatures for all scripts, or query them per script, or for DFLT script?

@bramstein
Copy link

This looks great! Nitpick: something about the word details bothers me, but I can't quite put my finger on it.

@scottkellum
Copy link

@drott @bramstein In font design programs this type of information is usually in the Info panel if that helps with labeling

@litherum
Copy link
Contributor Author

Pinging @tabatkins

@svgeesus
Copy link
Contributor

svgeesus commented May 2, 2018

That does look good. Time to put it into an unofficial draft?

@tabatkins
Copy link
Member

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).

@css-meeting-bot
Copy link
Member

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//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//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

@arnog
Copy link

arnog commented May 29, 2018

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.

@fantasai fantasai added Needs Edits and removed css-fonts-4 Current Work labels Jun 27, 2018
@scottkellum
Copy link

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.

@heycam
Copy link
Contributor

heycam commented Nov 8, 2018

Would variableFont.js work for system fonts though?

@RoelN
Copy link

RoelN commented Nov 8, 2018

@davelab6 Because it needs ~ 50KB of JavaScript to work and doesn't support WOFF/WOFF2 or system fonts.

@wentin
Copy link

wentin commented Feb 27, 2019

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

@jpamental
Copy link

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)

@scottkellum
Copy link

scottkellum commented Feb 27, 2019

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.

@litherum
Copy link
Contributor Author

“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.

@scottkellum
Copy link

@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?

@RoelN
Copy link

RoelN commented Mar 1, 2019

If the object could also exposed named instances and named OpenType features (e.g. names of stylistic sets), that'd be useful too.

@scottkellum
Copy link

Real world use cases

  • Any type of design tool or word processor using typography can query the features a text block supports and the interface can reflect those features instead of showing UI that doesn’t do anything or excluding features. (there is no good workaround for this and as someone trying to do this it’s really frustrating)
  • For typesetting, identify what features are supported by a font and progressively enhance for them.
    • Does the loaded font have a weight axis? If yes then style it using font variations instead of font weight.
    • Does a font support tabular numerals? If not then use a monospace font for some elements.
  • Use the proportion from the font metrics to determine line height and font size so that type gets rendered more consistently across all the fallback fonts in the font stack.
  • Pull the language support from the font metadata and ensure it matches the language on the site. If the font doesn’t work with your language then you can use one that supports a language better.

@jpamental
Copy link

@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)

@davelab6
Copy link
Contributor

I believe https://wicg.github.io/local-font-access/ provides this.

@arnog
Copy link

arnog commented May 27, 2020

It seems that https://wicg.github.io/local-font-access/ is limited to providing information about local fonts (see slightlyoff/local_font_access#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).

@litherum
Copy link
Contributor Author

litherum commented Sep 10, 2021

@scottkellum

I’d want to query what font features the loaded font on that element

There can be a dozen different fonts used to render that element, though, with a dozen different sets of features. Doing this at the element level is the wrong place.

@tabatkins

interface FontFaceFeatures {
    maplike<DOMString, (long or null)>;
    /* null for the name-only features like ss01 */
};

This appears to tell you what the feature settings are, not which features are available. FontFace already includes the featureSettings info, albeit exposed as a string.

Something like this might make more sense:

interface FontFaceFeature {
    readonly DOMString featureTag;
    readonly unsigned long minimumFeatureValue; // Usually 0. Maybe this member isn't even necessary.
    readonly unsigned long defaultValue;
    readonly unsigned long maximumFeatureValue;
}

interface FontFaceFeatures {
    readonly setlike<FontFaceFeature>; // Setlike because there's no order.
};

litherum added a commit to litherum/csswg-drafts that referenced this issue Sep 10, 2021
This is for w3c#520.

The [resolution](w3c#520 (comment)) is:

> RESOLVED: [add this functionality to] css-font-loading, level TBD

I added this to level 3, because level 4 doesn't exist. If the editor prefers this go in a level 4, that's no problem.

The GitHub thread hasn't come to a conclusion about what should go in the `FontFaceFeatures` interface, so I left it blank for now.
litherum added a commit to litherum/csswg-drafts that referenced this issue Sep 10, 2021
This is for w3c#520.

The [resolution](w3c#520 (comment)) is:

> RESOLVED: [add this functionality to] css-font-loading, level TBD

I added this to level 3, because level 4 doesn't exist. If the editor prefers this go in a level 4, that's no problem.

The GitHub thread hasn't come to a conclusion about what should go in the `FontFaceFeatures` interface, so I left it blank for now.
litherum added a commit to litherum/csswg-drafts that referenced this issue Sep 10, 2021
This is for w3c#520.

The [resolution](w3c#520 (comment)) is:

> RESOLVED: [add this functionality to] css-font-loading, level TBD

I added this to level 3, because level 4 doesn't exist. If the editor prefers this go in a level 4, that's no problem.

The GitHub thread hasn't come to a conclusion about what should go in the `FontFaceFeatures` interface, so I left it blank for now.
litherum added a commit to litherum/csswg-drafts that referenced this issue Sep 10, 2021
This is for w3c#520.

The [resolution](w3c#520 (comment)) is:

> RESOLVED: [add this functionality to] css-font-loading, level TBD

I added this to level 3, because level 4 doesn't exist. If the editor prefers this go in a level 4, that's no problem.

The GitHub thread hasn't come to a conclusion about what should go in the `FontFaceFeatures` interface, so I left it blank for now.
litherum added a commit to litherum/csswg-drafts that referenced this issue Sep 10, 2021
This is for w3c#520.

The [resolution](w3c#520 (comment)) is:

> RESOLVED: [add this functionality to] css-font-loading, level TBD

I added this to level 3, because level 4 doesn't exist. If the editor prefers this go in a level 4, that's no problem.

The GitHub thread hasn't come to a conclusion about what should go in the `FontFaceFeatures` interface, so I left it blank for now.
litherum added a commit that referenced this issue Sep 10, 2021
This is for #520.

The [resolution](#520 (comment)) is:

> RESOLVED: [add this functionality to] css-font-loading, level TBD

I added this to level 3, because level 4 doesn't exist. If the editor prefers this go in a level 4, that's no problem.

The GitHub thread hasn't come to a conclusion about what should go in the `FontFaceFeatures` interface, so I left it blank for now.
@litherum
Copy link
Contributor Author

litherum commented Sep 10, 2021

Alright, I've landed the initial draft into the spec: 96c35c2 and I've left FontFaceFeatures blank because it seems like we haven't come to consensus on that.

I've split out individual issues for this functionality:

  1. [css-font-loading] [info discovery] Populate FontFaceFeatures #6596
  2. [css-font-loading] [info discovery] FontFaceVariationAxis.name exposes system locale #6595
  3. [css-font-loading] [info discovery] Consider using ObservableArray instead of iterable #6594
  4. [css-font-loading] [info discovery] iterable doesn't tell you what index you are at #6593
  5. [css-font-loading] [info discovery] FontFaceSet uses size but FontFacePalettes/FontFacePalette use length #6597
  6. [css-font-loading] [info discovery] There is no consideration for elements #6598
  7. [css-font-loading] [info discovery] Named instances should be discoverable too #6599

So I think we can probably close this issue, and continue on individual issues. If I've missed any issues which were raised in this thread, please either file it directly, or let me know so I can file it.

@litherum
Copy link
Contributor Author

I'll give people a few days to comment if I've messed anything up. Hearing nothing, I'll close this some time next week.

@arnog
Copy link

arnog commented Sep 11, 2021

Does (1) #6596 cover access to the OpenType 'MATH' table?

@litherum
Copy link
Contributor Author

Does (1) #6596 cover access to the OpenType 'MATH' table?

No, it doesn't. I've filed #6686 about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests