Saltar al contenido
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
Primeros pasosWebReactSwiftUIJetpack ComposeFlutterReact NativePreajustesTu propio sistema de diseñoUsar Tanrei con agentes de IAMarcaTokens de diseñoSistemas de diseño y personalizaciónTheme StudioColorTipografíaIconosFormaElevaciónMovimientoEstados de interacciónComportamientoDiseño de páginaAccesibilidadTextosTokens de colorTokens de la escala tipográficaTokens de formaTokens de elevaciónTokens de movimientoTokens de estadoTokens de espacio y de medidaComponentesBotónBotón de acción principalBotón segmentadoGrupo de botonesBotón con menúBarra de herramientasBotón de copiarCasilla de verificaciónBotón de opciónInterruptorChipMenúControl deslizanteCampo de control deslizanteCalendarioDateTimePickerGrupo de camposGrupo de botones de opciónGrupo de casillas de verificaciónSelectCampo de selecciónBarra de menúsSubida de archivosSelector de archivos AvanzadoZona de soltar archivosEntrada de texto AvanzadoCampo de textoCampo de chipsCampoCuadro combinado AvanzadoCampo de cuadro combinadoEntrada numérica AvanzadoCampo numéricoEntrada de color AvanzadoCampo de colorEntrada de código de un solo uso AvanzadoCampo de código de un solo usoEntrada de texto incrustada AvanzadoCuadro de redacción de chatTarjetaDivisorCapa modal AvanzadoDiálogoListaFila de listaHoja inferiorHoja lateralCarruselBloque de códigoTablaPopoverPasosAcordeónLista de descripcionesFiguraEstructura de la aplicaciónCabecera de páginaVista de árbolLínea de tiempoVista previa de imágenesTirador de tamañoMarco redimensionableÁrea de desplazamientoInsigniaIndicador de progresoMedidorContador animadoIndicador de cargaSnackbarTooltipAtajo de tecladoTagCódigo en líneaCalloutAvatarEstado vacíoGrupo de tagsEsqueletoElemento de archivoMuestraTexto en marquesinaPestañasVista de pestañasBarra de la aplicaciónBarra de navegaciónPanel de navegaciónBúsquedaEnlacePaginaciónEnlaces anterior y siguienteIndicador de pasosRuta de navegaciónTabla de contenidoTarjeta de enlaceMenú FABEstadoCómo se construye TanreiCómo contribuirLicencia y atribución
InicioFundamentosTipografía

Tipografía

Dieciséis estilos de texto nombrados por nivel (un display, seis títulos, tres tamaños de cuerpo, etiquetas, código y un antetítulo), compuestos en Inter, con el énfasis como un paso de peso y no como un rol.

content_copyVer en Markdown

Los estilos de texto de Tanrei se nombran por el nivel que un texto tiene en una página, no por una clase de tamaño. Hay dieciséis roles: un display, de heading-1 a heading-6, tres tamaños de texto corrido, tres roles para el texto que va dentro de los controles y junto a ellos, dos para código y un eyebrow. Un h2 es heading-2; un párrafo es body; el texto de un botón es label. Nadie tiene que recordar cuál de tres roles de catorce píxeles corresponde al encabezado de una tabla.

Un rol es un estilo tipográfico completo: familia, tamaño, peso, interlineado y espaciado entre letras. Los componentes se vinculan a roles, nunca a tamaños en bruto, y una capa da nuevos valores a un rol sin cambiarle el nombre.

Los dieciséis roles

Rol Valor predeterminado Uso
display 48px · 450 · tipo de marca El único tamaño de cabecera: el mensaje de una pantalla de inicio, una pantalla de bienvenida. No es un nivel de título.
heading-1 32px · 500 · tipo de marca h1, el título de la página.
heading-2 24px · 500 · tipo de marca h2, una sección.
heading-3 20px · 500 · tipo de marca h3, una subsección.
heading-4 18px · 500 h4, un grupo dentro de una sección.
heading-5 16px · 500 h5, y el título de una tarjeta, de un diálogo o de un elemento de lista.
heading-6 14px · 500 h6, y el encabezado de una tabla o de una sección de formulario.
body-large 16px · 400 Texto de entrada y lectura larga.
body 14px · 400 p: el texto predeterminado de una interfaz.
body-small 13px · 400 small: texto secundario, un paso por debajo.
label 14px · 500 Texto dentro de los controles y junto a ellos: botones, campos de entrada, navegación.
label-small 12px · 500 Chips, insignias, controles densos.
caption 11px · 500 Texto de ayuda, metadatos, marcas de tiempo.
code 13px · 400 · mono code y pre.
code-small 12px · 400 · mono Código dentro de una interfaz densa.
eyebrow 12px · 500 · con espaciado entre letras El antetítulo de una sección, encima de un título; el componente lo pone en mayúsculas.

Cada familia es estrictamente monótona en tamaño: ningún título es más pequeño que el título del nivel siguiente, y ningún rol de cuerpo es más pequeño que el rol de cuerpo siguiente. Donde un título y un rol de cuerpo comparten tamaño (heading-6 y body miden ambos 14px; heading-5 y body-large, ambos 16px), la regla del sistema predeterminado cabe en una frase: los títulos pesan 500, el cuerpo pesa 400. Un preajuste define sus propios pesos (el heading-1 de m3-like es el 400 de Material).

Elige el nivel que tiene el texto, no el tamaño que quieres. Un h2 que debe verse pequeño sigue siendo heading-2; un producto que quiere títulos de sección más pequeños da un nuevo valor a heading-2 en su capa, y todos los h2 lo siguen.

Elementos de HTML y Markdown → roles

Elemento Rol
h1 … h6 heading-1 … heading-6
p, li, td body (body-large en la prosa con su tamaño de lectura)
Un párrafo de entrada body-large
small body-small
code, pre code
strong, b el rol en el que se encuentra, con el peso de énfasis
button, input, label label
Un antetítulo encima de un título eyebrow

En la web, @tanrei/web/text.css da a cada rol una clase de utilidad, .tanrei-text-<role>, que define los cinco campos del rol; .tanrei-text-emphasized, en el mismo elemento o en un descendiente, cambia al peso de énfasis. Lee las propiedades personalizadas del sistema activo, así que sigue a data-tanrei-system, a los diales y a un rol con nuevos valores.

<h2 class="tanrei-text-heading-2">Sección</h2>
<p class="tanrei-text-body">Texto corrido con <strong class="tanrei-text-emphasized">énfasis</strong>.</p>

Prosa: el texto que no has maquetado tú

Un artículo de ayuda, unas notas de versión, unas condiciones, un mensaje escrito en Markdown, una página de un CMS: el producto no coloca ese texto pieza a pieza, y aun así tiene que leerse como un mismo texto con el resto de la interfaz. La prosa es la parte del sistema que se ocupa de ello: la tabla anterior aplicada a lo que produzca un renderizador, con un único ritmo vertical y un límite para la longitud de línea. Da estilo y espacio; no analiza. Tanrei no incluye un analizador de Markdown en ninguna plataforma.

En la web es una clase de @tanrei/web/prose.css. Esta página está dibujada con ella.

<article class="tanrei-prose">…h1, p, ul, blockquote, hr…</article>
<article class="tanrei-prose" data-size="large">…</article>
  • Dos tamaños. medium compone el texto corrido en body, para la prosa entre controles: un panel, un diálogo, una tarjeta. large lo compone en body-large, para una página cuyo propósito es el texto. Los títulos son los mismos en ambos.
  • Un solo espacio entre dos vecinos. Los bloques están separados por un espacio; un título tiene más espacio antes que después, de modo que pertenece a lo que le sigue; un título que va justo debajo de otro toma el espacio del de arriba. Los espacios nunca se suman, y el primer bloque y el último no tienen ninguno.
  • Una medida. Los bloques de texto miden como máximo 36 em del texto corrido de ancho: entre unos 72 y 80 caracteres latinos, o 36 japoneses. Una tabla, un bloque de código, una figura o cualquier componente colocado en el flujo ocupa todo el ancho. data-measure="false" levanta el límite donde el contenedor ya es estrecho.
  • Sin color de texto. La prosa toma el color de contenido de la superficie sobre la que está, así que el mismo texto se lee en una página, en una tarjeta y en un aviso.
  • Los componentes siguen siendo ellos mismos. Lo que está dentro de un elemento de Tanrei, o dentro de una parte marcada con tanrei-not-prose, no recibe estilo de la prosa; la prosa solo lo espacia.
  • Los enlaces van subrayados en reposo, para que el color por sí solo nunca sea lo que distingue un enlace del texto que lo rodea.
  • Idiomas. Las líneas en japonés y en chino se dividen según sus propias reglas; el énfasis en chino, japonés y coreano es recto y con el peso de énfasis, porque esas escrituras no tienen cursiva; sus títulos, y el título de cada componente, se componen sin el espaciado entre letras negativo de los títulos latinos (uno positivo se mantiene), y una escritura que une sus letras o apila marcas sobre ellas no lleva ningún espaciado entre letras. El texto corrido en japonés se compone más suelto, con un interlineado de 1,85, de modo que el espacio entre dos líneas se acerca a un carácter, como recomiendan los requisitos de composición japonesa (JLREQ) para líneas tan largas como la medida. La dirección es la del lugar: un diseño de derecha a izquierda pone a la derecha las sangrías de las listas, la línea de una cita y el borde del texto.

Un título puede llevar un ancla: un enlace a sí mismo, después del final de su texto, que se muestra cuando el cursor pasa por el título o el enlace tiene el foco, y que se muestra siempre donde no hay cursor:

<div class="tanrei-prose-heading">
  <h2 id="install">Instalación</h2>
  <a class="tanrei-prose-anchor" href="#install" aria-label="Enlace a: Instalación">…</a>
</div>

Cada valor es un token comp.prose.*, así que una capa puede reorientar el ritmo sin tocar un margen. El comportamiento está escrito en specs/prose.spec.json; la web lo implementa primero, y las demás plataformas la siguen.

El énfasis es un peso, no un rol

Para destacar un texto sin cambiar su nivel (la pestaña seleccionada, una cifra clave, un strong dentro de un párrafo), una plataforma dibuja el rol con su peso más un paso propio de su familia. Los cuatro pasos son tokens:

Sistema de diseño emphasis.display emphasis.heading emphasis.body emphasis.label
tanrei 100 100 100 100
cupertino 100 200 200 200
m3-expressive-like 100 100 100 200
m3-like 100 100 100 200

Generado a partir de tokens/systems/*.system.json, design/tokens/<system>/tanrei.light.tokens.json

Tanrei suma 100 a todas las familias, así que un heading-1 con énfasis es 600 y un body con énfasis es 500. Un sistema de diseño que destaca de forma distinta según la familia define los cuatro números: m3-like suma 200 a las etiquetas, como hacen los estilos de etiqueta con énfasis de Material; cupertino suma 200 a los títulos, al cuerpo y a las etiquetas. La familia de un rol es el primer segmento de su nombre; caption, code, code-small y eyebrow toman el paso de las etiquetas.

Todas las plataformas exponen el mismo modificador: emphasized en la API de estilos de texto (.tanreiTextStyle(system.typescale.heading1, emphasized: true) en SwiftUI; typescale.heading1.emphasized() en Compose, o emphasized(system.typescale.emphasis) fuera de la composición; theme.textStyle(system.typescale.heading1, emphasized: true) en Flutter; text('heading1', { emphasized: true }) de useTanrei() en React Native; --tanrei-sys-typescale-<role>-font-weight-emphasized y .tanrei-text-emphasized en la web). No hay roles con énfasis que nombrar ni una segunda escala que mantener al día.

Tipos de letra

Las familias predeterminadas son Inter para el texto latino, Noto Sans JP para el japonés y Roboto Mono para el código, todas con licencia abierta (SIL OFL 1.1 y Apache-2.0). La pila continúa con Noto Sans para otras escrituras y después con la fuente de interfaz del sistema, así que el texto se degrada con elegancia donde las fuentes no están cargadas. Un producto que se publica en más escrituras añade a la pila, en su capa, la familia Noto de cada una (Noto Sans KR, SC, TC, Arabic, Devanagari, Thai); para el chino, el japonés y el coreano, define también lang en la página, porque los tres comparten puntos de código y el orden de las fuentes decide qué formas de glifo aparecen. Tanrei no incluye archivos de fuentes; los aporta el producto.

ref.typeface.brand
Display and headline text. Inter for Latin, Noto Sans JP for Japanese, Noto Sans for other scripts; a product adds the Noto family of each further script it ships (Noto Sans KR, SC, TC, Arabic, Devanagari, Thai…).
ref.typeface.plain
Running text and labels. Inter for Latin, Noto Sans JP for Japanese, Noto Sans for other scripts.
ref.typeface.mono
Code. Roboto Mono, with Noto Sans JP for Japanese inside code.

Generado a partir de tokens/ref/typeface.tokens.json

Tipos de letra por sistema de diseño

Los tipos de letra pertenecen al sistema de diseño. Los roles se construyen sobre tres pilas (ref.typeface.brand para display y de heading-1 a heading-3; plain para los títulos más pequeños, el texto corrido, las etiquetas y el antetítulo; mono para el código), y una capa cambia el tipo de letra en todas partes dando un nuevo valor a una pila. Esto es lo que resuelven los sistemas incluidos:

Sistema de diseño brand plain mono
tanrei Inter, Noto Sans JP, Noto Sans, system-ui, sans-serif Inter, Noto Sans JP, Noto Sans, system-ui, sans-serif Roboto Mono, Noto Sans JP, ui-monospace, monospace
cupertino -apple-system, BlinkMacSystemFont, system-ui, Inter, sans-serif -apple-system, BlinkMacSystemFont, system-ui, Inter, sans-serif ui-monospace, SF Mono, Menlo, monospace
m3-expressive-like Roboto, system-ui, sans-serif Roboto, system-ui, sans-serif Roboto Mono, ui-monospace, monospace
m3-like Roboto, system-ui, sans-serif Roboto, system-ui, sans-serif Roboto Mono, ui-monospace, monospace

Generado a partir de tokens/systems/*.system.json, design/tokens/<system>/tanrei.light.tokens.json

Así es como m3-like compone su texto en Roboto:

"tokens": {
  "tanrei.ref.typeface.brand": { "$value": ["Roboto", "system-ui", "sans-serif"], "reason": "El tipo de letra predeterminado de Material Design 3; Roboto tiene licencia OFL." },
  "tanrei.ref.typeface.plain": { "$value": ["Roboto", "system-ui", "sans-serif"], "reason": "El tipo de letra predeterminado de Material Design 3; Roboto tiene licencia OFL." },
  "tanrei.ref.typeface.mono":  { "$value": ["Roboto Mono", "ui-monospace", "monospace"], "reason": "El compañero monoespaciado de Roboto (OFL)." }
}

Los componentes no se tocan: se vinculan a roles, y los roles hacen referencia a las pilas.

Cómo se lee una pila

Una pila se escribe como la escribe CSS, porque esa es la forma que entiende toda herramienta de diseño. Solo la web puede usarla tal como está escrita, así que la compilación lee cada pila una vez y entrega a todas las plataformas los mismos cuatro datos:

Campo Significado
stack la lista tal como está escrita
families las familias con nombre, en orden: las que un producto puede instalar o registrar
generic la clase de fuente a la que se recurre: sans-serif, serif o monospace
system true cuando la pila pide la fuente propia de la plataforma antes que cualquier familia con nombre

La pila brand predeterminada, Inter, Noto Sans JP, Noto Sans, system-ui, sans-serif, se lee como las familias Inter, Noto Sans JP y Noto Sans, generic sans-serif y system false: system-ui viene después de las familias con nombre, así que es solo el recurso final. La pila de cupertino empieza por -apple-system, así que se lee como system true con Inter como única familia con nombre: primero la fuente propia de la plataforma, e Inter donde una plataforma no tiene tal noción.

Una plataforma usa las familias con nombre en orden y, después, su propia fuente de la clase generic; cuando system es true, su propia fuente va primero. Las plataformas no interpretan por sí mismas system-ui, ui-monospace ni las palabras clave genéricas.

Referenciados por nombre, nunca incluidos

Tanrei no distribuye archivos de fuentes, para ningún sistema de diseño. Una pila es una lista de nombres, y el producto aporta las fuentes que hay detrás de los nombres que quiere. Una familia que no está se omite, así que el texto se sigue representando con la familia siguiente o con la fuente de la plataforma, sin cambios en el tamaño, el peso, el interlineado ni el espaciado entre letras del rol.

Plataforma Cómo aporta un producto una familia con nombre
Web Cárgala con exactamente ese nombre de familia: tu propio @font-face, Google Fonts o un paquete de fuentes.
SwiftUI Añade los archivos de fuentes a la aplicación y regístralos (UIAppFonts / ATSApplicationFontsPath, o CTFontManagerRegisterFontsForURL).
Jetpack Compose Coloca las fuentes en los recursos de fuentes de la aplicación y asócialas a los nombres con TanreiFontFamilies, que se pasa a TanreiTheme.
Flutter Declara los archivos de fuentes en el pubspec.yaml de la aplicación con los mismos nombres de familia.
React Native Enlaza los archivos de fuentes (npx react-native-asset, o expo-font). React Native no tiene lista de fuentes alternativas y elige un archivo por peso, así que pasa resolveFont a TanreiProvider cuando tus fuentes estén registradas con un nombre por peso.

Las guías de primeros pasos y el README de cada paquete tienen los detalles. Comprueba la licencia de un tipo de letra antes de distribuirlo: los predeterminados tienen licencia abierta, y cupertino se refiere a las fuentes de Apple solo por palabra clave o por nombre, porque no pueden incluirse ni usarse en otras plataformas; en las demás recurre a un tipo de letra con licencia abierta.

Cómo los preajustes dan nuevos valores a la escala y la extienden

Un preajuste que imita otro sistema de diseño conserva los dieciséis nombres y les da los valores de ese sistema; donde su origen tiene un estilo que el núcleo no nombra, extiende el vocabulario con un rol propio. Los nombres nunca se mueven, así que un producto construido sobre tanrei pasa a m3-like sin tocar un solo título.

  • m3-like da nuevos valores a todos los roles a partir de la escala tipográfica de Material Design 3 (heading-1 toma el headline large de Material, body su body medium, label su label large) y añade display-large (57px) y display-small (36px), porque Material tiene tres tamaños de display y un producto necesita uno. Sus pasos de énfasis son los de Material: 100 en display, títulos y cuerpo, y 200 en las etiquetas. El arnés de fidelidad mide todos los estilos de texto que publica Material, los treinta, incluidos los de énfasis, junto con los roles de color y Button: de 288 tokens medidos, 273 son iguales, 14 están cubiertos por otro token, 1 no tiene correspondencia y está amparado por una laguna de imitación registrada, y ninguno es distinto. En la página de sistemas de diseño se muestra como 273 / 274, porque no cuenta los cubiertos. Las cifras se leen de tokens/generated/m3-like/fidelity.json, que la compilación reescribe.
  • cupertino da nuevos valores a todos los roles a partir de los once estilos de texto de iOS de Apple, de Large Title a Caption 2, y añade los tres que el núcleo no nombra: body-callout, body-subhead y caption-small. Sus pasos de énfasis son 100 en display y 200 en lo demás, que es la distancia entre los estilos normal y con énfasis de Apple.

Un rol que añade un preajuste es un token corriente en todas las plataformas: el display-large de m3-like es --tanrei-sys-typescale-display-large-font en la web y un miembro de la escala tipográfica en cada paquete nativo. La vista previa de Theme Studio lo dibuja en la escala de tipos junto a los dieciséis.

Carácter

  • El display y los títulos van apretados. El texto grande se compone con espaciado entre letras negativo (−0.04em en display, −0.03em en heading-1, que se reduce hasta −0.01em en heading-5), lo que mantiene serenos los títulos grandes; display, con peso 450, se mantiene ligero.
  • Los tamaños pequeños se abren. body-small, label-small, caption y eyebrow llevan un ligero espaciado entre letras positivo para que el texto de 11–13px siga siendo legible.
  • Los pesos son números. Como Inter es una fuente variable, pesos como 450 son válidos y se conservan en todas las plataformas que admiten ejes variables. Los pasos de énfasis son números por la misma razón: 450 + 100 es un peso real.
  • El tipo mono es para el código. code y code-small usan Roboto Mono. El eyebrow se compone en el tipo plain: pequeño, con espaciado entre letras amplio y puesto en mayúsculas por el componente, nunca por el token.

Idiomas

Los interlineados se eligen para que el texto que mezcla escritura latina y CJK no se recorte, y el japonés hereda los mismos roles. El espaciado entre letras negativo es un recurso de la escritura latina: dondequiera que el lang del texto sea chino, japonés o coreano (en prose, en las clases de texto y en el título de cada componente), Tanrei compone el título sin él. Define lang y el título no necesita nada más.

Escalado

Los tamaños de texto se expresan en unidades relativas en la web (rem) y se escalan con el ajuste de tamaño de texto del usuario en todas las plataformas. Los diseños deben tolerar el texto al 200%: los contenedores crecen, y las etiquetas se dividen en varias líneas antes de truncarse. Cada tamaño es un coeficiente sobre dial.type.base con dial.type.contrast como exponente, de modo que un dial mueve toda la escala y el otro separa los títulos del cuerpo.

Consulta todos los roles con muestras en vivo en la referencia de la escala tipográfica.