Nie tak dawno temu wybierałem się do kina i tym sposobem trafiłem na stronę Cinema City. Skoro już tam trafiłem, stwierdziłem, że przyjrzę się jej nieco bliżej.
Wygląd/działanie
-
Pierwsze, co rzuciło mi się w oczy, to fakt, że do adresu strony krótko po wczytaniu zostaje doklejony pewien ciąg znaków:
#/buy-tickets-by-cinema?in-cinema=undefined&view-mode=list
. Jeśli weźmiemy pod uwagę, że URL stanowi część UI, to tego typu zaśmiecanie adresu bez przyczyny należy uznać za błąd. -
Po otwarciu i zamknięciu okienka pozwalającego wybrać swoje kino focus często się gubi i wraca na sam początek strony zamiast do przycisku, który otworzył to okienko. Co więcej, sam ten przycisk nie reaguje na naciśnięcie spacji ani też nie jest przedstawiany w drzewku dostępności jako przycisk (w kodzie jest nieprowadzącym donikąd linkiem).
-
Na podstronie logowania Unlimited niewłaściwe użycie
[tabindex]
sprawia, że nawigacja po stronie jest zaburzona. Najpierw focusowane są pola formularza, następnie linki w menu nawigacyjnym, a dopiero potem – linki znajdujące się po formularzu logowania. Dlatego tak ważne jest nieużywanie wartości większych niż0
(zero) w atrybucie[tabindex]
. -
Przy niektórych elementach interaktywnych (jak np. menu z wyborem języka strony) nie widać, gdzie znajduje się focus. To de facto uniemożliwia korzystanie z tych elementów wyłącznie przy użyciu klawiatury.
-
Kolejność niektórych elementów na ekranie nie zgadza się z ich kolejnością w focusowaniu, np. w sekcji Repertuar focus najpierw powinien pojawić się na menu Wybierz kino, nie na przyciskach z prawej strony.
-
Część treści strony znajduje się w zakładkach. Kliknięcie dowolnej z zakładek zmienia URL strony. Niemniej przejście pod dany URL przy pomocy przycisku Wstecz w przeglądarce nie powoduje przełączenia na daną zakładkę. Na fakt, że jest to błąd, wskazuje też fakt, że przejście bezpośrednio pod konkretny URL zakładki powoduje przełączenie na nią.
Kod
HTML
-
Cała strona wczytuje łącznie 60 zewnętrznych skryptów JS. Jak na tak prostą stronę jest to naprawdę monstrualna wręcz liczba. W oczywisty sposób odbija się to na wydajności.
-
Deklaracja kodowania znajduje się za tytułem strony, co stanowi potencjalną lukę w zabezpieczeniach.
-
W kodzie znajduje się sporo niestandardowych tagów, jak np.
header-component
czyschedule-component
. Nie są to jednak Custom Elements, a komponenty Vue (sądząc po kodzie). Co więcej, wszystkie tego typu elementy zostają zamienione nadiv
y z odpowiednimi klasami już po wczytaniu strony.To trochę dziwne, bo SSR powinien się sprawdzić tutaj bardzo dobrze. Zwłaszcza, że dla robotów renderowana zawartość niektórych komponentów jest dodana przez tagi
noscript
. Nie jest to najbardziej fortunna strategia, bo Google rozumie JS, a co więcej – używa aktualnego Chrome’a do wczytywania stron. -
W kodzie istnieje nagłówek najwyższego poziomu, który ma klasę
.seo
i który jest ukryty przy pomocydisplay: none
. Prawdopodobnie można to uznać za technikę content cloaking.Co więcej, hierarchia nagłówków na stronie jest mocno zaburzona. Nie ma sensownego nagłówka najwyższego poziomu, a także brakuje nagłówków trzeciego poziomu, mimo że w stopce pojawiają się nagłówki
h4
. -
<a href="https://www.cinema-city.pl/filmy/krol-lew/3248d2r" title="heros-krol-lew-dystrybutor" target="_self"> <div class="inner-container hidden-sm"> <button class="ms-layer btn-arrow-primary short" style="left:800px; top:300px;" href="https://www.cinema-city.pl/filmy/krol-lew/3248d2r" target="_self">KUP TERAZ </button> […] </div> </a>
Ten kod działa wyłącznie dlatego, że kliknięcie przycisku tak naprawdę powoduje odpalenie akcji związanej z linkiem (czyli przejście na odpowiednią podstronę). Osadzanie przycisku wewnątrz linku (lub na odwrót, linku wewnątrz przycisku) jest całkowicie bezsensowne. Te dwa elementy służą do zupełnie różnych celów. Link służy do przejścia w inne miejsce, a przycisk – do odpalenia jakiejś akcji. Co więcej, łączenie tych dwóch elementów ze sobą nie działa w niektórych przeglądarkach (np. Firefox nie obsługuje linków osadzonych w przyciskach). I wcale nie jest to błąd tych przeglądarek, bo specyfikacja HTML nie zezwala na łączenie tych elementów:
- Content model:
- Transparent, but there must be no interactive content or
a
element descendants. - [Model zawartości:
- Przezroczysty, ale nie może zawierać interaktywnej treści lub potomków będących elementami
a
.]
https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element
- Content model:
- Phrasing content, but there must be no interactive content descendant.
- [Model zawartości:
- Treść tekstowa, ale nie może zawierać interaktywnej treści.]
https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element
Interactive content is content that is specifically intended for user interaction.
a
(if thehref
attribute is present), […]button
[…][Interaktywna treść to treść, która jest wyraźnie przeznaczona do interakcji z użytkownikiem.
Element
a
(jeśli jest obecny atrybut[href]
), […],button
[…]]https://html.spec.whatwg.org/multipage/dom.html#interactive-content-2
-
Sporo obrazków nie posiada atrybutu
[alt]
. Spora część[alt]
stanowi też teksty marketingowe, np.:<a aria-label="VOUCHERY DLA FIRM" href="/vouchery-dla-firm" class="card promobox-card promobox-large" target="_self"> <div class="card-top"> <img class="card-img-top" src="/static/dam/jcr:ed3c1b94-c1a7-4bc4-a55b-38dd0bc767be" alt="Vouchery do Cinema City to idealny pomysł na prezent. Vouchery to otwarte bilety, które mogą zostać zrealizowane na dowolny film, w dowolnym miejscu i czasie, także na premiery i pokazy przedpremierowe. "> <div class="card-img-overlay text-bottom"> <p class="card-title mb-none">VOUCHERY DLA FIRM</p> </div> </div> </a>
Z punktu widzenia dostępności odpowiedni byłby tutaj pusty
[alt]
, ponieważ potrzebne informacje dostarcza tekst w akapicie znajdującym się bezpośrednio po obrazku. Co więcej, widać wyraźnie, że[alt]
jest kierowany przede wszystkim pod roboty wyszukiwarek, bo dla czytników ekranowych podaje się alternatywną treść linka, jako atrybut[aria-label]
linku.Przy okazji warto zwrócić uwagę, że tekst pisany w całości dużymi literami może być potraktowany przez czytnik ekranowy jako skrótowiec.
-
Niektóre elementy (jak np. całe menu w stopce) są duplikowane dla mniejszych ekranów. Nie bardzo rozumiem ten zabieg, bo przy dobrze zrobionym RWD takie rzeczy po prostu powinny się dostosowywać.
CSS
-
Spora część kodu CSS nie jest zminifikowana. Dodatkowo używane jest
@import
, które opóźnia wczytywanie skryptów. -
Do strony dołączane są style tylko do druku. Niemniej nie zawierają nic poza standardową zaślepką Compassa:
/* Welcome to Compass. Use this file to define print styles. * Import this file using the following HTML or equivalent: * <link href="/stylesheets/print.css" media="print" rel="stylesheet" type="text/css" /> */
-
.modal .table-summary table tbody tr td
– książkowy przykład antyselektora.
JS
-
W konsoli jest widoczna ciekawa informacja:
You are running Vue in development mode. Make sure to turn on production mode when deploying for production. See more tips at https://vuejs.org/guide/deployment.html
Ogólnie wszystkie informacje debugujące są wyrzucane do konsoli: o odpalanych zdarzeniach, o ustawionych ciasteczkach, o wykryciu lokalizacji użytkownika… Tego typu informacje nie powinny się znaleźć w aplikacji produkcyjnej. Co więcej, na fakt, że mamy do czynienia z aplikacją w wersji developerskiej wskazuje fakt, że wszystkie elementy aplikacji są dołączane jako oddzielne pliki JS (stąd jest ich aż 60!).
-
Warto też zauważyć, że komponenty zawarte na stronie mają swoje osobne bundle, z własnymi wersjami Vue. To wskazuje, że całość jest tworzona zgodnie z założeniami mikrofrontendów. Problem z pierwotnymi założeniami mikrofrontendów jest taki, że każda aplikacja na danej stronie jest całkowicie niezależna. To sprawia, że na jednej stronie wczytywanych jest często wiele wersji tego samego frameworka. Ten problem – jeśli wierzyć komunikatom z konsoli – jest także obecny na tej stronie.
Osobiście uważam, że pomysł mikrofrontendów jest sensowny, ale pod warunkiem, że używają tego samego stacku technologicznego. Na froncie kwestia wydajności jest o wiele bardziej paląca niż w backendzie, bo użytkownik widzi wszystko. Dlatego nawet wzorce architektoniczne powinny być podporządkowane wydajności.
Inna rzecz, że wymóg stosowania tego samego stacku sprawia, że mikrofrontendy stają się niemal tożsame z architekturą komponentową. Na nią z kolei rozwiązania istnieją od bardzo dawna, w postaci czy to naprawdę starego BEM, czy młodszych Web Components, czy niezliczonej wręcz liczby frameworków. Natomiast podstawy pod komunikację pomiędzy niezależnymi komponentami lata temu położyła architektura Zakasa-Osmaniego.
-
Na fakt, że mamy do czynienia z aplikacją w wersji developerskiej, wskazuje także fakt, że większość kodu JS nie jest zminifikowana (mimo że nazwy plików by na to wskazywały!).
Chyba najbardziej zastanawia fakt, dlaczego całość wygląda jak wersja developerska aplikacji, nie zaś – jak finalny produkt. Samo doszlifowanie tego aspektu zdecydowanie poprawiłoby choćby problemy z wydajnością.
Cześć.
Jedno mnie Comandeerze zastanawia. Skoro display:none ukrywa element przed technologiami asystującymi to dlaczego Twoje menu na urządzeniach mobilnych ma display:none? Do momentu naciśnięcia przycisku jest niewidoczne.
Hej,
tutaj ważny jest kontekst. Na stronie Cinema City w taki sposób ukrywany jest element, który powinien być zawsze dostępny. Z kolei na WK menu jest ukrywane wtedy, gdy jest zwinięte. Użytkownik technologii asystującej ma do niego dostęp, ponieważ jest przycisk rozwijający menu.
Nie wiedziałem, że tak to działa. Dzięki.
Mój mózg krwawi za każdym razem, gdy odwiedzam tę stronę.
TO JEST DRAMATYCZNE NIEPOROZUMIENIE pod względem UI i UX.
„CZY KTOŚ TO TETOWAŁ???”
No ale pewnie agencji, która to 'wyprodukowała’ hajs się zgadza…