Przejdź do treści

Typografia

Jeden krój, jedna skala ról semantycznych i detale optyczne, dzięki którym tekst wygląda na starannie złożony, a nie po prostu wyrenderowany.

Interfejsy to przede wszystkim tekst. prfct traktuje typografię jako podstawowy materiał systemu: jedna, wyjątkowo czytelna rodzina krojów, niewielki zestaw nazwanych ról i dyskretne detale — rozmiar optyczny, dynamiczne odstępy międzyliterowe, cyfry tabelaryczne — które odróżniają zaprojektowany interfejs od domyślnego.

Szybsze kompilacje, spokojniejsze pulpity

v1.4Opublikowano 18 września · 4 min czytania

Kompilacje przyrostowe wykorzystują teraz skompilowane moduły między gałęziami, co skraca medianę czasu wdrożenia o 38%. Pulpit przebudowaliśmy na prfct — z gęstszymi tabelami i cyframi tabelarycznymi, które układają się w równe kolumny.

Co się zmieniło

Całą pracę wykonują role nagłówka, treści i podpisu: bez jednorazowych rozmiarów i przypadkowych grubości.

import { Badge } from "@/components/ui/badge"

export default function TypeHierarchy() {
  return (
    <article className="flex w-full max-w-lg flex-col gap-3">
      <h2 className="text-display-sm text-foreground">
        Szybsze kompilacje, spokojniejsze pulpity
      </h2>
      <div className="flex items-center gap-2 text-caption text-muted-foreground">
        <Badge variant="secondary" size="sm">
          v1.4
        </Badge>
        Opublikowano 18 września · 4 min czytania
      </div>
      <p className="text-body-md text-foreground/85">
        Kompilacje przyrostowe wykorzystują teraz skompilowane moduły między gałęziami, co skraca medianę czasu wdrożenia o 38%. Pulpit przebudowaliśmy na prfct — z gęstszymi tabelami i cyframi tabelarycznymi, które układają się w równe kolumny.
      </p>
      <h3 className="mt-2 text-heading-sm text-foreground">Co się zmieniło</h3>
      <p className="text-body-sm text-muted-foreground">
        Całą pracę wykonują role nagłówka, treści i podpisu: bez jednorazowych rozmiarów i przypadkowych grubości.
      </p>
    </article>
  )
}

Kroje pisma

Inter

prfct jest złożony krojem Inter 4.1 — zmienną rodziną zaprojektowaną z myślą o ekranach. Ma dwie osie: grubość i rozmiar optyczny, dzięki któremu kształty liter subtelnie zmieniają się wraz z rozmiarem. W rozmiarach tekstowych litery mają otwarte światła i swobodne odstępy; od 32 px pałeczkę przejmuje odmiana Display, z ciaśniejszymi odstępami i drobniejszymi detalami. Nie zmieniasz kroju dla nagłówków — to krój się dopasowuje.

Aa

Inter 4.1Inter 4.1, zmienny, hostowany samodzielnie ze wszystkimi funkcjami OpenType. Rozmiar optyczny przełącza się na krój Display od 32px.

ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 ąćęłńóśźż ÄÖÜß €$£ → ← ✓ ⌘ ⌥ ⇧

Ag300
Ag400
Ag500
Ag600
Ag700
Ag800

prfct hostuje krój Inter samodzielnie, zamiast ładować go z CDN z fontami. Wersje z takich serwisów często wycinają funkcje OpenType, żeby oszczędzić bajty — w tym cyfry tabelaryczne, na których opierają się interfejsy pełne danych. Build prfct zachowuje wszystkie funkcje i obie osie, ogranicza zestaw znaków do pisma łacińskiego (z pełną obsługą polskiego, czeskiego, tureckiego i innych języków z zakresu Latin Extended-A), wstępnie ładuje tylko odmianę prostą i dostarcza font zastępczy o dopasowanych metrykach, żeby tekst nie przeskakiwał, kiedy font się doładuje.

Geist Mono

Kod, klawisze i wartości techniczne zapisujemy krojem Geist Mono: zwartym, o znakach równej szerokości i zaprojektowanym do pracy w parze z neogroteskowymi krojami bezszeryfowymi.

Aa

Geist MonoGeist Mono do kodu, klawiszy i danych tabelarycznych. Załaduj go przez next/font jako --font-geist-mono; bez niego użyty zostanie monospace platformy.

ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 ąćęłńóśźż ÄÖÜß €$£ → ← ✓ ⌘ ⌥ ⇧

Ag300
Ag400
Ag500
Ag600
Ag700
Ag800

Skala typograficzna

prfct nazywa style tekstu według roli, a nie rozmiaru. Rola łączy rozmiar, interlinię, odstępy międzyliterowe i grubość w jedną decyzję, więc style tekstu nie mogą rozjechać się po jednej właściwości naraz.

72px / 76px · 600
-0.024em

Wdrożenia w tym tygodniu

Nagłówki hero na powierzchniach marketingowych.

60px / 64px · 600
-0.023em

Wdrożenia w tym tygodniu

Sekcje hero stron.

48px / 52px · 600
-0.022em

Wdrożenia w tym tygodniu

Otwarcia sekcji.

40px / 46px · 600
-0.021em

Wdrożenia w tym tygodniu

Tytuły funkcji.

32px / 40px · 600
-0.02em

Wdrożenia w tym tygodniu

Tytuły stron dokumentacji.

28px / 36px · 600
-0.021em

Raport przychodów kwartalnych

Tytuły stron najwyższego poziomu w aplikacji.

24px / 32px · 600
-0.019em

Raport przychodów kwartalnych

Tytuły sekcji w interfejsie produktu.

20px / 28px · 600
-0.016em

Raport przychodów kwartalnych

Tytuły kart i okien dialogowych.

16px / 24px · 600
-0.011em

Raport przychodów kwartalnych

Tytuły grup i paneli.

14px / 20px · 600
-0.006em

Raport przychodów kwartalnych

Nagłówki gęstych list i tabel.

18px / 28px · 400
-0.014em

Faktury wysyłamy pierwszego dnia roboczego miesiąca, z terminem płatności 14 dni. Opłacone same trafiają do archiwum.

Akapity wprowadzające, wstępy.

16px / 26px · 400
-0.011em

Faktury wysyłamy pierwszego dnia roboczego miesiąca, z terminem płatności 14 dni. Opłacone same trafiają do archiwum.

Dłuższe teksty do czytania.

14px / 22px · 400
-0.006em

Faktury wysyłamy pierwszego dnia roboczego miesiąca, z terminem płatności 14 dni. Opłacone same trafiają do archiwum.

Domyślny tekst interfejsu produktu.

13px / 20px · 400
-0.003em

Faktury wysyłamy pierwszego dnia roboczego miesiąca, z terminem płatności 14 dni. Opłacone same trafiają do archiwum.

Tekst drugorzędny w gęstym interfejsie.

16px / 24px · 500
-0.011em

Zapisz zmiany

Duże kontrolki.

14px / 20px · 500
-0.006em

Zapisz zmiany

Przyciski, pola, pozycje menu.

13px / 18px · 500
-0.003em

Zapisz zmiany

Kompaktowe kontrolki, odznaki.

12px / 16px · 500
0em

Zapisz zmiany

Mikroetykiety, liczniki.

12px / 16px · 400
+0.002em

Zaktualizowano 2 minuty temu

Podpisy, znaczniki czasu, tekst pomocniczy.

11px / 16px · 600
+0.08em

Fundamenty

Krótkie etykiety wersalikami: jednostki, nazwy grup w gęstych danych. Nigdy nad nagłówkiem.

13px / 22px · 400
0em

const theme = resolveTheme({ brand })

Kod w tekście i w blokach (mono).

<h1 className="text-heading-xl">Settings</h1>
<h2 className="text-heading-md">Notifications</h2>
<p className="text-body-sm text-muted-foreground">Choose what we email you about.</p>

Rozmiarowe klasy Tailwinda (text-sm, text-lg…) nadal są dostępne do precyzyjnej pracy nad interfejsem i też mają odstępy międzyliterowe prfct.

Rodzina rólZastosowanie
DisplaySekcje hero w marketingu, tytuły stron w dokumentacji i na stronach docelowych. Nigdy w interfejsie samego produktu.
HeadingTytuły w produkcie: strony, sekcje, karty, okna dialogowe.
BodyTekst do czytania. body-md do dłuższych tekstów, body-sm jako domyślny w interfejsie.
LabelTekst na kontrolkach: przyciski, pola, pozycje menu, zakładki.
Caption / overlineMetadane, znaczniki czasu, tekst pomocniczy; overline do jednostek i nazw grup w gęstych danych, nigdy nad nagłówkiem.

Detale, które mają znaczenie

Dynamiczne odstępy międzyliterowe

Odstępy między literami podążają za zależnymi od rozmiaru metrykami kroju Inter: przy 12 px są lekko rozluźnione, bo litery potrzebują powietrza, a im większy rozmiar, tym są ciaśniejsze, bo domyślne odstępy zaczynają wyglądać luźno. Każda rola i każdy rozmiar Tailwinda mają już właściwą wartość — nie dodawaj tracking-* do zwykłego tekstu.

Własny głos nagłówków

Role Display włączają jednopiętrowe a (cv11) i zaokrąglone cudzysłowy (ss03) kroju Inter. Duże nagłówki zyskują dzięki temu łagodniejszy, bardziej charakterystyczny głos, a tekst podstawowy i interfejs zachowują domyślne dwupiętrowe a, które w małych rozmiarach jest czytelniejsze.

Cyfry w równych kolumnach

Liczby w tabelach, statystykach i licznikach czasu muszą układać się w równe kolumny. Tabele prfct domyślnie włączają cyfry tabelaryczne; w każdym innym miejscu dodaj klasę numeric.

Cyfry proporcjonalne
Frankfurt1 204 11881,4 ms
Warszawa987 45074,9 ms
Wirginia11 009 871112,0 ms
Cyfry tabelaryczne (numeric)
Frankfurt1 204 11881,4 ms
Warszawa987 45074,9 ms
Wirginia11 009 871112,0 ms
const rows = [
  { region: "Frankfurt", requests: "1 204 118", p95: "81,4 ms" },
  { region: "Warszawa", requests: "987 450", p95: "74,9 ms" },
  { region: "Wirginia", requests: "11 009 871", p95: "112,0 ms" },
]

function Column({ title, tabular }: { title: string; tabular: boolean }) {
  return (
    <div className="flex flex-col gap-2 rounded-xl border bg-card p-4">
      <span className="text-xs font-medium text-muted-foreground">{title}</span>
      <table
        className="text-sm"
        style={{
          fontVariantNumeric: tabular ? "tabular-nums" : "proportional-nums",
        }}
      >
        <tbody>
          {rows.map((row) => (
            <tr key={row.region} className="border-b last:border-0">
              <td className="py-1.5 pr-6 text-foreground">{row.region}</td>
              <td className="py-1.5 pr-6 text-right text-foreground">
                {row.requests}
              </td>
              <td className="py-1.5 text-right text-muted-foreground">
                {row.p95}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

export default function TabularNumbers() {
  return (
    <div className="grid w-full max-w-2xl gap-3 sm:grid-cols-2">
      <Column title="Cyfry proporcjonalne" tabular={false} />
      <Column title="Cyfry tabelaryczne (numeric)" tabular />
    </div>
  )
}
<span className="numeric">1,204,118</span>

Zrównoważone i estetyczne łamanie wierszy

Nagłówki używają text-wrap: balance, więc ich wiersze mają zbliżoną długość; akapity — text-wrap: pretty, żeby ostatnie słowo nie zostawało samotnie w ostatnim wierszu. Oba ustawienia działają globalnie.

Wytyczne

  • Używaj ról, nie rozmiarów. Jeśli projekt wymaga rozmiaru, którego nie daje żadna rola, zwykle potrzebuje po prostu innej roli.
  • Jeden styl na poziom nagłówka. Każdemu poziomowi daj jedną rolę i nie przeskakuj poziomów — ani w znacznikach HTML, ani w skali wizualnej.
  • Wyróżniaj grubością, nie rozmiarem. Słowo w font-medium wewnątrz body-sm w zupełności wystarczy.
  • Trzymaj długość wiersza w granicach 45–75 znaków. Do długich tekstów używaj max-w-prose albo max-w-2xl.
  • Wielka litera tylko na początku — w nagłówkach, na przyciskach, w pozycjach menu. Pisanie Każdego Wyrazu Wielką Literą to w polszczyźnie anglicyzm; w interfejsie wygląda jak krzyk i zaciera różnicę między nazwami własnymi a zwykłymi słowami.

E-mail do rozliczeń

Faktury wysyłamy na adres finance@acme.co.

DobrzeHierarchia z ról: jeden nagłówek, jeden styl tekstu podstawowego, jeden podpis.

E-mail Do Rozliczeń

Faktury Wysyłamy Na Adres finance@acme.co.

ŹleMieszane rozmiary, grubości i wielkie litery walczą o uwagę.

Dostępność

  • Wszystkie rozmiary są podane w rem, więc tekst skaluje się razem z rozmiarem czcionki ustawionym w przeglądarce. Układy dopasowują się aż do szerokości 320 px, czyli powiększenia 400% w oknie 1280 px.
  • Role Body mają interlinię co najmniej 1,5× dla tekstu do czytania, a w małych rozmiarach nigdy nie schodzą poniżej grubości 400.
  • Wyciszony tekst nadal spełnia 4,5:1; zobacz Kolor.
  • Wersaliki są zarezerwowane dla krótkich nadtytułów, które mają zwiększone odstępy między literami i interpunkcję dopasowaną do wersalików, dzięki czemu pozostają czytelne.