Proč vůbec redesign
Starý web fungoval. Měl portfolio, blog, kontakt a dal se otevřít na mobilu. Kdybych ho ukázal klientovi, nikdo by nic nenamítl.
Problém byl jinde. Portfolio má jednu nepříjemnou vlastnost: je zároveň argument i důkaz. Když na něm tvrdím, že dělám rychlé weby, musí být rychlý. Když píšu o přístupnosti, musí projít. A když jsem si ten svůj pořádně proměřil, našel jsem tohle:
| Nález | Proč to vadilo |
|---|---|
| 868 kB cizího kódu kvůli měření | Správce značek a měřicí kód na každé stránce. Lišta se stahovala, ale nikdy se nezobrazila, takže nikdo nemohl dát souhlas — a bez souhlasu se nic nezměřilo. |
| Čísla v článcích bez zdroje | Statistiky, které zněly přesně a neexistovaly. Nikdo si je nevymyslel schválně, ale byly tam. |
| Animační knihovna za 55 kB | Platil ji každý návštěvník na každé stránce. Používala se na tři efekty, které umí samotné CSS. |
| Sdílecí obrázek starého webu | Zůstal i po změně vizuálu, takže každé sdílení ukazovalo web, který už neexistoval. |
Žádná z těch věcí nebyla vidět při běžném prohlížení. Všechny se našly až měřením — a to je přesně ten typ chyby, který na webu vydrží roky.
Zadání, které jsem si dal
Před prvním řádkem kódu jsem si napsal jedno pravidlo a držel se ho celou dobu:
Každé rozhodnutí musí jít změřit, nebo zdůvodnit větou, kterou bych řekl klientovi. Ne „vypadá to líp“. Buď je to vidět v číslech, nebo pro to mám důvod, který unese odpor.
Marian Bendák
Z toho pravidla vypadlo všechno ostatní. Paleta má pevný počet hodnot, protože se pak dá hlídat skriptem. Pohyb je v CSS, protože knihovna má cenu v kilobajtech. Obrázky mají dva deriváty, protože třetí by nic nepřidal. Nic z toho není estetická preference — je to řada rozhodnutí, u kterých se dá ukázat, co by stálo to druhé řešení.
Barvy: třináct hodnot a brána, která je hlídá
Paleta má třináct pojmenovaných hodnot a nic mimo ně se na webu nepoužívá. Zní to přísně, ale dělá to pravý opak: přestanete řešit odstíny a začnete řešit, co má být vidět dřív.
| Skupina | Hodnoty | K čemu |
|---|---|---|
| Papír | bone #EDE9E1, bone-dim #DCD5C8, bone-deep #C9C0AF | Text na tmavé a světlé plochy |
| Tma | ink-black #121110, ink-warm #17120F, ink-soft #4E4941 | Pozadí celého webu a text na světlé |
| Akcent | aura #5B3FD9, aura-on-ink #A78BFA | Odkazy, zvýraznění, hlavní akce |
| Signál | signal #A52B05, signal-on-ink #FF5C2B, ember #E0812B | Výstrahy a grafické akcenty |
| Modrá | volt #2440D6, volt-on-ink #6C8CFF | Druhý akcent, odlišení sekcí |
Fialovou jsem nevybral z přehlídky trendů. Každý portrét na tomhle webu je nasvícený z jedné strany magentou a z druhé modrou, a tam, kde se ta dvě světla na obličeji potkají, vznikne přesně tahle barva. Je to změřený průměr vlastních fotek, ne odhad.
Spočítaný kontrast ale nestačí. Text často leží na fotce nebo na přechodu, kde žádná hodnota z CSS neplatí. Proto je k tomu ještě druhá kontrola, která měří vykreslené pixely: stránka se vyfotí, pak znovu s průhledným písmem, a porovná se, co je doopravdy za každým znakem. Ta sonda našla věci, které by výpočet nikdy neukázal — třeba lištu navigace nad bílým screenshotem.
Dvě písma a česká sazba
Písma jsou dvě a každé má svůj úkol. Bricolage Grotesque na všechno, co se čte, JetBrains Mono na štítky, čísla a popisky. Obě se hostují ze serveru webu, ne z cizí CDN, takže se při načtení nikam neposílá adresa návštěvníka.
Nejmenší písmo na celém webu je 15 px. Není to kompromis — je to hranice, pod kterou text přestává být pro část lidí čitelný, a tím pádem nemá smysl ho tam psát.
A pak je tu věc, kterou na českém webu skoro nikdo nedělá: jednopísmenné předložky a spojky nesmí končit řádek. Za každým a, i, k, o, s, u, v, z je v textech nezlomitelná mezera. Hlídá to skript, který projde datové soubory a doplní ji. Do metadat, strukturovaných dat a popisků obrázků ale nepatří — je to pokyn pro sazbu, ne znak, který má někdo hledat, a vyhledávači by zbytečně rozbíjel slova.
Čím je to postavené
Next.js 16 a React 19, ale ve statickém režimu: build vyrobí hotové HTML soubory a server už jen posílá soubory. Žádná databáze, žádný redakční systém, žádný běžící proces, který by se dal napadnout nebo který by musel odpovídat.
| Balíček | K čemu |
|---|---|
| next, react, react-dom | Samotný framework |
| clsx, tailwind-merge | Skládání tříd, dohromady pár kilobajtů |
| server-only | Pojistka, aby se serverový kód nedostal do prohlížeče |
Šest závislostí. Všechno ostatní — galerie, lightbox, rozbalovací otázky, rastr teček, animace — je napsané ručně. Ne ze zásady, ale proto, že každá knihovna má cenu, kterou platí návštěvník, a u těchhle věcí ta cena nestála za ušetřený čas.
Deset bran, které build nepustí dál
Tohle je podle mě nejdůležitější část celého redesignu a zároveň ta, která není vidět. Web se nedá postavit, pokud neprojde deseti kontrolami:
- Kontrast
Počítá 24 dvojic barev včetně průhledností. Spadne, když text klesne pod hranici čitelnosti.
- Překryv otázek
Hlídá, aby dvě stránky neodpovídaly na tutéž otázku a nepraly se spolu ve vyhledávání.
- Odkazy v článcích
Každý vnitřní odkaz musí vést na stránku, která existuje.
- Existence obrázků
Každá cesta k obrázku v datech musí mít soubor.
- Deriváty obrázků
Vyrobí náhled 640 px a plnou verzi 1400 px. Nikdy nezvětšuje.
- Sdílecí obrázky
Vyrobí JPEG 1200×630 pro náhledy na sítích.
- Rozměry obrázků
Zapíše je do datového souboru, aby galerie uměla rozvrhnout řádky dřív, než dorazí první bajt.
- Prořezání exportu
Vyhodí originály, na které se nikdo neodkazuje. Naposledy 393 souborů, 71 MB.
- Mapa webu
Ověří, že se adresy v mapě a kanonické adresy shodují na znak.
- Náhledy na sítích
Přečte hotový export a spadne, když některý náhled míří na neexistující soubor nebo má jiný rozměr, než stránka tvrdí.
Ta poslední brána se vyplatila hned napoprvé: chytla výchozí sdílecí obrázek, na který se nikde neodkazuje jménem, protože je to výchozí hodnota funkce. Bez ní by šly ven tři stránky s prázdným náhledem.
Obrázky: dva deriváty a žádné zvětšování
Z každého obrázku vzniknou dvě verze — náhled 640 px a plná 1400 px — a stránka si vybere podle toho, jak velký ten obrázek doopravdy bude. Ne podle pořadí v seznamu, podle skutečné kresby.
Jedno pravidlo je v tom tvrdé: obrázek se nikdy nezobrazí širší, než je jeho zdroj. Náhledy projektů jsou 1140 px a na širokém monitoru se nafukovaly přes celou šířku — a bylo to vidět. Teď se radši nechá místo, než aby se obraz roztáhl.
Galerie navíc zná rozměry všech obrázků dopředu, protože je build zapsal do datového souboru. Díky tomu umí rozvrhnout řádky dřív, než dorazí první bajt, a nic se při načítání neposune. Odtud to CLS 0.
Pohyb bez knihovny
Animační knihovnu jsem chtěl. Ušetřila by mi práci. Pak jsem si spočítal cenu: 55 kB po kompresi na každé stránce, které zaplatí každý návštěvník, za tři efekty — prolnutí, posun a odkrytí. Všechny tři umí CSS samo.
Co na webu zůstalo z pohybu a proč:
- Jedno odkrytí pro celý web. Prvek se zvedne a prolne, jednou, a při
prefers-reduced-motionvůbec. - Rastr teček na pozadí hero sekcí. Jedno plátno, vlna běží pořád a kurzor k ní přidává světlo.
- Nit procesem, která se kreslí tím, jak čtete. Pět kroků v řadě vypadá jako pět možností; čára skrz ně je pořadí.
- Jedno světlo obíhající navigaci. Ne pulz — fixní lišta je v periferním vidění pořád a co tam bliká, to po chvíli otravuje.
Rychlost: naměřeno, ne odhadnuto
Tohle je devět typů stránek, měřeno na hotovém exportu, po zahřívacím průchodu, v okně 1440×900 bez umělého zpomalení:
| Stránka | LCP |
|---|---|
| Úvodní stránka | |
| Detail projektu | |
| Výpis blogu | |
| Článek | |
| O mně | |
| Časté dotazy | |
| Tvorba webů | |
| Kontakt | |
| Portfolio |
Medián 152 ms a CLS 0 na všech devíti. Doporučená hranice pro LCP je 2,5 sekundy, takže je v tom slušná rezerva — i když na pomalém mobilním připojení budou čísla jinde. To je ostatně důvod, proč rozhoduje, co se na stránku vůbec nedostane.
Mobil není zmenšenina
Většina návštěv přijde z telefonu, takže se na něm kreslí i kontroluje — ne že se hotový web na konci „zmenší“. Konkrétně:
- Celý web se projíždí v okně 390 px a nic nesmí přetékat do strany. Kontroluje se to na všech 69 adresách.
- Pole formuláře mají 16 px, protože při menším písmu iOS při kliknutí zazoomuje stránku.
- Klikací plochy mají nejmíň 24 px na výšku. Drobečková navigace jich 53 stránkách nesplňovala, než se to změřilo.
- Menu se na telefonu otevírá jako panel pod lištou, ne jako přes celou obrazovku — a stránka pod ním zůstává živá.
SEO a strukturovaná data
Nic z téhle části nejsou triky. Je to spíš seznam věcí, které musí sedět, aby vyhledávač nemusel hádat:
| Co | Jak |
|---|---|
| Strukturovaná data | Article a FAQPage u článků, CreativeWork u projektů, ProfessionalService a Person na úvodní, BreadcrumbList všude |
| Mapa webu | 69 adres, všechny s koncovým lomítkem, shoda s kanonickou adresou na znak |
| Náhledy na sítích | 72 obrázků, všechny JPEG 1200×630 — WebP by LinkedIn podle všeho přeskočil |
| Popisy stránek | Skládané z vlastního textu stránky, ne z jedné věty. Dvacet tři grafik mělo popis o čtrnácti znacích, což Google bere jako žádný. |
| Rozcestník pro AI | llms.txt a textová verze celého webu na jedné adrese, pro jazykové modely a AI vyhledávače |
Jedna věc z toho stojí za zdůraznění: brána na překryv otázek. Při přepisování blogu se stalo, že dvě stránky odpovídaly na tutéž otázku a navzájem si braly pozici. Vyhledávač si pak vybírá sám a většinou hůř, než byste si vybrali vy.
Měření a cookies: co jsem smazal
Starý web měl správce značek po předchozím nastavení. Změřil jsem, co dělá:
| Soubor | Velikost |
|---|---|
| Měřicí kód | |
| Správce značek | |
| Knihovna cookie lišty |
Výsledek: nula cookies, prázdné úložiště prohlížeče a lišta, která se stáhla, ale nikdy nevykreslila. Návštěvník tedy neměl jak dát souhlas ani ho odepřít, a bez souhlasu měřicí kód neukládá nic. Plná cena, nulový výnos.
Smazal jsem to celé a nenahradil ničím. Rozhodovalo to, že konverze, která mě jediná zajímá, je odeslaná poptávka — a tu vidím v e-mailu, ne v grafu. A co pro vyhledávání opravdu potřebuju, dává vyhledávací konzole: ta bere data od Googlu, ne z prohlížeče návštěvníka, takže nepotřebuje cookies ani souhlas.
Po smazání přeměřeno na čtyřech typech stránek: nula cookies a ani jeden měřicí požadavek. Cookie lištu tenhle web nepotřebuje — ne proto, že bych ji obcházel, ale protože není k čemu dávat souhlas.
Kde mi pomohla AI a kde ne
Napíšu to rovnou, protože to k tomuhle webu patří: na redesignu jsem hodně používal AI a je na tom postavená velká část rutiny. Zároveň je to nástroj, který se bez dohledu umí utrhnout, takže dává smysl říct, kde přesně má místo.
| Kde ano | Kde ne |
|---|---|
| Rutinní kód a přepisy komponent | Rozhodnutí, jak má web vypadat a co je priorita |
| Varianty řešení, ze kterých se vybírá | Výběr té varianty, kterou budu obhajovat |
| Měřicí skripty a kontrolní brány | Čísla v článcích — každé musí být naměřené nebo ze zdroje |
| Hledání chyb napříč 69 stránkami | Posouzení, jestli je nález opravdu chyba |
Nejnebezpečnější totiž není špatný text. Je to věrohodné číslo bez zdroje — zní přesně, nikdo si ho neověří a zůstane na webu roky. Přesně to se stalo na staré verzi tohohle webu. Proto tady každé číslo buď někde naměřím, nebo ho neuvedu, a proto jsou kontroly součástí buildu místo toho, aby byly na mojí paměti.
Co se při tom pokazilo
Tohle je část, kterou do článků o vlastní práci nikdo nedává, a je podle mě nejužitečnější:
- Měřil jsem na špatném místě
Tvrdil jsem, že navigační lišta má dost kontrastu, a měl jsem na to číslo. Jenže jsem ho vzal z místa, kde byla za lištou náhodou tmavá plocha. Teprve sken všech stránek ukázal, že lišta sedí na skoro bílém obsahu na 60 z 69 adres.
- Bílá lišta, která tam neměla co dělat
Navigace startovala ve světlé variantě a na tmavou se přepnula, až když si po načtení změřila, nad čím je. Na webu není jediná světlá sekce, takže ta varianta existovala jen jako bílý problesk — a protože pozadí přechází jinou rychlostí než popisky, byl v tom okamžik bledého textu na bledé liště.
- Hranaté rohy u otevřeného menu
Animace otevírání si držela svůj poslední snímek, takže otevřený panel měl pořád nasazený ořez. Ořez usekne všechno vně krabice — tedy i stín a barevný prstenec — a rohy proto vypadaly hranatě.
- Efekt, který nic nedělal
Zkoušel jsem ztmavovat pozadí pod lištou filtrem. Prohlížeč hlásil, že filtr aplikuje, a složené pixely vyšly světlejší než bez něj. Zahodil jsem to — čitelnost nemůže stát na efektu, který neumím doložit.
Společné mají jedno: všechny čtyři našlo až měření nebo cizí oko, ne pohled na obrazovku. A tři ze čtyř vznikly tím, že jsem si byl jistý.
Co z toho platí i pro váš web
Z celého redesignu jsou podle mě přenositelné tři věci, a žádná z nich nestojí na rozpočtu:
- Omezte paletu a držte ji. Pevný počet hodnot je svoboda, ne klec — přestanete řešit odstíny a začnete řešit hierarchii.
- Co nemá na stránce práci, ať tam není. Rychlost se nedělá optimalizací na konci. Dělá se tím, co se na stránku nedostane.
- Nechte si to kontrolovat strojem. Kontrast, odkazy, obrázky, mapa webu — všechno, co se dá ověřit skriptem, by nemělo záviset na tom, jestli si někdo vzpomene.
Co s tím dál
Web není hotový a asi nikdy nebude — pořád na něm něco upravuju a některé věci z tohohle článku se za půl roku změní. Co se ale nezmění, je ten způsob: rozhodnutí, které nejde změřit ani obhájit větou, na web nepatří.
Celý redesign je i v portfoliu jako projekt — MB Portfolio redesign se snímky všech stránek, a vedle něj první verze, kterou nahradil. Jedno bez druhého nedává smysl.
Jestli vás zajímá, jak tahle pravidla vypadají na klientském webu místo na vlastním, projděte si portfolio — u každého projektu je i to, proč se co rozhodlo. A když chcete probrat svůj web, napište mi: konzultace i návrh jsou zdarma a nezávazné.

