UXAIRFORCE

Detale UI, które robią różnicę – sesja projektowa z Jamesem McDonaldem #EN327

A

Adam Michalski

13 października 2025

Prawdziwe rzemiosło w projektowaniu interfejsów objawia się w detalach, które na pierwszy rzut oka mogą wydawać się nieistotne. Różnica między dobrym a doskonałym produktem często tkwi właśnie w nich.

To są notatki z dwugodzinnej sesji projektowej na żywo, podczas której James McDonald pomagał dopracować szczegóły interfejsu produktu Inflight. Wszystkie przemyślenia, techniki i obserwacje pochodzą bezpośrednio od uczestników tej rozmowy. Nie jest to teoria – to konkretne decyzje podejmowane nad realnym produktem.


TL;DR

  • Cienie w trybie ciemnym wymagają innych wartości niż w jasnym – prosta zmiana przezroczystości nie wystarcza
  • Technika 1px spread zamiast stroke pozwala cieniom „przeciekać” przez warstwy i eliminuje problem rozmazanych krawędzi
  • Negative spread w cieniach tworzy naturalny efekt źródła światła – technika zapożyczona od Dereka
  • 0.5px stroke daje ostrość, której nie osiągniesz standardowym 1px – subtelna różnica, ogromny efekt wizualny
  • Empty states to okazja do wyróżnienia produktu – od nudnej ikony do custom ilustracji można dojść w kilkanaście minut
  • Rozdzielenie koloru głównego od koloru notyfikacji tworzy czytelniejszy system wizualny
  • Przyciski w dark mode często wyglądają lepiej bez stroke, podczas gdy w light mode potrzebują wyraźnego obramowania
  • Konsekwencja w detalach buduje wrażenie produktu premium – te same zasady dla cieni, borders i komponentów

Filozofia cieni – więcej warstw niż myślisz

James od razu zauważył, że projekt używał solid stroke na komponentach. Problem pojawia się, gdy element znajduje się nad różnymi tłami – obramowanie zlewało się z kontekstem.

Jego podejście jest odmienne. Zamiast stroke używa 1px spread z niską przezroczystością, co pozwala cieniom „przeciekać” przez kolejne warstwy. Tłumaczył, że zawsze stara się, żeby wszystko się przenikało, zamiast tworzyć ostre odcięcia.

Konkretny przykład: przycisk w light mode miał solid stroke, który dobrze wyglądał na białym tle. Jednak gdy ten sam komponent znalazł się nad innym elementem UI, efekt był „muddy” – krawędzie traciły wyrazistość.

Rozwiązaniem okazał się spread shadow z opacity zamiast stroke. Dzięki temu wszystkie warstwy cieni pod spodem „przebijają” przez obramowanie, tworząc spójną głębię niezależnie od kontekstu.

Negative spread – sekret naturalnego światła

James wspomniał technikę, którą określił jako „ukradzioną od Dereka”. Użycie negative spread w shadows daje znacznie bardziej naturalny efekt źródła światła, jakby cień był rzucany pod konkretnym kątem.

To nie jest domyślne ustawienie w większości narzędzi, ale robi różnicę szczególnie przy większych cieniach. Zamiast równomiernego rozmycia wokół elementu, negative spread tworzy efekt światła padającego z określonego kierunku.

Ile warstw cieni jest za dużo?

W przykładzie kontenera James nie zawahał się użyć pięciu nałożonych efektów cienia. Stwierdził wprost, że to nie wydaje mu się dużo – czasem robi nawet więcej.

Każda warstwa pełni swoją funkcję:

  • Pierwsza tworzy subtelne obramowanie
  • Kolejne budują głębię
  • Ostatnie dodają miękkie podświetlenie lub ambient occlusion

Kluczowa zasada? Trial and error. James przyznał, że to zawsze próby i błędy, nie ma żadnego benchmarku. Po prostu eksperymentuje z wartościami, aż rezultat wygląda dobrze.

Co ciekawe, nie trzyma się okrągłych liczb. W projekcie użył 42% opacity w jednym miejscu, 16% w innym. To pokazuje jego iteracyjne podejście – nie istnieje uniwersalnie „poprawna” wartość.


Dark mode wymaga dedykowanych stylów

Początkowo projekt używał tych samych wartości cieni dla obu trybów, zmieniając tylko przezroczystość. James był jednak jasny – dark mode wymaga osobnego myślenia, nie jest to tylko odwrócenie kolorów.

Przyciski w dark mode – lekcja z Clerk

James podzielił się konkretnym przykładem z pracy w Clerk. Zespół miał solid stroke (dark blue albo dark gray) na przyciskach. Najpierw skupili się na light mode UI, ale gdy wprowadzili dark mode, powstał problem – stroke tworzył dziwne rozmycie wokół krawędzi przycisku.

Przyczyną była prosta niekonsekwencja: stroke dodający kontrast w light mode, w dark mode powodował „weird blurriness” gdy UI przewijało się pod przyciskiem.

Rozwiązanie? W dark mode całkowicie usunęli stroke z przycisku. Zamiast tego zastosowali białe obramowanie z bardzo niską przezroczystością (spread shadow), podczas gdy w light mode zachowali ciemniejszy solid stroke.

James podsumował to stwierdzeniem, że dark mode po prostu wymaga dodatkowego wysiłku. Nie można przenieść stylów 1:1 między trybami.

Problem z opacity borders na scrollowanych elementach

Pojawił się konkretny przypadek kontenera z opacity border. Gdy różne elementy (szczególnie obrazki) przewijały się pod tym borderem, efekt był nierówny. Border był intensywny na górze i jakby rozpływał się na dole przez różne tła.

James potwierdził, że to klasyczny problem opacity borders. Dlatego preferuje outer spread z niską przezroczystością – efekt „bleeding through” działa w obie strony, tworząc spójny wygląd niezależnie od kontekstu.

Kontrast w modals i overlays

Pierwszy projektant użył overlay z około 60% opacity. James od razu podkręcił to do 80%, argumentując, że kontrast jest tutaj najważniejszy. Element musi się wyróżniać.

Jednocześnie przestrzegał przed przesadą – dopóki widać jakiś kontekst pod spodem, pomaga to użytkownikowi zorientować się gdzie jest.


0.5px stroke – detal który robi różnicę

Projekt używał 0.5px stroke w kilku miejscach. James był tego entuzjastą, twierdząc, że w porównaniu do 1px daje to dużo bardziej wyraziste krawędzie.

To nie jest abstrakcyjna preferencja. Gdy obaj projektanci porównali komponenty obok siebie, różnica była widoczna. 0.5px dawało ostrość, której 1px nie osiągało.

Jest to szczególnie istotne w komponentach takich jak przyciski, pola formularzy czy karty. W produktach B2B SaaS, gdzie interfejs często składa się głównie z takich elementów, ten detal powtarza się setki razy.


Empty states – od nudnych do zapadających w pamięć

Projekt miał placeholder empty states z podstawowymi ikonami z biblioteki Phosphor. Pierwszy projektant przyznał wprost, że był to trzyminutowy placeholder i właśnie tak wyglądał.

James i jego podejście do ikon

Podczas dyskusji James przyznał, że ma „dziwny OCD” związany z ikonami – musi je rysować sam, w przeciwnym razie czuje się źle.

Oczywiście używa gotowych zestawów ikon jak Iconist do prototypów. Jednak w finalnym produkcie prawie zawsze rysuje custom ikony od zera. To nie tylko kwestia estetyki – własne ikony dają pełną kontrolę nad szczegółami i dopasowaniem do reszty interfejsu.

Live redesign w 15 minut

James wziął pustą ikonę wiadomości i na żywo pokazał transformację:

  1. Narysował custom kształt – zamiast płaskiej ikony użył pen tool w Figmie do stworzenia własnej koperty
  2. Dodał spójne style – gradient fill i shadows z tych samych wartości co secondary button
  3. Zbudował głębię – zastosował shadows i subtelny inner glow dla efektu 3D
  4. Dodał wizualny akcent – małą „kartę” wystającą z koperty jako dodatkowy element

Przy „karcie” James zastosował progressive blur technique do stworzenia efektu światła wychodzącego z koperty. Chciał uzyskać wrażenie, jakby światło emitowało się z wnętrza.

Problem? Progressive blur tworzy lekko rozmazane krawędzie. Rozwiązaniem była maska z ostrą linią, zachowująca ostre krawędzie przy zachowaniu efektu światła.

Rezultat powstał w 10-15 minut. Ilustracja wyglądała znacznie bardziej premium niż stock icon, ale jednocześnie była na tyle prosta, że można ją powtórzyć dla innych empty states.

Kolor w empty states – kiedy jest OK?

Pojawiło się pytanie od widzów o użycie primary color (niebieski) w ilustracji. James był ostrożny – zazwyczaj trzyma to przygaszone, bo jasny kolor może wyglądać jak aktywny element lub notyfikacja, nie jak pusty stan.

Wyjątek? Gdy empty state celebruje osiągnięcie. Przykładem jest „Inbox Zero” – tam użycie zielonego koloru z odcieniem celebracji ma sens.

A co z animacją?

Gdy pojawił się pomysł animacji empty state, James był pragmatyczny. Zapytał wprost, czy motion jest tu naprawdę potrzebny.

Jego stanowisko było jasne – można dodać motion, ale to opcjonalne. Najpierw należy zrobić dobrze statyczną wersję. Jeśli jest czas i narzędzia (wspomniał Jitter jako świetne do szybkich animacji), to fajne dodanie. Nie jest to jednak requirement dla dobrego empty state.

Pokazywał też przykład z pulsującym badge’em. Bardzo subtelny efekt, który może pomóc poprawić wrażenie produktu premium, ale znowu – optional.


System kolorów – rozdzielenie funkcji

Projekt używał niebieskiego (primary color) do większości akcentów, włącznie z badge’ami pokazującymi nieprzeczytane wiadomości. James zaproponował odważne rozwiązanie – osobny kolor dla notyfikacji. W tym przypadku zielony.

Tworzy to wyraźne rozdzielenie funkcji:

  • Niebieski = akcje, główne interakcje, branding
  • Zielony = notyfikacje, stany, alerty

James zauważył, że podoba mu się pomysł koloru praktycznie zarezerwowanego dla notyfikacji.

Konsekwentnie zastosowali to do badge’y z liczbą nieprzeczytanych, podkreśleń w zakładkach i akcentów w empty state „all caught up”.

White vs colored opacity – zmienne podejście

Przy okazji kolorów James przyznał coś interesującego. Zmienia to cały czas – używa pełnego koloru na solid borders albo po prostu robi white fill z niższą przezroczystością. To zależy od palety, z którą pracuje.

Pokazuje to istotną rzecz – nie ma jednego „poprawnego” podejścia. James dostosowuje technikę do konkretnej palety kolorów i kontekstu produktu. Czasem white z opacity daje lepszy efekt, czasem colored border z opacity.


Pola formularzy – inny problem, ta sama filozofia

Projekt miał input z inner shadow i transparent stroke. W dark mode wyglądało to zbyt kontrastowo. James podszedł do tego analogicznie jak do przycisków – dark mode dostał własne, lżejsze tło zamiast tylko zmiany przezroczystości. Default state był subtelniejszy, dopiero focused/active stawał się ciemniejszy.

Podobnie z borderem. W dark mode użył outer spreadu zamiast inner stroke, żeby zachować spójność z resztą komponentów.


Design tokens – dlaczego warto inwestować wcześniej

Pierwszy projektant konsekwentnie budował system zmiennych w Figmie, mimo że produkt był we wczesnej fazie. Normalnie byłoby to over-engineering.

Wyjaśnił jednak, że nigdy nie robiłby tego poziomu systematyzacji na obecnym etapie produktu, ale wszystkie AI tools są skuteczne, gdy mamy shared tokens między Figmą a kodem. Może po prostu samemu to zbudować.

To zmienia obliczenia. Wcześniej design system w early stage był waste of time – za dużo pracy, za mało zwrotu. Teraz? AI jest tak dobre jak inputy, które mu dajemy. Dobre tokeny oznaczają lepszy output z AI tools.

Konkretnie wspomniał Figma MCP dla prototyping, Cursor i Claude Code dla development oraz łatwość przełączania między narzędziami przy shared tokens.

Od primitive do semantic colors

Proces transformacji był konkretny. Zaczął od „reskinned Tailwind ramp” – podstawowe kolory w odstępach co 100 (gray-100, gray-200, etc).

Następnie przeszedł do semantic color system obejmującego container colors dla różnych typów powierzchni, fill colors dla komponentów, overlay values, text hierarchy oraz border system.

Cel? Perfect parity at the token level między Figmą a kodem, żeby móc swobodnie przełączać się między narzędziami.

James potwierdził wartość tego podejścia, szczególnie przy pracy nad dual-mode (light/dark). Gdy style są zorganizowane w zmienne, można eksperymentować z wartościami bez manualnego aktualizowania setek instancji.


Praktyczne wnioski

Tę sesję wyróżniała konkretność. Nie było ogólników „zależy od kontekstu” bez pokazania tego kontekstu.

Zasady, które przewijały się w rozmowie:

  • Konsekwencja ponad perfekcję – James wolałby zobaczyć ten sam język wizualny we wszystkich empty states (nawet jeśli prostszy) niż mix różnych stylów
  • Dark mode wymaga czasu – nie da się go dobrze zrobić przez proste zmniejszenie przezroczystości. Trzeba przemyśleć kontrast, cienie i często całkowicie inne wartości
  • Drobne detale się kumulują – 0.5px stroke, sposób nakładania cieni, negative spread, spójność w narożnikach. Każdy element to 1% różnicy, ale łącznie budują wrażenie produktu premium
  • Trial and error jest OK – James nie udawał, że ma gotowe odpowiedzi. Konsekwentnie testował różne wartości przezroczystości, rozmycia, spread, aż wyglądało dobrze
  • „Bleeding through” jako filozofia – to nie tylko technika, to sposób myślenia o layeringu w UI. Wszystko powinno się przenikać, tworzyć spójną głębię, nie ostre odcięcia

Checklisty do wykorzystania

✅ Dark mode – co sprawdzić przed publishem

  • Czy cienie mają inne wartości niż w light mode (nie tylko przezroczystość)?
  • Czy kontrast overlay’ów jest wystarczający (80%+ dla modalów)?
  • Czy przyciski nie mają rozmazanych krawędzi przez niewłaściwy stroke?
  • Czy pola formularzy w default state nie są zbyt kontrastowe?
  • Czy widać kontekst pod modalami/overlay’ami?
  • Czy wszystkie borders używają spreadu zamiast stroke dla spójności?
  • Czy przetestowałeś jak elementy wyglądają gdy scrollują się pod sobą?

✅ Cienie i głębia – techniczna checklista

  • Używasz 1px spread zamiast stroke dla obramowań?
  • Czy cienie „przeciekają” przez warstwy (bleeding through)?
  • Czy masz 3-5 warstw cieni dla komponentów z dużą głębią?
  • Czy pierwsza warstwa tworzy subtelne obramowanie?
  • Czy ostatnie warstwy dodają ambient occlusion?
  • Czy wypróbowałeś 0.5px stroke dla większej ostrości?
  • Czy rozważyłeś negative spread dla naturalnego efektu światła?
  • Czy iterujesz wartości (trial and error) zamiast trzymać się okrągłych liczb?

✅ Empty states – od placeholdera do premium

  • Czy ikona jest custom czy stock? (stock = okazja do upgrade)
  • Czy używasz tych samych stylów (gradienty, cienie) co w komponentach?
  • Czy wszystkie empty states mają spójny język wizualny?
  • Czy kolor jest przygaszony (chyba że celebracja)?
  • Czy motion jest potrzebny czy optional?
  • Czy tekst daje jasny next step użytkownikowi?
  • Czy wypróbowałeś progressive blur dla efektu światła?

✅ System kolorów i tokens

  • Czy primary color i notification color są rozdzielone?
  • Czy konsekwentnie stosujesz notification color w badge’ach?
  • Czy masz zmienne w Figmie zorganizowane dla light/dark mode?
  • Czy możesz zmienić wartość w jednym miejscu i zaktualizować wszystkie instancje?
  • Czy Twoje tokens są zsynchronizowane z kodem?
  • Czy przeszedłeś od primitive do semantic colors?

Narzędzia wspomniane w rozmowie

  • Figma – główne narzędzie do designu
  • Phosphor Icons – jako baza do customizacji
  • Iconist – jeden z lepszych zestawów ikon według Jamesa
  • Jitter – do animacji empty states
  • Cursor i Claude Code – do AI-assisted development
  • Figma MCP – dla lepszej integracji z AI tools
  • SheetJS – do pracy z Excelem w analysis tool

Kluczowy insight

Granica, która nie jest linią

Standardowo myślimy: aby oddzielić element od tła, należy dodać mu wyraźne, widoczne obramowanie (stroke).

W praktyce okazuje się, że: najbardziej naturalne oddzielenie nie pochodzi z twardej linii, ale z iluzji granicy stworzonej przez 1px spread z niską przezroczystością. To pozwala cieniom i tłu „przenikać” przez krawędź, integrując element z otoczeniem, zamiast sztucznie go izolować.

Dlaczego to jest istotne: gdy stosujesz solid stroke na przycisku, dobrze wygląda on na białym tle. Jednak umieść go nad obrazkiem, gradientem czy innym elementem UI i nagle masz rozmazaną krawędź. Spread z opacity automatycznie adaptuje się do kontekstu, bo pozwala tłu „przebijać” przez obramowanie. Komponent wygląda dobrze wszędzie, nie tylko w wyizolowanym przypadku w design system.

Test na jutro: następnym razem gdy będziesz dodawać border do komponentu, zamiast używać solid stroke (inner czy outer) spróbuj 1px spread shadow z 8-12% opacity. Umieść ten komponent nad różnymi tłami – jasnym, ciemnym, obrazkiem i sprawdź jak zachowuje spójność wizualną bez manualnego dostosowywania wartości.


Ten wpis jest częścią mojej kolekcji notatek z ciekawych podcastów, webinarów i innych treści, które uważam za wartościowe i do których sam chcę wracać. Materiał pochodzi z livestream sesji projektowej z Jamesem McDonaldem nad produktem Inflight.

More from the blog