RWD i SASS jak się za to zabrać? Mobile first vs Desktop first.

Lubisz pisać responsywne strony i aplikacje? Znasz już kilka technik CSS których używasz przy RWD i nie masz nic przeciwko aby poznać coś nowego? A może to wszystko dopiero przed Tobą? Tutaj dowiesz się jak można podejść do tego tematu używając SASS’a.

Czego się dzisiaj dowiesz?

Będzie krótki wstęp do tego czym w ogóle są responsywne strony internetowe. Potem opiszę technikę tworzenia responsywnych widoków przy użyciu CSS Math a na końcu o filozofii Mobile First oraz Desktop First i jaka jest różnica między nimi.

Seria SASS

W skład serii wchodzą:

  1. Podstawy SASS – struktura kodu, importy, zmienne, mixiny i extendy.
  2. RWD i CSS Math. Jak sobie z tym poradzić? Mobile First vs Desktop First.
  3. Zaawansowany SASS – funkcje, pętle i logika.

Czym jest Responsive Web Design – RWD?

Jak sama nazwa wskazuje chodzi tutaj o design czyli generalnie projekt graficzny. Responsive oznacza “odpowiadający”. Odpowiadający czemu? Odpowiadający rozdzielczości ekranu. Reasumując, projekt graficzny/wygląd ma odpowiadać rozdzielczości ekranu.

Jaka znowu rozdzielczość?

A no nie jest to dla Ciebie tajemnicą, że internet może być przeglądany na rozmaitych urządzeniach tzn. komputery stacjonarne, laptopy, tablety, smartfony itp. Każde z tych urządzeń ma inną rozdzielczość/wielkość ekranu a co za tym idzie przeglądarka inaczej wyświetla zawartość stron internetowych.

Jakie mamy rozdzielczości ekranów?

Producenci sprzętów prześcigają się rozmaitych formatach niemniej są pewne wielkości używane jako standardowe:

4K – 4096px x 2304px

Taka rozdzielczość jest używana przy współczesnych monitorach o wysokiej rozdzielczości. Czyli ekran jest bardzo szeroki i wysoki. Generalnie jak starasz się stworzyć widok pod konkretną rozdzielczość to musisz po prostu dysponować sprzętem który tą rozdzielczość obsługuje. Nie zoptymalizujesz widoku 4K mając monitor HD itd.

HD – 1920px x 1080px

Standardowa rozdzielczość większość monitorów (np. 24 calowych).

Laptop 15’’ – 1366px x 768px

Standardowa rozdzielczość dla większość laptopów.

Laptop 13’’ – 1280px x 720px 

Standardowa rozdzielczość dla mniejszych laptopów.

Tablet – 1024px x 768px

Standardowy tablet ma właśnie taką rozdzielczość. Teraz wchodzimy w sferę urządzeń mobilnych wiec trzeba mieć na uwadze, że ekran można przekręcić i wtedy rozdzielczość się “odwraca”.

Mały tablet 640px x 480px

Zdarzają się mniejsze tablety np. Samsunga które działają na tej rozdzielczości.

iPhone Plus – 414px x 736px

Duże komórki takie jak np. iPhone Plus.

Mniejsze komórki <375px x  <667px

Czyli większość używanych dzisiaj telefonów komórkowych.

Jak widać rozdzielczości jest dużo a te wymienione wyżej są tylko orientacyjne…

Pod jakie rozdzielczości optymalizować projekty?

Powiedziałbym im więcej tym lepiej 🙂 Ale wiadomo, że jest to bardziej czasochłonne. Takie rzeczy są zazwyczaj w specyfikacji projektu, a jeśli takiej specyfikacji nie masz bo np. tworzysz swój własny projekt to… decyzja należy do Ciebie!

Jak tworzyć strony RWD?

Skoro już wiemy czym jest RWD to kolejnym pytaniem jest jak się za to zabrać? Z definicji wynika, że chodzi nam o widoki a widoki to wiadomo… tworzy się przy użyciu CSS. A więc RWD tworzy się przy użyciu CSS.

Układ strony

Każda strona internatowa ma swoją “strukturę” jeśli chodzi o układ poszczególnych elementów znajdujących się na niej tzn. jest podzielona na kolumny i rzędy o odpowiedniej wysokości czy szerokości. Szczegółowe parametry “struktury” strony są definiowane jej zawartością czyli które informacje i w jaki sposób mają być wyświetlane. Zajmą one wtedy określoną ilość miejsca. Uproszczony schemat wygląda tak:

RWD ma za zadanie dostosować ten układ do konkretnego rozmiaru ekranu. Określa które informacje mają być wyświetlone np. na smartfonie a które mogą być… ukryte bo mogą nie być aż tak istotne w punktu widzenia funkcjonalności aplikacji. No to jak się za to zabrać?

Media queries

Zanim zaczniemy pisać CSSy trzeba w pliku .html umieścić następujący meta-tag:

<meta name="viewport" content="width=device-width, initial-scale=1">

Do definiowania widoków dla poszczególnych rozdzielczości służą @media-queriesMedia query jest to specjalny blok kodu w którym umieszczamy reguły CSS dotyczące konkretnej rozdzielczości. Jak to wygląda w SASS?

.container {
    background-colour: blue;
}

// media query
@media (max-width: 1024px) {
    .container {
        background-colour: red;
    }
}

Powyższy blok kodu oznacza, że dany element ma tło w kolorze niebieskim. Jeśli rozdzielczość ekranu zmniejszy się do 1024px to tło zmieni kolor na czerwony. Proste?

Oczywiście w praktyce wygląda to bardziej skomplikowanie jednak zasada jest taka sama. Wybieramy dla jakich rozdzielczości chcemy dopasować widok ( breakpoints ) a następnie piszemy dodatkowe reguły CSS dla każdej rozdzielczości używając media-query. Potrafi to być dość czasochłonne…

Bardzo fajnie wytłumaczone to jak pisać RWD w SASS jest wytłumaczone w tym artykule.

Jakich jednostek CSS używać?

Chodzi o jednostki absolutne np. px lub względne np. em. Więcej info tutaj. To których używać przy stylowaniu RWD? Szczerze to ciężko mi się do tego jednoznacznie ustosunkować. Mi się wydaje, że jednostki absolutne w tym przypadku są bardziej czytelne. Może napiszesz w komentarzu co o tym sądzisz?

Układ strony i RWD

Wróćmy do układu strony. Często to jest największym wyzwaniem bo ilość i szerokość poszczególnych kolumn z zawartością zmienia się wraz z rozdzielczością. Jak to wszystko opanować?

Tutaj do gry wchodzą frameworki CSS które tworzą nam specjalną strukturę. Na chwilę obecną przed konkurencję wybija się Bootstrap i w zasadzie na nim lepiej się skupić. Do obsługi RWD służy ichniejszy grid-system. Generalnie Bootstrap jest super ale…

Framework to zawsze dodatek który ułatwia pracę ale może odciągać od tego co jest najważniejsze czyli… dobrej znajomości samego języka… w tym wypadku CSS. Czyli w porównaniu core vs framework dla mnie wygrywa core. No więc…

CSS wprowadził super właściwość zwaną grid która pozwala w stosunkowo łatwy sposób modyfikować układ strony. Jednak trzeba mieć na uwadze to, czy przeglądarka pod którą przygotowujesz swoją aplikację będzie obsługiwać grida.

Co jeszcze mogę zrobić?

Jeśli jednak nie chcesz lub nie możesz korzystać z wyżej wspomnianych narzędzi zawsze możesz modyfikować układ strony za pomocą własnych reguł. W tym wypadku każda kolumna, każdy rząd ma oddzielnie zdefiniowane wymiary w zależności od potrzeb projektu. Jest to żmudna praca ale czasami warto.

.menu {
    width: 20%;
    height: 300px;
}

.content {
    width: 80%;
    height: 800px;
}

CSS Math

Teraz czas na technikę którą chciałbym się Wami podzielić czyli trochę matematyki 😛 Tak w zasadzie wszystkie manewry które zaraz opiszę można rozwiązać na inne sposoby ale… Warto też znać takie podejście 🙂

Założenie jest takie, mamy kontener z dużą ilością mniejszych elementów np. sklep internetowy a w nim dużo produktów. Stworzyłem sobie kontener za pomocą flexboxa, dałem produktom stały rozmiar tzn. 150px/150px i niech to wygląda np. tak:

See the Pen rwd_1 by Bart (@bedekodzic) on CodePen.

Generalnie wszystko ładnie mi się zawija wraz ze zmianą rozdzielczości. Trochę się podrówna i będzie… Ale co jeśli chce mieć kontrolę nad tym np. ile przedmiotów znajdzie się w każdym rzędzie w zależności od rozdzielczości?

Interpolation of Strings

Jeszcze chciałbym krótko napisać o jednej z właściwości SASS’a która umożliwia dynamiczną modyfikację nazw selektorów np.

Chcesz ostylować klasę “house” więc używasz następującego kodu:

.house {
    width: 50%;
}

A teraz co jeśli chcesz zrobić to samo z klasą “house-5” ale numer porządkowy ma być przypisany do zmiennej? Można to zrobić to np. tak:

$house-number: 5;

.house-#{$house-number} {
    width: 50%;
}

Taka operacja to właśnie interpolacja nazw selektorów. Zaraz użyję tej właściwości w praktyce…

CSS Math i RWD

No dobra i jak to wszystko się ma do siebie? Otóż wrócę do tego sklepu. Przy pomocy właściwości SASS’a i CSS Math napiszę formułę która pozwoli na kontrolę ilości elementów w jednym rzędzie:

@mixin rwd-layout($number, $margin) {
    // określam odstępy między elementami
    margin-right: $margin;
    margin-bottom: $margin;
    // formuła określająca szerokosc elementu
    width: ((100% - ($margin * ($number - 1))) / $number);
}

.container {
    text-align: center;
    padding: 2%;
    display: flex;
    flex-wrap: wrap;
    .container__item {
        border: 1px solid grey;
        border-radius: 5px;
        box-sizing: border-box;
        // wywoluje mixin dla 5 elementów i 1% margin
        @include rwd-layout(5, 1%);
        img {
            margin-top: 2%;
            max-width: 70%;
            max-height: 70%;
        }
        p {
            margin: 5px;
        }
    }
}

Co tu się stało się? Po prostu mixin określa ile elementów ma zajmować 100% kontenera (czyli jeden rząd) i jaki ma być między nimi odstęp np. mamy 5 elementów i 1% odstępu między (margin-right) nimi więc każdy element ma mieć szerokość:

( 100% – 5 * 1% ) / 5

ale… przecież nie ma 5 odstępów między 5 elementami tylko 4 odstępy więc prawidłowa formuła to:

(100% – 4 * 1% ) / 5

więc:

(100% – (n-1) * margin ) / n

czyli w takim wypadku musimy usunąć odstęp w każdym ostatnim elemencie każdego rzędu. Trzeba zmodyfikować mixin…

@mixin rwd-layout($number, $margin) {
    margin-bottom: $margin;
    width: ((100% - ($margin * ($number - 1))) / $number);
    &:nth-child(n) {
        margin-right: $margin;
    }
    &:nth-child(#{$number}n) {
        margin-right: 0%;
    }
}

No… i wszystko działa jak należy!

Media Query

Wiemy już jak kontrolować liczbę elementów w rzędzie. Dostosujmy to więc do RWD:

@media (max-width: 1024px) {
    .container {
        .container__item {
            @include rwd-layout(5, 1%);
        }
    }
}

@media (max-width: 768px) {
    .container {
        .container__item {
            @include rwd-layout(4, 1%);
        }
    }
}

@media (max-width: 414px) {
    .container {
        .container__item {
            @include rwd-layout(2, 1%);
        }
    }
}

No i działający przykład:

See the Pen rwd_2 by Bart (@bedekodzic) on CodePen.

Minusy

Minusem tego podejścia (poza dodatkowym wysiłkiem oczywiście) jest kwestia wysokości kontenerów z przedmiotami. Otóż w tym momencie dostosowuje się ona do zawartości ale co jeśli chcemy np. idealne kwadraty?

Opcja 1

Możemy manualnie sterować wysokością poprzez dawanie paddingów/marginów wewnątrz każdego z elementów:

.container__item {
    border: 1px solid grey;
    border-radius: 5px;
    box-sizing: border-box;
    @include rwd-layout(6, 1%);
    img {
        margin-top: 10%;
        max-width: 70%;
        max-height: 70%;
    }
    p {
        margin: 5px;
    }
}

Trochę to mozolne…

Opcja 2

W mixinie dodajemy padding-top równy szerokości tzn:

padding-top: ((100% - ($margin * ($number - 1))) / $number);

W ten sposób mamy idealny kwadrat ale…

Musimy wtedy zawartość kontenera ustawić na position:absolute :

<div class="container__item">
   <div class="container__item--cont">
      <img src="https://1.allegroimg.com/s128/01e27a/4c43c9f946cdb46fa33bb239d3c1" alt="">
      <p>Super FOOD</p>
   </div>
</div>
.container__item {
    position: relative;
    .container__item--cont{
        position: absolute;
        img {
        //
        }
        p {
        //
        }
    }
}

Tak czy inaczej ta technika jest dość ciekawa 🙂 Jedziemy dalej z tym wpisem…

Desktop First

Skoro pisanie kodu RWD nie jest juz nam obce to spójrzmy na dwie podstawowe metodyki pisania CSS. Pierwszą z nich jest Desktop First.

Polega to na tym, że urządzeniem na które domyślnie piszemy style na samym początku jest ekran o dużej rozdzielczości (przekątnej). Potem z pomocą media query max-width przechodzimy do coraz mniejszych wyświetlaczy. Kod wygląda np tak:

// PIERWOTNY KOD CSS

.container {
  //
}

@media (max-width: 1366px) {
    // NOWY KOD CSS
}

@media (max-width: 1024px) {
    // NOWY KOD CSS
}

@media (max-width: 768px) {
    // NOWY KOD CSS
}

@media (max-width: 414px) {
    // NOWY KOD CSS
}

Mobile First

W związku z tym, że w ostatni latach udział urządzeń mobilnych drastycznie rośnie wyciągnięto wniosek, że widoki mobilne mają większy priorytet. Dlatego przy projektowaniu, kodowaniu aplikacji należy zacząć właśnie od nich.

Sytuacja jest analogiczna tylko odwrotna. Zaczynamy pisać CSS’y a następnie za pomocą media query min-width określamy reguły dla coraz to większych urządzeń:

// PIERWOTNY KOD CSS

.container {
   //
}

@media (min-width: 414px) {
    // NOWY KOD CSS
}

@media (min-width: 768px) {
    // NOWY KOD CSS
}

@media (min-width: 1024px) {
    // NOWY KOD CSS
}

@media (min-width: 1366px) {
    // NOWY KOD CSS
}

Ot cała filozofia 🙂

Podsumowanie

Choć cała koncepcja RWD wygląda w miarę prosto, to napisanie fajnego i łatwego w utrzymaniu kodu wymaga sporo wprawy. No ale wiadomo, jak rozumiemy co tam się dzieje i znamy dobre praktyki to wszystko jest tylko kwestią czasu 🙂

Na końcu tradycyjna już prośba. Drogi czytelniku, jeśli mój wpis zawiera jakieś błędy myślowe, ominąłem coś ważnego lub po prostu walnąłem gafę to napisz proszę o tym w komentarzu! Dziękuję 🙂


Bartek Cis

Piszę dla was tego bloga bo lubię aplikacje internetowe. Mogę je projektować, kodować a potem o nich pisać czując dreszczyk ekscytacji za każdym razem gdy trafię na coś nowego. Bo uczymy się całe życie. Prawda?
  • Jeśli mówimy o purystycznym podejściu do RWD, to w takim obrazku jednostek absolutnych praktycznie nie ma, bo żaden element strony nie ma sztywnych wymiarów. Jeśli stronę można oglądać zarówno na smartwachu, jak i ekranie 4k, to logicznym wydaje się, że zamiast jednostek absolutnych (które sprawią, że 300px to będzie zawsze 300px, co na jednym ekranie zajmie 95% a na drugim 5%) wypada myśleć i pracować na relacjach pomiędzy elementami czy proporcjach. Zresztą nowsze narzędzia layoutowe w CSS takie myślenie wspierają – czy to flexbox, czy to grid (który wręcz wprowadzana nową jednostkę – `fr`, fraction). Tu od razu warto zauważyć, że w ostatnich miesiącach doszło do przesunięcia paradygmatu i miejsce RWD zaczyna zajmować IWD – Intrinsic Web Design → https://adactio.com/journal/13671

    Przy okazji: nie warto linkować W3Schools jako źródła, bo nawet ta tabelka z jednostkami jest niekompletna. Dla porównania tabelka z MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/length – a to tylko długość, bez wchodzenia w inne typy jednostek (jak choćby kąty itd.).

    • Bartłoś Ce

      Super komentarz 🙂 Dzięki!

  • O stary, gif z paragrafu „Jakich jednostek CSS używać?” ostro zrył mi beret z samego rana. Hahaha :D.

    Dzięki za świetny artykuł :)!

    • Bartłoś Ce

      Hehe no ten gif coś w sobie ma… Jak juz patrze na niego któryś raz to chcę przewijać w dół ale jeszcze na moment zerkam…

  • Mateusz Pieszczyk

    Miodzio wpis! Z niecierpliwością czekam na kolejny z tej serii 🙂

    W kwestii jednostek, moim zdaniem wszystko zależy od tego co chcemy osiągnąć i jak ostylowany element ma się wyświetlać. Ja z przyzwyczajenia korzystam z jednostek absolutnych, ale powoli zaczynam „przeskakiwać” na względne, bo dają dużo większą elastyczność w porównaniu do tych pierwszych (bynajmniej według moich odczuć).

    Pozdrawiam 🙂

  • mklkj

    „`
    @media (max-width: 1024px) {
    –.container {
    —-.container__item {
    ——@include rwd-layout(5, 1%);
    —-}
    –}
    }
    „`

    Niepotrzebne zagnieżdżenie selektora. Tak byłoby chyba poprawniej (+ zagnieżdżone @media):

    „`
    .container {
    –&__item {
    —-@media (max-width: 1024px) {
    ——@include rwd-layout(5, 1%);
    —-}
    –}
    }
    „`

  • Bardzo ciekawy artykuł! Zakochałem się w tym gifie ❤️