Podstawowy opis tworzenia komponentu ustawień z suwakowymi i opcjonalnymi polami wyboru.
W tym poście chcę podzielić się z Wami swoimi przemyśleniami na temat tworzenia komponentu Ustawienia na potrzeby stron internetowych, który jest responsywny, obsługuje dane wejściowe z różnych urządzeń i działa w różnych przeglądarkach. Wypróbuj wersję demonstracyjną.
Jeśli wolisz film lub chcesz zobaczyć, jak wygląda interfejs użytkownika, który tworzymy, obejrzyj ten krótszy film na YouTube:
Omówienie
Aspekty tego komponentu podzielono na te sekcje:
- Układy
- Kolor
- Pole do wpisania niestandardowego zakresu
- Niestandardowe pole wyboru
- Ułatwienia dostępu
- JavaScript
Układy
To pierwsze wyzwanie z interfejsem graficznym, w którym wszystko jest w CSS Grid. Oto każda siatka wyróżniona za pomocą Narzędzi deweloperskich w Chrome:
Tylko dla przerwy
Najczęstszy układ:
foo {
display: grid;
gap: var(--something);
}
Nazywam ten układ „just for gap”, ponieważ wykorzystuje on tylko siatkę do dodawania przerw między blokami.
Tę strategię stosuje 5 schematów. Oto ich lista:
Element fieldset
, który zawiera każdą grupę danych wejściowych (.fieldset-item
), używa elementu gap: 1px
do tworzenia cienkich linii oddzielających elementy. Nie ma trudnego rozwiązania dotyczącego granicy.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Zawijanie do siatki
Najbardziej skomplikowanym układem okazał się makroukład, czyli układ logiczny w systemie <main>
i <form>
.
Wyśrodkowywanie treści otaczających
Zarówno flexbox, jak i grid umożliwiają align-items
lub align-content
, a w przypadku elementów z zawijaniem wyrównania układu content
będą rozmieszczać elementy podrzędne w grupie.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
Głównym elementem jest użycie place-content: center
skrótu do wyrównania, aby elementy podrzędne były wyrównane pionowo i poziomo w układzie z 1 i 2 kolumnami.
W powyższym filmie widać, że „treści” pozostają wyśrodkowane, mimo że nastąpiło łamanie.
Powtórz automatyczne dopasowanie minmax
<form>
używa w przypadku każdej sekcji układu siatki adaptacyjnej.
Ten układ przełącza się z 1 na 2 kolumny w zależności od dostępnej przestrzeni.
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
Ta siatka ma inną wartość dla atrybutu row-gap
(--space-xl) niż dla atrybutu column-gap
(--space-xxl), aby nadać niestandardowy charakter układowi responsywnemu. Gdy kolumny są ułożone w stosie, chcemy, aby między nimi było dużo miejsca, ale nie tak dużo jak na szerokim ekranie.
Właściwość grid-template-columns
używa 3 funkcji CSS: repeat()
, minmax()
i min()
. Una Kravets opublikowała świetny post na blogu na temat układu, nazywając go RAM.
W porównaniu z aplikacją Una nasz układ zawiera 3 specjalne dodatki:
- Przekazujemy dodatkową funkcję
min()
. - Określamy
align-items: flex-start
. - Do wyboru jest styl
max-width: 89vw
.
Dodatkowa funkcja min()
jest dobrze opisana przez Evana Minto w jego blogu w artykule Automatycznie dostosowywany układ CSS za pomocą funkcji minmax() i min().
Polecam przeczytać ten artykuł. Poprawka wyrównania flex-start
ma na celu usunięcie domyślnego efektu rozciągania, dzięki czemu elementy podrzędne tego układu nie muszą mieć jednakowej wysokości, ale mogą mieć naturalną, właściwą wysokość. W filmie w YouTube znajdziesz krótkie omówienie tego dodatku.
max-width: 89vw
warto omówić w tym poście.
Pokażę Ci układ z zastosowaniem stylu i bez niego:
Co się dzieje? Gdy określono wartość max-width
, służy ona do zapewnienia kontekstu, rozmiaru docelowego lub określonego rozmiaru, aby algorytm układu auto-fit
wiedział, ile powtórzeń może zmieścić w danej przestrzeni. Wydaje się oczywiste, że przestrzeń ma „pełną szerokość”, ale zgodnie ze specyfikacją siatki CSS należy podać określony rozmiar lub maksymalny rozmiar. Podano maksymalny rozmiar.
Dlaczego 89vw
? Ponieważ „działało” w przypadku mojego układu.
Razem z kilkoma innymi osobami z zespołu Chrome sprawdzamy, dlaczego bardziej rozsądna wartość, taka jak 100vw
, nie wystarcza i czy jest to rzeczywiście błąd.
Odstępy
Harmonia tego układu wynika głównie z ograniczonej palety odstępów, a ściślej mówiąc z 7.
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
Te elementy świetnie współdziałają z siatką, CSS @nest i składnią poziomu 5 @media. Oto przykład pełnego zestawu stylów układu <main>
.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
Siatka z wyśrodkowanymi treściami, z umiarkowanym marginesem (jak na urządzeniach mobilnych). Gdy jednak staje się dostępna większa przestrzeń w widoku, obraz rozszerza się, zwiększając odstępy. Wygląda na to, że usługa porównywania cen w 2021 r. będzie całkiem niezła.
Pamiętasz wcześniejszy układ „just for gap”? Oto bardziej szczegółowy opis tego, jak wyglądają w tym komponencie:
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
Kolor
Umiejętne używanie kolorów sprawiło, że ten projekt wyróżniał się wyrazistością, a jednocześnie minimalizmem. Ja robię to tak:
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
Nazwy kolorów powierzchni i tekstu nadaję za pomocą liczb, a nie nazw takich jak surface-dark
i surface-darker
, ponieważ w zapytaniu o media będę je przełączać, a jasny i ciemny nie będą miały znaczenia.
W zapytaniu o preferowane media odwracam je w ten sposób:
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
Zanim zagłębisz się w szczegóły składni kolorów, warto najpierw przyjrzeć się ogólnemu obrazowi i strategii. Ale ponieważ trochę wyprzedzam fakty, cofnę się trochę.
LCH?
Nie wchodząc zbyt głęboko w teorię kolorów, można powiedzieć, że LCH to składnia zorientowana na człowieka, która uwzględnia sposób postrzegania kolorów przez ludzi, a nie sposób pomiaru kolorów za pomocą matematyki (np. 255). Daje to wyraźną przewagę, ponieważ ludzie mogą łatwiej pisać w tym języku, a inni ludzie będą rozumieć te zmiany.
W tym pokazie skupimy się na składni i wartościach, które zmieniam, aby uzyskać jasne i ciemne kolory. Spójrzmy na 1 powierzchnię i 1 kolor tekstu:
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0)
to jasność 10%
, chroma 0 i ton 0: bardzo ciemny bezbarwny szary. Następnie w zapytaniu o multimedia w trybie jasnym jasność jest ustawiona na 90%
z --surface1: lch(90 0 0);
. I to jest sedno tej strategii. Zacznij od zmiany jasności między 2 motywami, zachowując współczynniki kontrastu wymagane przez projekt lub takie, które mogą zapewnić dostępność.
Dodatkową zaletą lch()
jest to, że jasność jest dostosowana do potrzeb użytkowników, a %
zmiana będzie dla nich wyczuwalna i konsekwentna.%
Na przykład hsl()
nie jest tak niezawodny.
Jeśli chcesz, możesz dowiedzieć się więcej o przestrzeniach barw i lch()
. Już nadchodzi.
Obecnie CSS nie ma dostępu do tych kolorów. Powtórzę: nie mamy dostępu do jednej trzeciej kolorów na większości nowoczesnych monitorów. Nie są to dowolne kolory, ale najżywsze kolory, jakie ekran może wyświetlić. Nasze witryny są wyblakłe, ponieważ sprzęt monitora ewoluował szybciej niż specyfikacje CSS i implementacje przeglądarek.
Lea Verou
Elastyczne elementy sterujące formularzem z schematem kolorów
Wiele przeglądarek zawiera opcje motywu ciemnego, obecnie są to Safari i Chromium, ale musisz określić w CSS lub HTML, że Twoja grafika korzysta z tych opcji.
Powyższa ilustracja pokazuje efekt właściwości w panelu Styl w DevTools. Demonstracja używa tagu HTML, który moim zdaniem jest ogólnie lepszym miejscem:
<meta name="color-scheme" content="dark light">
Więcej informacji na ten temat znajdziesz w tym color-scheme
artykule Thomasa Steinera. Możesz zyskać znacznie więcej niż tylko możliwość zaznaczania pól wyboru.
CSS accent-color
Ostatnio pojawiła się aktywność dotycząca elementu accent-color
w elementach formularza. Jest to pojedynczy styl CSS, który może zmienić kolor zabarwienia używany w elementach wejściowych przeglądarki. Więcej informacji znajdziesz tutaj na GitHubie. Dołączyłem go do stylów tego komponentu. Ponieważ przeglądarki obsługują tę funkcję, pola wyboru będą bardziej pasować do różowych i fioletowych akcentów.
input[type="checkbox"] {
accent-color: var(--brand);
}
Wyostrzenie kolorów z usztywnionymi gradientami i fokusem
Kolor najbardziej przyciąga uwagę, gdy jest używany oszczędnie. Jednym ze sposobów na osiągnięcie tego efektu jest wykorzystanie kolorowych interakcji w UI.
W powyższym filmie występuje wiele warstw interakcji i sprzężenia zwrotnego interfejsu, które nadają interakcji charakteru dzięki:
- Wyróżnianie kontekstu.
- Przekazywanie informacji zwrotnych dotyczących interfejsu użytkownika o tym, jak bardzo wartość mieści się w zakresie.
- wyświetlanie informacji w interfejsie, że pole akceptuje dane wejściowe;
Aby zapewnić informacje zwrotne po interakcji z elementem, CSS używa pseudoklasy :focus-within
do zmiany wyglądu różnych elementów. Przyjrzyjmy się bliżej temu elementowi: .fieldset-item
.
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
Gdy jeden z podrzędnych elementów tego elementu ma fokus wewnętrzny:
- Tłonu
.fieldset-item
przypisano kolor powierzchni o wyższym kontraście. - Umieszczony wewnątrz element
svg
jest wypełniony na biało, aby zwiększyć kontrast. - Zagnieżdżony element
<picture>
clip-path
rozszerza się do pełnego koła, a tło wypełnia jasny gradient.
Zakres niestandardowy
Na przykładzie tego elementu wejściowego HTML pokażę, jak spersonalizować jego wygląd:
<input type="range">
Ten element składa się z 3 części, które musimy dostosować:
Style elementów zakresu
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
Pierwsze kilka wierszy kodu CSS to niestandardowe części stylów. Mamy nadzieję, że wyraźne oznaczenie tych elementów pomoże Ci w rozpoznaniu ich funkcji. Pozostałe style to głównie style resetowania, które stanowią spójną podstawę do tworzenia trudnych części komponentu.
Style ścieżki
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
Wystarczy „odsłonić” żywy kolor wypełnienia. W tym celu użyj twardego gradientu u góry. Gradient jest przezroczysty do określonego procentu wypełnienia, a po przekroczeniu tego poziomu używa koloru niewypełnionej powierzchni ścieżki. Za tą pustą powierzchnią znajduje się kolor o pełnej szerokości, który jest widoczny dzięki przezroczystości.
Styl wypełnienia ścieżki
Aby zachować styl wypełnienia, moja grafika wymaga JavaScriptu. Istnieją strategie tylko z użyciem CSS, ale wymagają one, aby element miniatury miał taką samą wysokość jak utwór, a nie udało mi się znaleźć harmonii w tych granicach.
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
Myślę, że to jest miła zmiana wizualna. Suwak działa świetnie bez JavaScriptu, parametr --track-fill
nie jest wymagany, ale jeśli go nie ma, suwak nie będzie mieć stylu wypełnienia. Jeśli kod JavaScript jest dostępny, wypełnij właściwość niestandardową, obserwując jednocześnie wszelkie zmiany wprowadzane przez użytkownika i zsynchronizuj właściwość niestandardową z wartością.
Tutaj znajdziesz świetny post na temat CSS-Tricks autorstwa Any Tudor, który prezentuje rozwiązanie tylko z użyciem CSS do wypełniania ścieżki. Ten range
element również był dla mnie bardzo inspirujący.
Style miniatur
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
Większość tych stylów służy do tworzenia ładnych kół.
Ponownie widzisz gradient tła, który scala dynamiczne kolory miniatur, ścieżek i powiązanych elementów SVG.
Aby ułatwić wyodrębnienie techniki box-shadow
używanej do podświetlenia po najechaniu kursorem, oddzieliłem style interakcji:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
Celem było stworzenie łatwego w obsłudze i animowanego wizualnego wyróżnienia, które pozwoli użytkownikom wyrazić opinię. Dzięki cieniowi mogę uniknąć uruchomienia układu. Aby to zrobić, utwórz cień, który nie jest rozmyty i pasuje do okrągłego kształtu miniatury. Następnie zmieniam i przechodzę do rozmiaru rozszerzonego obrazu po najechaniu kursorem.
Gdyby tylko efekt podświetlenia był tak łatwy w przypadku pól wyboru…
Selektory dla różnych przeglądarek
Aby zapewnić spójność między przeglądarkami, potrzebowałem tych selektorów -webkit-
i -moz-
:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
Pole wyboru
Na przykładzie tego elementu wejściowego HTML pokażę, jak spersonalizować jego wygląd:
<input type="checkbox">
Ten element składa się z 3 części, które musimy dostosować:
Element pole wyboru
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
Style transform-style
i position
przygotowują pseudoelement, który wprowadzimy później, aby nadać styl wyróżnieniu. Poza tym to głównie moje osobiste opinie. Chcę, aby kursor był wskaźnikiem, lubię odstępy w obrysie, domyślne pola wyboru są zbyt małe, a jeśli accent-color
jest obsługiwane, te pola powinny być w schemacie kolorów marki.
Etykiety pól wyboru
Etykiety pól wyboru są ważne z 2 przyczyn. Pierwszym jest reprezentowanie tego, do czego służy wartość pola wyboru, aby można było odpowiedzieć na pytanie „co włączyć lub wyłączyć?”. Drugi powód to UX. Użytkownicy internetu przyzwyczaili się do interakcji z polami wyboru za pomocą powiązanych etykiet.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
W etykiecie umieść atrybut for
, który wskazuje pole wyboru według identyfikatora: <label for="text-notifications">
. W polu wyboru wpisz nazwę i identyfikator, aby można było je znaleźć za pomocą różnych narzędzi i technologii, takich jak mysz czy czytnik ekranu:
<input type="checkbox" id="text-notifications" name="text-notifications">
.
:hover
, :active
i inne są dostępne bezpłatnie w ramach połączenia, co zwiększa możliwości interakcji z formularzem.
Wyróżnienie pola wyboru
Chcę zachować spójność interfejsów, a element suwaka ma ładne podświetlenie miniatury, którego chciałbym użyć w przypadku pola wyboru. Miniatura mogła używać właściwości box-shadow
i spread
, aby skalować cień w górę i w dół. Ten efekt nie działa jednak w tym przypadku, ponieważ nasze pola wyboru są i powinny być kwadratowe.
Udało mi się uzyskać ten sam efekt wizualny za pomocą pseudoelementu i niefortunnej ilości skomplikowanego kodu CSS:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
Utworzenie pseudoelementu koła jest proste, ale umieszczenie go za elementem, do którego jest dołączony, było trudniejsze. Oto stan przed i po naprawieniu:
To zdecydowanie mikrointerakcja, ale zależy mi na spójności wizualnej. Technika skalowania animacji jest taka sama jak w innych miejscach. Ustawiamy niestandardową właściwość na nową wartość i pozwalamy CSS na przejście do niej na podstawie preferencji ruchu. Najważniejsza funkcja to translateZ(-1px)
. Encja nadrzędna utworzyła przestrzeń 3D, a pseudoelement podrzędny się do niej podłączył, umieszczając się nieco z tyłu w osi Z.
Ułatwienia dostępu
Film w YouTube doskonale pokazuje, jak w ramach tego komponentu ustawień można korzystać z myszy, klawiatury i czytnika ekranu. Podam kilka szczegółów.
Wybór elementów HTML
<form>
<header>
<fieldset>
<picture>
<label>
<input>
Każdy z nich zawiera wskazówki dotyczące narzędzia do przeglądania użytkownika. Niektóre elementy wyświetlają wskazówki dotyczące interakcji, inne umożliwiają interakcję, a jeszcze inne pomagają tworzyć drzewo ułatwień dostępu, po którym porusza się czytnik ekranu.
Atrybuty HTML
Możemy ukryć elementy, których nie potrzebują czytniki ekranu. W tym przypadku jest to ikona obok suwaka:
<picture aria-hidden="true">
Film pokazuje działanie czytnika ekranu w systemie Mac OS. Zwróć uwagę, że punkt zaznaczenia przesuwa się bezpośrednio z jednego suwaka na następny. Dzieje się tak, ponieważ ukryliśmy ikonę, która mogła być przystankiem na drodze do następnego suwaka. Bez tego atrybutu użytkownik musiałby zatrzymać się, posłuchać i przejść obok obrazu, którego może nie widzieć.
Plik SVG zawiera wiele obliczeń, więc dodamy element <title>
, który będzie wyświetlany po najechaniu na niego kursorem. Dodamy też tytuł i komentarz dla użytkowników, aby wiedzieli, co tworzą obliczenia:
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
Oprócz tego użyliśmy wystarczającej ilości wyraźnie oznaczonego kodu HTML, dzięki czemu formularz działa bardzo dobrze z myszą, klawiaturą, kontrolerami do gier wideo i czytnikami ekranu.
JavaScript
Omówiliśmy już, jak kolor wypełnienia ścieżki był zarządzany za pomocą kodu JavaScript. Teraz przyjrzyjmy się powiązanemu kodowi JavaScript: <form>
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
Za każdym razem, gdy użytkownik wchodzi w interakcję z formularzem i go zmienia, konsola rejestruje go jako obiekt w tabeli, aby można było go łatwo sprawdzić przed przesłaniem na serwer.
Podsumowanie
Teraz, gdy już wiesz, jak to zrobić, jak Ty to zrobisz? To tworzy ciekawą architekturę komponentów. Kto przygotuje pierwszą wersję z miejscami na reklamy w ulubionej platformie? 🙂
Zróżnicujemy nasze podejścia i poznamy wszystkie sposoby tworzenia stron internetowych. Utwórz wersję demonstracyjną, wyślij mi linki, a ja dodam je do sekcji Remiksy społeczności.