W3C home > Mailing lists > Public > www-style@w3.org > June 2009

advanced font features in CSS

From: John Daggett <jdaggett@mozilla.com>
Date: Mon, 29 Jun 2009 00:51:34 -0700 (PDT)
To: www-style <www-style@w3.org>
Message-ID: <18519188.395351246261894555.JavaMail.root@cm-mail01.mozilla.org>
Below is a proposal for supporting in CSS advanced font features found
in OpenType and AAT fonts.  Supporting features available in "smart
font" formats like OpenType and AAT presents a quandary, there are lots
and lots of features and the list is constantly evolving.  The proposal
below is an attempt to capture some of these without producing an
explosion in the number of CSS properties.  As much as possible, the
features are grouped to try and make their use intuitive but it's
assumed that the mapping onto underlying OpenType/AAT features will need
to be normative, without it interoperability would be almost impossible.
For comparison, see the link below describing WPF OpenType feature

At this point I think the actual property names and values are less
important than whether the set of underlying OpenType features is
sufficient/appropriate.  Are there OpenType features omitted here that
should really be exposed for authors?  Or limitations that are
unfortunate?  For example, OpenType allows distinct sets of glyphs with
a common style to be specified independently but the 'styleset' value
defined here is associated with a single numeric value, so only one of
these stylesets could be applied at a time.

OpenType also contains many language-specific features; some of these
are best left to the control of the shaping engine using them.  Others,
such as the CJK related glyphset and width properties listed below seem
like interesting candidates for inclusion but I'm still unsure of the
exact set of properties/values that are supported currently.

Overall shorthand

The font-variant property is extended to be a shorthand for all the
properties below.  Values that don't seem to fit into a separate
property are added here.  The 'normal' keyword resets all properties
below and any specification of values resets features whose value was

font-variant: normal | [<ligature-values> | <alternate-values> | <caps-value> | <numeric-values> | <char-position-value>]+ ;
font-variant-ligatures: normal | <ligature-values> ;
font-variant-alternates: normal | <alternates-values> ;
font-variant-caps: normal | <caps-value> ;
font-variant-numeric: normal | <numeric-values> ;
font-variant-position: normal | <char-position-value> ;

Each of the font-variant-xxx properties above allows for a specific
subset of features to be overridden.  In cases where multiple values
that are mutually exclusive are listed, the last value is used.  Other
than 'small-caps', these properties are not involved with the font
matching process, they are applied as rendering properties; if a font
lacks support for a given feature, default rendering takes place.

OpenType is sensitive to language when font features like ligatures are
enabled.  For example, in Turkish the fi ligature is typically disabled
so that the distinction with the dotless-i is clear.  It would make
sense for user agents to map document language to OpenType language but
this is probably somewhat tricky to do normatively.

Some feature selections only apply to a single font.  Swashes and
styleset values are defined differently across fonts, so applying those
values across fonts would not always give the intended result.  One way
of allowing per-face control would be to define the font-variant
descriptor within @font-face rules to imply font feature settings for a
single face:

  @font-face {
    font-family: Rebus;
    src: url(xxx);
    font-variant: contextual; /* enable calt only for this font */

Using src local(), this could be applied to individual locally available
font faces although this is somewhat awkward.  The descriptor value
would apply on top of values specified through font properties.

Value definitions are listed below along with the intended mapping to
OpenType and AAT feature settings.


  <ligature-values> :== [common-ligs | additional-ligs | historical-ligs | no-common-ligs | no-additional-ligs | no-historical-ligs]+
where these keywords imply the following underlying features

  normal: clears all features below, uses font defaults
  common-ligs: liga (OT), ligatures = common (AAT)
  additional-ligs: dlig (OT), AAT?
  historical-ligs: hlig (OT), ligatures = rare (AAT)
  no-xxx: disables features above

mutually exclusive values:

  (common-ligs, no-common-ligs) (additional-ligs, no-additional-ligs) (historical-ligs, no-historical-ligs)
Note: no control over rlig, required ligatures, since this should be
under the control of the shaping engine.  Should "common" ligatures be
labeled another way?  "default"?

Alternates and Swashes
  <alternates-values> :== [alternates <number> | contextual | no-contextual | styleset <number> | swash <number> | random-alternates]+

where these keywords imply the following underlying features

  normal: clears all features below, uses font defaults
  alternates: salt(number) (OT), character alternatives = number (AAT)
  contextual: calt, clig (OT), not in AAT
  no-contextual: disable feature above
  random-alternates: rand (OT), not in AAT
  styleset: ss## where ## = number (OT), design complexity = number (AAT)
  swash: swsh(number), cswh(number) (OT), AAT?
mutually exclusive values:

  (contextual, no-contextual)


  <caps-value> :== small-caps | petite-caps | titling-caps
where these keywords imply the following underlying features

  normal: clears all features below, uses font defaults
  small-caps: smcp (OT), letter case = small caps (AAT)
  petite-caps: pcap (OT), not in AAT
  titling-caps: titl (OT), style options = titling caps (AAT)
All capitalization values are mutually exclusive.
Numeric styles

This is relatively easy to define, both AAT and OpenType have these
features, although with fractions there's some interaction with other
features (numr/dnom).  Not sure if there would be feature interactions
when rendering MathML for example.

These properties all relate to numerics but it may make sense to split
out fractions, since these are typically to specific values and not to
overall runs of text.

  <numeric-values> :== [<number-style> | <number-width> | <fraction> | slashed-zero]+

  <number-style> :== [lining-nums | oldstyle-nums]
  <number-width> :== [proportional-nums | tabular-nums]
  <fraction>     :== [diagonal-fractions | stacked-fractions]
and these keywords imply the following underlying features

  normal: clears all features below, uses font defaults
  lining-nums: lnum (OT), number case = upper case (AAT)
  oldstyle-nums: onum (OT), number case = lower case (AAT)
  proportional-nums: pnum (OT), number spacing = proportional (AAT)
  tabular-nums: tnum (OT), number spacing = monospaced (AAT)  
  diagonal-fractions: frac (OT), fractions = diagonal
  stacked-fractions: afrc (OT), fractions = stacked
  slashed-zero: zero (OT), AAT?

mutually exclusive values:

  (lining-nums, oldstyle-nums) (proportional-nums, tabular-nums) (diagonal-fractions, stacked-fractions)
Character position

  <char-position-value> :== inferior | ordinal | ruby | subscript | superscript

and these keywords imply the following underlying features

  normal: clears all features below, uses font defaults
  inferior: sinf (OT), vertical position = inferiors
  ordinal: ordn (OT), vertical position = ordinals
  ruby: ruby (OT), AAT?
  subscript: subs (OT), vertical position = inferiors
  superscript: supr (OT), vertical position = superiors 

All character position values are mutually exclusive.

Other properties still under investigation

  font-variant-east-asian: normal | [<char-variant-value> | <char-width-value>]+ ;
  <char-variant-value> :== hojo-kanji | jis04 | jis78 | jis83 | jis90 | nlckanji | simplified | traditional | traditional-names
  <char-width-value>   :== full-width | half-width | third-width | quarter-width | proportional


Håkon's proposal for extending font-variant to make it a shorthand
property for a set of font-variant-xxx properties:


Interesting comments on www-style from Sergey Malkin, who worked on
Uniscribe and WPF at Microsoft:


A more extensive, slightly different proposal was posted by Etan Wexler
a few months later:


OpenType feature list:

AAT font feature registry:

WPF api for OpenType features:

Flash 10 API (see ElementFormat):
Received on Monday, 29 June 2009 07:52:19 UTC

This archive was generated by hypermail 2.4.0 : Friday, 25 March 2022 10:07:37 UTC