Características de OpenType: font-variant frente a font-feature-settings
Qué es una feature y quién decide que exista, por qué las propiedades font-variant cascadean y la lista no, y las características que de verdad arreglan una interfaz.
Dentro de una fuente hay tablas que describen sustituciones y posicionamientos condicionales: cambia estas dos letras por esta ligadura, usa estas cifras en lugar de aquellas, aprieta este par. Se identifican con etiquetas de cuatro letras y CSS las expone por dos vías con exactamente la misma asimetría que los ejes variables: una lista de bajo nivel que no cascadea y un conjunto de propiedades de alto nivel que sí.
- Explicar qué es una característica de OpenType y quién la define.
- Justificar por qué
font-feature-settingssufre el mismo problema que la lista de ejes. - Aplicar cifras tabulares donde arreglan un problema de layout real.
- Descubrir qué características trae una fuente concreta.
Qué es una característica y quién decide que exista
Una característica es una regla guardada en la fuente, en las tablas de sustitución y de posicionamiento. Cada una tiene una etiqueta de cuatro letras y una definición estandarizada de qué debe hacer, pero la implementa el tipógrafo o no la implementa: activar smcp en una fuente sin versalitas dibujadas no hace nada.
Algunas están activas por defecto en cualquier motor: el kerning, las ligaduras comunes, las alternativas contextuales, la composición de diacríticos. Otras están apagadas y hay que pedirlas.
| etiqueta | qué hace |
|---|---|
kern |
ajusta el espacio entre pares concretos, activa por defecto |
liga |
ligaduras comunes, activa por defecto |
dlig |
ligaduras discrecionales, apagada |
tnum |
cifras de ancho fijo |
pnum |
cifras de ancho proporcional |
onum |
cifras elzevirianas, con ascendentes y descendentes |
lnum |
cifras de altura de mayúscula |
zero |
cero barrado |
frac |
fracciones compuestas |
smcp |
versalitas |
case |
puntuación ajustada a mayúsculas |
ss01 a ss20 |
conjuntos estilísticos definidos por el tipógrafo |
Las dos vías
font-feature-settings toma una lista completa:
.texto { font-feature-settings: 'tnum' 1, 'zero' 1; }
Y sufre exactamente el problema de la lista de ejes variables: es una sola propiedad con un valor de lista, así que no cascadea característica a característica. Un descendiente que declare font-feature-settings: 'onum' 1 pierde tnum y zero, aunque no los mencione.
Peor todavía, hay un efecto que sorprende: declarar la lista desactiva las características que el navegador tenía activas por su cuenta si no las incluyes. En la práctica los motores conservan las activas por defecto, pero el modelo mental correcto es que estás sustituyendo la configuración entera.
Las propiedades font-variant-* son la vía de alto nivel: propiedades independientes que cascadean, se heredan y se sobrescriben por separado.
.tabla { font-variant-numeric: tabular-nums lining-nums; }
.tabla .id { font-variant-numeric: tabular-nums slashed-zero; }
La familia completa: font-variant-numeric, font-variant-ligatures, font-variant-caps, font-variant-position, font-variant-east-asian, font-variant-emoji y font-variant-alternates.
La regla es la misma que con los ejes: usa font-variant-* siempre que exista la propiedad, y reserva font-feature-settings para lo que no tiene equivalente, que en la práctica son los conjuntos estilísticos ss01 a ss20 y las características que el tipógrafo haya inventado.
/* correcto: solo lo que no tiene propiedad de alto nivel */
.marca { font-feature-settings: 'ss02' 1; }
Las características que cambian una interfaz
Cifras tabulares. Esta es la que más impacto tiene y la que menos se conoce. En una fuente proporcional, el 1 es más estrecho que el 8, así que un número que cambia —un contador, un cronómetro, un precio que se actualiza, una columna de importes— cambia de anchura y todo lo que hay al lado da saltos.
.cronometro,
.precio,
td.numero {
font-variant-numeric: tabular-nums;
}
Una línea, y el temblor desaparece. Es el arreglo correcto para un problema que la gente resuelve con min-width a ojo, con una fuente monoespaciada solo para los números, o con relleno de ceros.
Cero barrado. En referencias, códigos e identificadores, distinguir el cero de la O mayúscula deja de ser un ejercicio de contexto.
code, .codigo-producto { font-variant-numeric: slashed-zero tabular-nums; }
Cifras elzevirianas en texto corrido. Las cifras de altura de mayúscula interrumpen la línea en un párrafo; las elzevirianas, con ascendentes y descendentes, se integran con las minúsculas.
article p { font-variant-numeric: oldstyle-nums proportional-nums; }
Ligaduras fuera del código. Las ligaduras contextuales de una fuente de programación —la flecha, el distinto de— son útiles en un editor y confusas dentro de un bloque de código de una página, porque cambian los caracteres que el lector va a copiar.
pre code { font-variant-ligatures: none; }
Puntuación ajustada a mayúsculas. En un texto todo en mayúsculas, los paréntesis y los guiones diseñados para minúsculas quedan bajos.
.rotulo { text-transform: uppercase; font-feature-settings: 'case' 1; }
Descubrir qué trae tu fuente
Ninguna característica funciona si la fuente no la implementa, y la documentación del proveedor suele ser incompleta. La lista real está en las tablas de sustitución:
python3 -m fontTools.ttx -t GSUB -o - fuente.woff2 | grep -o 'FeatureTag value="[a-z0-9]*"' | sort -u
Y para el kerning y el posicionamiento, la tabla GPOS. Hay también páginas web que suben la fuente y listan sus características con una muestra de cada una, que para explorar es más cómodo.
Un detalle práctico: si has subconjuntado la fuente, comprueba la lista después del subsetting, porque la opción de características de pyftsubset puede haber eliminado justo la que quieres usar.
El caso de las cifras tabulares merece una lectura más general, porque es un ejemplo perfecto de un patrón que se repite por todo el desarrollo de interfaces: un síntoma aparece en una capa y su causa vive en otra, y quien solo conoce la capa del síntoma acaba construyendo una solución que funciona y no debería existir. El contador que tiembla se ve como un problema de layout, así que se resuelve con layout: un ancho mínimo calculado a ojo, un contenedor de ancho fijo, una fuente monoespaciada solo para ese elemento, en los casos más tristes un componente entero que renderiza cada dígito en su propia caja. Todas esas soluciones funcionan, todas añaden complejidad permanente, y todas se vuelven incorrectas cuando cambia el tamaño o la fuente. La causa real —los avances de los glifos numéricos son distintos— vive en la fuente, y la fuente ya trae la solución dentro, esperando una declaración. El hábito que hay que cultivar es preguntarse, ante cualquier arreglo que parezca desproporcionado para el problema, si el problema está de verdad en la capa donde se está mirando. En tipografía la respuesta es que no sorprendentemente a menudo, porque una fuente moderna es un programa con más funcionalidad de la que la mayoría de los desarrolladores sospecha.