Last updated 2016/02/28.
I spent a considerable amount of time researching this and wrestling with it.
After digging around as best I could, the top solutions for now are:
@supports
Take advantage of the @supports
rule in browsers. This is what I initially
opted to do on this project.[1] You use the rule this way:
.some-class {
font-variant: small-caps;
}
@supports(font-feature-settings: 'smcp') {
.some-class {
font-variant: normal;
font-feature-settings: 'smcp';
}
}
I've simplified by leaving out the prefixed versions; you'll need to add the
-webkit-
and -moz-
prefixes to get this actually working. Update,
2012/02/28: you no longer need the -moz-
prefix, and this will work in
Safari in the next release (iOS 9.3 and OS X Safari 9.1).
This has the advantage that support for real small caps and
support for the @supports
rule are very similar:
@supports
: Can I Use Feature Queries?: Chrome 31+, Firefox
29+, Opera 23+, Android 4.4+, Safari 9+, Edge 12+, Chrome for Android
Update, 2016/02/28: as the chart linked above will make clear, all
evergreen browsers now have @supports
support.
font-feature-settings
: Using Small Caps & Text Figures on the Web:
Chrome, Firefox, IE10+
This isn't perfect: since IE10/11 don't implement @supports
, you miss one
browser. (Edit, 2015/09/31: IE proper doesn't have @supports
, but Edge 12+
does, and that should increasingly cover all consumer users of the site.)
Still, this gets you most of the way there, and it should be future-facing: this
should progressively enhance the site nicely. The normal (bad, but functional)
small caps are displayed in the meantime, and when browsers eventually get
around to using OpenType small caps by default for font-variant: small-caps
,
this will continue to work just fine. It's "progressive enhancement" and it'll
work nicely for most purposes.[2]
Typeface subsetting
As mentioned in the question, one can create a subset of the typeface that
includes only small capitals. This is what I have done for the small caps on my
own website; see the first line of the first
paragraph in this post for an example.
To pull this off, you'll need to start by subsetting the typeface. You can do
this manually with a font tool, or (the simpler way) you can use FontSquirrel's
custom subsetting tool in their webfont generator. (Note: You
must check the license and confirm that the typeface in question allows this
kind of modification. See below.) In the web font generator, first upload the
file you wish to modify. Then choose the Expert radio button. Most of the
settings you can leave as they are; they're good sane defaults. Midway down the
page you'll see OpenType Flattening options. Here, select only "Small Caps".
Run the generator. The result will be a complete replacement of the normal
lowercase letters with the small caps set.[3]
In that case, you can simply apply a style to the elements you want to have
small capitals, e.g.:
.divine-name {
font-family: 'my_typeface_smcp', 'my_typeface', serif;
}
The major advantage to this approach is consistency: that typeface is going to
display on every browser out there, back to IE5.5, as long as you deliver it
correctly using the various hooks required by @font-face
.
There are a few disadvantages to this approach, though:
It means delivering another font file. In my case, this would be an
acceeptably low size (since I actually only need four characters), but it's
still something to consider in general. It is in any case another HTTP
request, which is going to further slow the page load time or at least give
you some flash of unstyled text when it reloads.
It may violate the licenses of the typefaces in question. For at least one
of the fonts I am using on this project, it does: the license explicitly
forbids rebuilding the font using tools like FontSquirrel. (FontSquirrel was
the tool I used for this approach before, and it works quite well.) This is
a make-or-break issue for using a subset of a typeface to accomplish the
goal. That being said, if you have a good reason to do it, you may be able
to get support from the vendor (especially if they're a small shop). For the
project that prompted this question, I was able to do just that with a nice
email—the designer is a great guy.
The other major reason not to do it this way is that it has a significantly
higher maintenance cost. If at any point you need to change or update the
typeface, you have to go through the subsetting process all over again. By
contrast, the first option will simply work, though admittedly not as
pleasantly as one might hope, and will not only continue to work but will
actually improve over time as browsers increase their implementation of the CSS3
standard.
Notes
For various reasons (especially see note 2 below), I actually opted for the
second approach outlined here, which is the same approach I was trying to
avoid. Alas.
Issues remain: even in the latest Chrome (38 as of the time of this
edit), using the font-feature-settings: 'smcp'
approach has some
issues. For example, if you turn on letter-spacing
(a fairly common
recommendation for small caps), the small caps will revert
to normal lowercase letters. Fixed in Chrome 48. HT to answerer
below.
From the FontSquirrel blog post that introduced the feature:
If you have a font with OpenType features, you can now flatten some of
them into your webfont. For instance, some fonts have small caps built in,
but they are completely inaccessible in a web browser. By selecting the
"Small Cap" option, the Generator will replace all the lowercase glyphs
with the small cap variants, giving you a small cap font. Please note that
not all OpenType features are supported and if the font lacks OpenType
features, using these options won't create them.
font-variant: small-caps
should use the font's baked in small caps, if present, so you shouldn't need to turn on thesmcp
feature, basic CSS should already do the right thing. – Limpetfont-variant
has the downside at present that it doesn't use actual small capitals; it just downscales the capitals. From a typography perspective, this is obnoxious and always has been. @Mike'Pomax'Kamermans, that's true in theory, but it doesn't work on any browser I've tested, and the MDN pages report the same—no support for it. Vendors appear to be supporting only the low-level handles (e.g.'smcp'
) until the CSS3 spec is finalized, not supporting high-level declarations (so nofont-variant-ligatures
, either, and so on). – Girish