Design systém gov.cz4.7.1

Breakpointy

Breakpointy v Design systému gov.cz ​

Breakpointy určují šířky, na kterých se mění rozvržení stránky. Design systém gov.cz je stavěný mobile first: výchozím stavem je nejužší zobrazení a každý breakpoint přidává pravidla směrem vzhůru.

Sada je záměrně malá — pět pásem pokryje telefon, tablet i desktop. Breakpoint navíc znamená další rozvržení, které je potřeba navrhnout, otestovat a udržovat.

Hodnoty ​

NázevHodnotaŠířka při 16pxPásmo platnostiTypické zařízení
none00 px0 – 591 pxtelefon portrait
sm37em592 px592 – 767 pxtelefon landscape / phablet
md48em768 px768 – 991 pxtablet portrait
lg62em992 px992 – 1279 pxtablet landscape / notebook
xl80em1280 px1280 px a vícedesktop

Nad xl se rozvržení už nemění. Šířka obsahu je zastropovaná tokenem --templates-layout-page-limit-max (75rem = 1200 px), takže na širokých monitorech zůstává po stranách volné místo místo neúnosně dlouhých řádků textu.

Sadu nedoplňujeme o 2xl — nad xl by dnes nic neměnil.

Proč jsou hodnoty v em a ne v px ​

Breakpointy jsou definované v em, takže se vztahují k základní velikosti písma v prohlížeči. Když si čtenář text zvětší, layout se překlopí do užší varianty dřív — obsah se tedy přeskládá místo toho, aby se zvětšené písmo mačkalo do stejně široké mřížky. To je záměr a plní WCAG 1.4.4 Změna velikosti textu.

Praktický důsledek: hodnoty v px platí jen při výchozí velikosti písma 16 px. Všechny hodnoty jsou dělitelné šestnácti, aby jim v em odpovídala celá čísla.

Jak se breakpointy používají ​

Ve stylech přes mixin mq(), který se stará o správné hranice pásem:

scss
@use "@gov-design-system-ce/core/src/sass/mixins" as mixin;

.example {
	// Od `md` výš (min-width: 48em)
	@include mixin.mq($from: md) {
		display: flex;
	}

	// Pod `lg` (max-width: 61.99em) — horní hranice je nezahrnutá,
	// takže pásma na sebe navazují bez mezery i bez přesahu.
	@include mixin.mq($until: lg) {
		display: block;
	}
}

V komponentách jsou breakpointy dostupné rovnou jako atributy a utility třídy:

  • gov-spacer — <gov-spacer size="l" breakpoint="md"> přidá odsazení až od daného breakpointu.
  • gov-grid — col-span-md, row-span-lg a podobně.
  • gov-hide--md skryje prvek pod daným breakpointem.

V JavaScriptu nepoužívejte window.innerWidth — porovnává px proti em breakpointům, takže se při zvětšeném písmu rozejde se styly. Použijte hodnoty z balíčku @gov-design-system-ce/utils, které vyhodnotí stejný media dotaz, jaký generují styly:

ts
import {matchesFrom, onBreakpointChange} from "@gov-design-system-ce/utils"

if (matchesFrom("lg")) {
	// desktopová varianta
}

const unsubscribe = onBreakpointChange("lg", (matches) => {
	// volá se jen při skutečném překlopení, ne na každý pixel při resize
})

Container queries — jiná osa než breakpointy ​

Část komponent nereaguje na šířku okna, ale na šířku vlastního kontejneru. Karta v úzkém sloupci mřížky se tedy zalomí do mobilní varianty i na širokém monitoru. Takto se chovají gov-card, gov-tile, gov-empty a gov-error-code.

Názvy breakpointů jsou stejné, význam se ale liší: sm u container query znamená „kontejner je široký aspoň 592 px", ne „okno je široké aspoň 592 px".

Doporučené šířky pro návrh ve Figmě ​

Framy volte doprostřed pásma, ne na jeho hranu — na hraně se chování zlomu právě mění a návrh pak neukazuje ani jednu z variant spolehlivě.

FramePásmoReprezentuje
390 pxnonetelefon portrait
680 pxsmtelefon landscape / phablet
834 pxmdtablet portrait
1150 pxlgtablet landscape / notebook
1440 pxxldesktop

Kromě toho je dobré ověřit dvě situace mimo tabulku: 320 px jako závazné minimum podle WCAG 1.4.10 Reflow (obsah musí fungovat bez vodorovného posuvníku), a 1920 px jako nejběžnější velký monitor — samostatný breakpoint pro něj nemáme, přesto se na něm layout nesmí rozpadnout do příliš dlouhých řádků.

Kde jsou breakpointy definované ​

Zdrojem pravdy je jediná mapa v packages/core/src/sass/variables/_mq.scss. Z ní vychází mixiny mq() a cq(), generované utility třídy i hodnoty pro JavaScript (packages/utils/lib/breakpoints.utils.ts). Soulad obou míst hlídá kontrola npm run breakpoints:check, takže se hodnoty nemohou rozejít.