chevron-left chevron-right

Jak korzystać z nowych własności CSS używając styled components i TypeScript?

Tworzenie aplikacji internetowych po stronie frontendu (tego przeglądarkowego) jest coraz bardziej złożone. Od dłuższego czasu coraz więcej projektów korzysta z TypeScript jako bazowej składni JS, co wiąże się też z tym że wymaga to skonfigurowania odpowiedniego środowiska developerskiego. W swoim projekcie bazującym na TypeScript i styled components spotkałem się z pewnym problemem związanym z brakiem możliwości korzystania z nowych własności CSS. O tym w dalszej części tekstu.

Czym są styled components?

Na początek wyjaśnię czym są styled components. Jest to rozwiązanie bardzo popularne w środowisku programistów React, polegające na tym, aby style CSS były ściśle powiązane z komponentami React. Tylko tyle i aż tyle. Dzięki temu zarządzanie kodem staje się znacznie uproszczone w dłuższym okresie czasu. Pisanie kodu styled components przypomina miks modułów CSS i SASSa.

Jaki problem rozwiązuje styled components?

Korzystanie ze styled components rozwiązuje szereg problemów z którymi spotykają się na co dzień programiści frontend piszący kod w tradycyjny sposób (czytaj osobno JS i osobno CSS). Główne problemy które zostały rozwiązane w ten sposób to:
  • W znaczący sposób ograniczono scope (czyt. zakres działania) kodu CSS. Kod CSS jest przypisany bezpośrednio do komponentu i jego elementów składowych:
    // Item.theme.tsx
    export const Item = styled.li`
        display: grid;
        grid-template-areas: 
                'title title actions'
                'image content content'
                'meta ad .';
    }
    Który może być wykorzystany w następujący sposób:
    // List.tsx
    import * as React from 'react';
    
    import { Item } from './Item.theme';
    
    export const List = (): JSX.Element => {
        return (
      Element 1 Element 2
    
        );
    }
    Co ciekawe, jeśli w innym komponencie będzie styled component o nazwie Item to jego style zostaną przetłumaczone na klasę CSS z innym, unikalnym hashem. Dzięki temu, możemy mieć wiele różnych elementów Item wykorzystanych w wielu różnych, niepowiązanych komponentach i nie musimy się martwić o to, że style będą kolidowały.
  • Do wykonania obliczeń wartości własności CSS możemy wykorzystywać kod JS bezpośrednio wewnątrz styli komponentu:
    interface Props {
        isImportant: boolean;
    }
    
    export const Item = styled.div`
        font-size: ${({ isImportant }): string => isImportant ? '32px' : '16px' };
    `;
  • Ułatwiono długoterminowe zarządzanie stylami komponentu. Jeśli jakiś styled component nie jest używany w kodzie docelowego komponentu, to po prostu usuwamy jego kod bez obawy, że jego usunięcie zepsuje jakiś niepowiązany ficzer. To co ważne, należy unikać pisania kodu w stylu:
    export const Item = styled.div`
        width: 100%;
    
        div {
            padding: 16px;
    
            p {
                font-size: 14px;
            }
        } 
    `;
    W takiej sytuacji nieważne jest to, że styled component o nazwie Item już nie jest używany. Może się okazać, że zagnieżdżone komponenty korzystały z jego stylów, czyli zadziałała klasyczna kaskadowość stylów CSS.
Do wad na pewno należy zaliczyć potencjalne obniżenie wydajności takiej aplikacji, jeśli w kodzie styled components mamy dużo obliczeń matematycznych przy każdej zmianie propsów przekazywanych do takiego komponentu. Potencjalnym rozwiązaniem tego problemu może być wykorzystanie zmiennych CSS natywnie działających w przeglądarce, ale to już temat na inny artykuł.

ts-styled-plugin - unknown property

ts-styled-plugin unknown error highlighted code To tyle tytułem wstępu do problemu: w moim przypadku kiedy pisałem kod styled components i chciałem wykorzystać najnowsze własności CSS, to spotkałem się z problemem: Unknown property: 'content-visibility' - ts-styled-plugin(9999) i zastanowiło mnie jak to rozwiązać? ts-styled-plugin error message Przez tą informację o błędzie nie mogłem kompilować kodu TypeScript. Okazało się, że rozwiązanie jest zaskakująco proste.

Jak korzystać z nowych własności CSS w kodzie TypeScript?

Aby rozwiązać ten problem, wystarczyło zmodyfikować plik konfiguracyjny TypeScript w następujący sposób:
//tsconfig.json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-styled-plugin",
        "lint": {
          "validProperties": ["content-visibility", "contain-intrinsic-size"]
        }
      }
    ]
  }
}
Dodałem informację o tym, aby TypeScript świadomie akceptował nieznane sobie nazwy własności CSS. Tym samym, jesteśmy w stanie rozwiązać problem z akceptowaniem przez TypeScript nieznanych własności CSS.

Podsumowanie

W tym wpisie wyjaśniłem pokrótce czym są styled components oraz przedstawiłem rozwiązanie problemu jakim może być używanie nieznanych TypeScriptowi własności CSS w kodzie tychże komponentów. Jeśli interesuje ciebie czym są własności: content-visibility oraz contain-intrisic-size to warto zapoznać się tekstem na stronie Google Developers, gdzie zostało to ładnie wyjaśnione. W skrócie, chodzi o optymalizację renderowania elementów na stronie w momencie, gdy nie pojawiają się w widocznej części okna przeglądarki po załadowaniu strony. To potencjalnie może znacząco poprawić performance score w narzędziu Page Speed Insights od Google.