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:

Co jsem našel na vlastním webu, než jsem ho přestavěl
NálezProč 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 zdrojeStatistiky, které zněly přesně a neexistovaly. Nikdo si je nevymyslel schválně, ale byly tam.
Animační knihovna za 55 kBPlatil 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 webuZů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.

Paleta webu podle toho, k čemu slouží
SkupinaHodnotyK čemu
Papírbone #EDE9E1, bone-dim #DCD5C8, bone-deep #C9C0AFText na tmavé a světlé plochy
Tmaink-black #121110, ink-warm #17120F, ink-soft #4E4941Pozadí celého webu a text na světlé
Akcentaura #5B3FD9, aura-on-ink #A78BFAOdkazy, zvýraznění, hlavní akce
Signálsignal #A52B05, signal-on-ink #FF5C2B, ember #E0812BVýstrahy a grafické akcenty
Modrávolt #2440D6, volt-on-ink #6C8CFFDruhý 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.

Běhové závislosti webu
BalíčekK čemu
next, react, react-domSamotný framework
clsx, tailwind-mergeSkládání tříd, dohromady pár kilobajtů
server-onlyPojistka, 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:

  1. Kontrast

    Počítá 24 dvojic barev včetně průhledností. Spadne, když text klesne pod hranici čitelnosti.

  2. Překryv otázek

    Hlídá, aby dvě stránky neodpovídaly na tutéž otázku a nepraly se spolu ve vyhledávání.

  3. Odkazy v článcích

    Každý vnitřní odkaz musí vést na stránku, která existuje.

  4. Existence obrázků

    Každá cesta k obrázku v datech musí mít soubor.

  5. Deriváty obrázků

    Vyrobí náhled 640 px a plnou verzi 1400 px. Nikdy nezvětšuje.

  6. Sdílecí obrázky

    Vyrobí JPEG 1200×630 pro náhledy na sítích.

  7. Rozměry obrázků

    Zapíše je do datového souboru, aby galerie uměla rozvrhnout řádky dřív, než dorazí první bajt.

  8. Prořezání exportu

    Vyhodí originály, na které se nikdo neodkazuje. Naposledy 393 souborů, 71 MB.

  9. Mapa webu

    Ověří, že se adresy v mapě a kanonické adresy shodují na znak.

  10. 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-motion vů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í:

Největší vykreslený obsah podle typu stránky
StránkaLCP
Úvodní stránka244 ms
Detail projektu240 ms
Výpis blogu212 ms
Článek192 ms
O mně152 ms
Časté dotazy152 ms
Tvorba webů148 ms
Kontakt144 ms
Portfolio132 ms

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 web posílá vyhledávačům
CoJak
Strukturovaná dataArticle a FAQPage u článků, CreativeWork u projektů, ProfessionalService a Person na úvodní, BreadcrumbList všude
Mapa webu69 adres, všechny s koncovým lomítkem, shoda s kanonickou adresou na znak
Náhledy na sítích72 obrázků, všechny JPEG 1200×630 — WebP by LinkedIn podle všeho přeskočil
Popisy stránekSklá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 AIllms.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á:

Co se stahovalo kvůli měření, než jsem to smazal
SouborVelikost
Měřicí kód432 kB
Správce značek382 kB
Knihovna cookie lišty54 kB

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.

Rozdělení práce při redesignu
Kde anoKde ne
Rutinní kód a přepisy komponentRozhodnutí, 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ánkamiPosouzení, 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ší:

  1. 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.

  2. 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ě.

  3. 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ě.

  4. 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é.