.
W jaki sposób możesz obecnie powiązać jeden element z drugim? Możesz spróbować śledzić ich pozycję lub użyć jakiejś formy elementu kodu.
<!-- index.html -->
<div class="container">
<a href="/link" class="anchor">I’m the anchor</a>
<div class="anchored">I’m the anchored thing</div>
</div>
/* styles.css */
.container {
position: relative;
}
.anchored {
position: absolute;
}
Takie rozwiązania często nie są idealne. Potrzebuje JavaScriptu lub wprowadzenia dodatkowych znaczników. Interfejs API pozycjonowania kotwicy CSS ma na celu rozwiązanie tego problemu poprzez udostępnienie interfejsu CSS API do tetheringu elementów. Umożliwia określenie pozycji i rozmiaru jednego elementu na podstawie położenia i rozmiaru pozostałych elementów.
Obsługa przeglądarek
Możesz wypróbować interfejs CSS pozycjonowania zakotwiczonego interfejsu API w Chrome Canary, korzystając z funkcji „Eksperymentalne funkcje platformy internetowej”. flaga. Aby włączyć tę flagę, otwórz Chrome Canary i wejdź na chrome://flags
. Następnie włącz „Eksperymentalne funkcje platformy internetowej”. flaga.
Zespół Oddbird opracował też kod polyfill. Sprawdź repozytorium na stronie github.com/oddbird/css-anchor-positioning.
Wsparcie do zakotwiczenia możesz sprawdzić w:
@supports(anchor-name: --foo) {
/* Styles... */
}
Pamiętaj, że ten interfejs API jest nadal w fazie eksperymentalnej i może się zmienić. W tym artykule ogólnie omawiamy najważniejsze kwestie. Obecna implementacja nie jest też całkowicie zgodna ze specyfikacją grupy roboczej ds. usług porównywania cen.
Problem
Dlaczego warto to robić? Znanym przypadkiem użycia jest tworzenie etykietek. W takim przypadku warto powiązać etykietkę z treścią, do której się ona odnosi. Często istnieje konieczność zastosowania jakiegoś sposobu na powiązanie elementu z innym. Oczekujesz też, że interakcja ze stroną nie spowoduje przerwania tetheringu – na przykład jeśli użytkownik przewinie stronę lub zmieni rozmiar interfejsu.
Innym problemem jest konieczność zapewnienia, że powiązany element pozostanie widoczny – na przykład jeśli otworzysz etykietkę i zostanie ona przycięta przez granice widocznego obszaru. Może to nie być przyjemne dla użytkowników. Chcesz dostosować etykietkę.
Bieżące rozwiązania
Obecnie można podejść do tego problemu na kilka różnych sposobów.
Pierwsze to podstawowe określenie „Opakuj kotwicę”. jak ważna jest pokora. Wystarczy, że zapakujesz oba elementy do kontenera. Następnie za pomocą polecenia position
możesz określić położenie etykietki względem kotwicy.
<div class="containing-block">
<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
</div>
.containing-block {
position: relative;
}
.tooltip {
position: absolute;
bottom: calc(100% + 10px);
left: 50%;
transform: translateX(-50%);
}
Możesz przenieść kontener, a wszystko pozostanie tam, gdzie chcesz.
Możesz też znać położenie reklamy zakotwiczonej lub w jakiś sposób ją śledzić. Możesz go przekazać do etykietki z właściwościami niestandardowymi.
<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
:root {
--anchor-width: 120px;
--anchor-top: 40vh;
--anchor-left: 20vmin;
}
.anchor {
position: absolute;
top: var(--anchor-top);
left: var(--anchor-left);
width: var(--anchor-width);
}
.tooltip {
position: absolute;
top: calc(var(--anchor-top));
left: calc((var(--anchor-width) * 0.5) + var(--anchor-left));
transform: translate(-50%, calc(-100% - 10px));
}
A co w sytuacji, gdy nie znasz położenia reklamy zakotwiczonej? Prawdopodobnie musisz interweniować w JavaScript. Możesz zrobić coś takiego jak ten podany poniżej, ale teraz oznacza to, że style zaczynają wypływać z CSS w JavaScript.
const setAnchorPosition = (anchored, anchor) => {
const bounds = anchor.getBoundingClientRect().toJSON();
for (const [key, value] of Object.entries(bounds)) {
anchored.style.setProperty(`--${key}`, value);
}
};
const update = () => {
setAnchorPosition(
document.querySelector('.tooltip'),
document.querySelector('.anchor')
);
};
window.addEventListener('resize', update);
document.addEventListener('DOMContentLoaded', update);
Zaczynają się pojawiać pytania:
- Kiedy obliczam style?
- Jak obliczyć style?
- Jak często obliczam style?
Czy to rozwiąże problem? Może tak być w Twoim przypadku, ale jest jeden problem: nasze rozwiązanie się nie dostosowuje. Nie reaguje. Co się stanie, jeśli zakotwiczony element zostanie przycięty w widocznym obszarze?
Musisz teraz zdecydować, czy zareagować na to i jak. Liczba pytań i decyzji, które musisz podejmować, zaczyna rosnąć. Musisz tylko zakotwiczyć jeden element do drugiego. W idealnym świecie rozwiązanie dostosowuje się i reaguje do otoczenia.
Aby ułatwić sobie zadanie, możesz sięgnąć po odpowiednie rozwiązanie JavaScript. Wiąże się to z kosztem dodania zależności do projektu i może spowodować problemy z wydajnością w zależności od tego, jak z nich korzystasz. Na przykład niektóre pakiety używają parametru requestAnimationFrame
do utrzymywania prawidłowej pozycji. Oznacza to, że Ty i Twój zespół musicie zapoznać się z pakietem i jego opcjami konfiguracji. W efekcie liczba pytań i decyzji może nie zostać ograniczona. Jest to częścią mechanizmu do pozycjonowania kotwicy CSS. Dzięki temu nie musisz już brać pod uwagę kwestii skuteczności przy obliczaniu pozycji.
Oto jak może wyglądać kod z użyciem obiektu „float-ui”, który jest popularnym pakietem w przypadku tego problemu:
import {computePosition, flip, offset, autoUpdate} from 'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.2.1/+esm';
const anchor = document.querySelector('.anchor')
const tooltip = document.querySelector('.tooltip')
const updatePosition = () => {
computePosition(anchor, tooltip, {
placement: 'top',
middleware: [offset(10), flip()]
})
.then(({x, y}) => {
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`
})
})
};
const clean = autoUpdate(anchor, tooltip, updatePosition);
Spróbuj zmienić położenie reklamy zakotwiczonej, która korzysta z tego kodu.
„Etykieta” może nie działać zgodnie z oczekiwaniami. Reaguje na wyjście poza widoczny obszar na osi Y, ale nie poza osią X. Zapoznaj się z dokumentacją, a prawdopodobnie znajdziesz tam rozwiązanie, które sprawdzi się w Twoim przypadku.
Jednak znalezienie pakietu, który sprawdzi się w Twoim projekcie, może zająć dużo czasu. To dodatkowe decyzje, które mogą być frustrujące, jeśli nie wszystko działa, jak chcesz.
Korzystanie z pozycjonowania zakotwiczonych
Wpisz interfejs API do pozycjonowania kotwicy CSS. Chodzi o zachowanie stylów w arkuszu CSS i zmniejszenie liczby decyzji, które musisz podjąć. Chcesz osiągnąć taki sam efekt, ale naszym celem jest poprawa komfortu korzystania z aplikacji przez programistów.
- JavaScript nie jest wymagany.
- Pozwól przeglądarce wybrać najlepsze miejsce na podstawie Twoich wskazówek.
- Koniec z zależnościami zewnętrznymi
- Brak elementów otoki.
- Działa z elementami, które znajdują się w górnej warstwie.
Odtwórzmy i rozwiążmy problem, który próbowaliśmy rozwiązać powyżej. Zamiast tego posłużmy się analogią do łodzi z kotwicą. Reprezentują one element zakotwiczony i reklamę zakotwiczoną. Woda reprezentuje ten blok.
Najpierw musisz wybrać sposób zdefiniowania reklamy zakotwiczonej. Możesz to zrobić w kodzie CSS, ustawiając właściwość anchor-name
na elemencie zakotwiczonym. Może mieć wartość kreska-ident.
.anchor {
anchor-name: --my-anchor;
}
Kotwica będzie można również zdefiniować w kodzie HTML za pomocą atrybutu anchor
. Wartość atrybutu to identyfikator elementu zakotwiczonego. Spowoduje to utworzenie niejawnej kotwicy.
<a id="my-anchor" class="anchor"></a>
<div anchor="my-anchor" class="boat">I’m a boat!</div>
Po zdefiniowaniu reklamy zakotwiczonej możesz użyć funkcji anchor
. Funkcja anchor
przyjmuje 3 argumenty:
- Element zakotwiczony:
anchor-name
kotwicy, która ma zostać użyta. Możesz też pominąć wartość, aby użyć kotwicyimplicit
. Można ją zdefiniować za pomocą relacji HTML lub za pomocą właściwościanchor-default
z wartościąanchor-name
. - Strona zakotwiczona: słowo kluczowe odpowiadające pozycji, której chcesz użyć. Może to być
top
,right
,bottom
,left
,center
itp. Możesz też przekazać wartość procentową. Na przykład 50% będzie równacenter
. - Kreacja zastępcza: jest to opcjonalna wartość zastępcza, która może zawierać długość lub wartość procentową.
Funkcji anchor
możesz używać jako wartości właściwości wstawienia (top
, right
, bottom
, left
lub ich logicznych odpowiedników) elementu zakotwiczonego. Funkcji anchor
możesz też używać w calc
:
.boat {
bottom: anchor(--my-anchor top);
left: calc(anchor(--my-anchor center) - (var(--boat-size) * 0.5));
}
/* alternative with anchor-default */
.boat {
anchor-default: --my-anchor;
bottom: anchor(top);
left: calc(anchor(center) - (var(--boat-size) * 0.5));
}
Nie ma właściwości wstawienia center
, więc możesz użyć calc
, jeśli znasz rozmiar zakotwiczonego elementu. Dlaczego nie chcesz używać translate
? Możesz użyć tego:
.boat {
anchor-default: --my-anchor;
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
}
Przeglądarka nie uwzględnia jednak przekształconych pozycji w przypadku elementów zakotwiczonych. Stanie się jasne, dlaczego jest to tak ważne przy analizowaniu wartości zastępczych pozycji i automatycznego pozycjonowania.
Jak już pewnie wiesz, została zastosowana powyżej właściwość niestandardowa --boat-size
. Jeśli jednak chcesz określić rozmiar zakotwiczonego elementu na podstawie reklamy zakotwiczonej, możesz też uzyskać dostęp do tego rozmiaru. Zamiast obliczać go samodzielnie, możesz użyć funkcji anchor-size
. Na przykład aby łódź była 4-krotnie większa niż szerokość kotwicy:
.boat {
width: calc(4 * anchor-size(--my-anchor width));
}
Dzięki anchor-size(--my-anchor height)
masz również dostęp do wysokości. Za jego pomocą możesz ustawić rozmiar jednej lub obu osi.
Co zrobić, jeśli chcesz zakotwiczyć element z pozycją absolute
? Obowiązuje zasada, że elementy nie mogą być równorzędne. W takim przypadku możesz opakować reklamę zakotwiczoną kontenerem z pozycjonowaniem relative
. Potem możesz go zakotwiczyć.
<div class="anchor-wrapper">
<a id="my-anchor" class="anchor"></a>
</div>
<div class="boat">I’m a boat!</div>
Obejrzyj prezentację, w której możesz przeciągnąć kotwicę, a łódź pójdzie sama.
Śledzenie pozycji przewijania
W niektórych przypadkach element zakotwiczony może znajdować się w przewijanym kontenerze. Zakotwiczony element może też znajdować się poza tym kontenerem. Przewijanie odbywa się w innym wątku niż układ, więc musisz mieć sposób na jego śledzenie. Umożliwia to właściwość anchor-scroll
. Ustawiasz go na zakotwiczonym elemencie i nadajesz mu wartość kotwicy, którą chcesz śledzić.
.boat { anchor-scroll: --my-anchor; }
Wypróbuj tę wersję demonstracyjną, w której możesz włączyć i wyłączyć usługę anchor-scroll
za pomocą pola wyboru w rogu.
Ta analogia jest jednak trochę płaska, tak jak w idealnym świecie łódź i kotwica są na wodzie. Funkcje takie jak interfejs Popover API promują możliwość umieszczania powiązanych elementów w pobliżu. Pozycjonowanie zakotwiczone działa jednak w przypadku elementów, które znajdują się w górnej warstwie. To jedna z głównych zalet interfejsu API, czyli możliwość powiązania elementów w różnych przepływach.
Rozważ tę wersję demonstracyjną, która ma przewijany kontener z kotwicami i podpowiedziami. Elementy etykietki, które są wyskakującymi okienkami, mogą nie być umieszczone w tym samym miejscu co kotwice:
Zauważysz jednak, że wyskakujące okienka śledzą odpowiadające im linki zakotwiczone. Możesz zmienić rozmiar przewijanego kontenera, a pozycje zostaną zaktualizowane.
Pozycjonowanie kreacji zastępczej i automatycznego pozycjonowania
Dzięki temu skuteczność reklam zakotwiczonych wznosi się na wyższy poziom. Element position-fallback
może określić położenie zakotwiczonego elementu na podstawie podanego przez Ciebie zestawu kreacji zastępczych. Ty zarządzasz przeglądarką za pomocą stylów i pozwól, aby to ona ustaliła pozycję za Ciebie.
Typowym przypadkiem użycia jest etykietka, która powinna przełączyć się między wyświetlaniem się nad lub pod kotwicą. Działanie to zależy od tego, czy etykietka zostanie przycięta przez swój kontener. To zazwyczaj widoczny obszar.
Jeśli chcesz przyjrzeć się kodowi z poprzedniej wersji demonstracyjnej, zauważyłeśby, że używana jest właściwość position-fallback
. Po przewinięciu strony kontenera można zauważyć, że zakotwiczone wyskakujące okienka przeskoczyły. Dzieje się tak, gdy reklamy zakotwiczone zbliżyły się do granicy widocznego obszaru. W tym momencie wyskakujące okienka próbują dostosować się i pozostać w widocznym obszarze.
Zanim utworzysz jawną właściwość position-fallback
, możesz też korzystać z automatycznego pozycjonowania przez pozycjonowanie zakotwiczone. Możesz to zrobić bezpłatnie, używając wartości auto
zarówno w funkcji kotwicy, jak i odwrotnej właściwości wstawienia. Jeśli np. używasz atrybutu anchor
w przypadku elementu bottom
, ustaw wartość top
na auto
.
.tooltip {
position: absolute;
bottom: anchor(--my-anchor auto);
top: auto;
}
Alternatywą dla automatycznego pozycjonowania jest użycie wyraźnego atrybutu position-fallback
. Wymaga to zdefiniowania zestawu kreacji zastępczych. Przeglądarka będzie je przeglądać, aż znajdzie element, którego może użyć, a następnie zastosuje pozycjonowanie. Jeśli nie będzie można znaleźć działającej wersji, domyślnie zostanie zdefiniowany pierwszy tag.
Element position-fallback
, który próbuje wyświetlić etykietki powyżej, a potem poniżej, może wyglądać tak:
@position-fallback --top-to-bottom {
@try {
bottom: anchor(top);
left: anchor(center);
}
@try {
top: anchor(bottom);
left: anchor(center);
}
}
Wygląda to tak:
.tooltip {
anchor-default: --my-anchor;
position-fallback: --top-to-bottom;
}
anchor-default
umożliwia ponowne używanie elementu position-fallback
w przypadku innych elementów. Aby ustawić anchor-default
, możesz też użyć właściwości niestandardowej o zakresie ograniczonym.
Przyjrzyjmy się tej prezentacji jeszcze raz, używając łodzi. Istnieje zestaw: position-fallback
. Gdy zmienisz położenie kotwicy, łódź dostosuje się, aby pozostać w kontenerze. Spróbuj też zmienić wartość dopełnienia, by dostosować dopełnienie treści. Zwróć uwagę, jak przeglądarka poprawia pozycję. Pozycje można zmieniać, zmieniając wyrównanie siatki kontenera.
Tym razem position-fallback
działa bardziej szczegółowo, próbując ustawić położenie w kierunku zgodnym z ruchem wskazówek zegara.
.boat {
anchor-default: --my-anchor;
position-fallback: --compass;
}
@position-fallback --compass {
@try {
bottom: anchor(top);
right: anchor(left);
}
@try {
bottom: anchor(top);
left: anchor(right);
}
@try {
top: anchor(bottom);
right: anchor(left);
}
@try {
top: anchor(bottom);
left: anchor(right);
}
}
Przykłady
Omówiliśmy już główne funkcje pozycjonowania reklam zakotwiczonych. Teraz spójrzmy na kilka ciekawych przykładów, które nie są tylko podpowiedziami. Dzięki tym przykładom dowiesz się, jak możesz wykorzystać pozycjonowanie zakotwiczone. Najlepszym sposobem na poszerzenie specyfikacji jest wykorzystanie informacji od prawdziwych użytkowników takich jak Ty.
Menu kontekstowe
Zacznijmy od menu kontekstowego za pomocą interfejsu Popover API. Kliknięcie przycisku z szewronem powoduje wyświetlenie menu kontekstowego. Ma ono własne menu, które można rozwinąć.
Znaczniki nie są tu istotne. Ale masz 3 przyciski, z których każdy korzysta z usługi popovertarget
. Dalej masz 3 elementy, które korzystają z atrybutu popover
. Dzięki temu możesz otwierać menu kontekstowe bez użycia kodu JavaScript. Może to wyglądać tak:
<button popovertarget="context">
Toggle Menu
</button>
<div popover="auto" id="context">
<ul>
<li><button>Save to your Liked Songs</button></li>
<li>
<button popovertarget="playlist">
Add to Playlist
</button>
</li>
<li>
<button popovertarget="share">
Share
</button>
</li>
</ul>
</div>
<div popover="auto" id="share">...</div>
<div popover="auto" id="playlist">...</div>
Teraz możesz zdefiniować element position-fallback
i udostępnić go między menu kontekstowych. Pamiętaj też, aby wyłączyć style inset
dla wyskakujących okienek.
[popovertarget="share"] {
anchor-name: --share;
}
[popovertarget="playlist"] {
anchor-name: --playlist;
}
[popovertarget="context"] {
anchor-name: --context;
}
#share {
anchor-default: --share;
position-fallback: --aligned;
}
#playlist {
anchor-default: --playlist;
position-fallback: --aligned;
}
#context {
anchor-default: --context;
position-fallback: --flip;
}
@position-fallback --aligned {
@try {
top: anchor(top);
left: anchor(right);
}
@try {
top: anchor(bottom);
left: anchor(right);
}
@try {
top: anchor(top);
right: anchor(left);
}
@try {
bottom: anchor(bottom);
left: anchor(right);
}
@try {
right: anchor(left);
bottom: anchor(bottom);
}
}
@position-fallback --flip {
@try {
bottom: anchor(top);
left: anchor(left);
}
@try {
right: anchor(right);
bottom: anchor(top);
}
@try {
top: anchor(bottom);
left: anchor(left);
}
@try {
top: anchor(bottom);
right: anchor(right);
}
}
Zapewnia to interfejs adaptacyjnego zagnieżdżonego menu kontekstowego. Spróbuj zmienić pozycję treści za pomocą zaznaczenia. Wybrana opcja zmienia wyrównanie siatki. Wpływa to na sposób pozycjonowania wyskakujących okienek przez pozycjonowanie zakotwiczonych.
Skup się i obserwuj
Ta wersja demonstracyjna łączy podstawowe elementy CSS przez wywołanie funkcji :has(). Chodzi o przeniesienie wskaźnika wizualnego do elementu input
, na którym jest skupienie.
Aby to zrobić, ustaw nową kotwicę w czasie działania aplikacji. W tej wersji demonstracyjnej właściwość niestandardowa o zakresie jest aktualizowana na podstawie danych wejściowych.
#email {
anchor-name: --email;
}
#name {
anchor-name: --name;
}
#password {
anchor-name: --password;
}
:root:has(#email:focus) {
--active-anchor: --email;
}
:root:has(#name:focus) {
--active-anchor: --name;
}
:root:has(#password:focus) {
--active-anchor: --password;
}
:root {
--active-anchor: --name;
--active-left: anchor(var(--active-anchor) right);
--active-top: calc(
anchor(var(--active-anchor) top) +
(
(
anchor(var(--active-anchor) bottom) -
anchor(var(--active-anchor) top)
) * 0.5
)
);
}
.form-indicator {
left: var(--active-left);
top: var(--active-top);
transition: all 0.2s;
}
Ale jak możesz pójść o krok dalej? Możesz go użyć jako nakładki instruktażowej. Etykietka może przesuwać się między ciekawymi miejscami i aktualizować jej zawartość. Treść może się rozmyć. W tym przypadku mogą się tu sprawdzić pojedyncze animacje pozwalające animować display
lub wyświetlić przejścia.
Obliczenia na wykresie słupkowym
Pozycjonowanie zakotwiczone umożliwia też połączenie go z parametrem calc
. Wyobraź sobie wykres z kilkoma wyskakującymi okienkami dotyczącymi adnotacji.
Możesz śledzić najwyższe i najniższe wartości za pomocą CSS min
i max
. Kod CSS tego elementu może wyglądać mniej więcej tak:
.chart__tooltip--max {
left: anchor(--chart right);
bottom: max(
anchor(--anchor-1 top),
anchor(--anchor-2 top),
anchor(--anchor-3 top)
);
translate: 0 50%;
}
Wykonujemy JavaScript, by aktualizować wartości wykresu, oraz CSS, by określić styl wykresu. Jednak pozycjonowanie zakotwiczone zajmuje się aktualizacjami układu.
Zmień rozmiar uchwytów
Nie musisz zakotwiczyć tylko jednego elementu. Dla elementu można użyć wielu kotwic. Mogło to być dobrze widoczne na przykładzie wykresu słupkowego. Etykietki były zakotwiczone do wykresu, a do niego odpowiedniego słupka. Jeśli rozwiniesz ten pomysł, możesz użyć go do zmiany rozmiaru elementów.
Możesz traktować punkty zakotwiczenia jak niestandardowe uchwyty zmiany rozmiaru i korzystać z wartości inset
.
.container {
position: absolute;
inset:
anchor(--handle-1 top)
anchor(--handle-2 right)
anchor(--handle-2 bottom)
anchor(--handle-1 left);
}
W tej demonstracji funkcja GreenSock Draggable sprawia, że uchwyty można przeciągać. Jednak rozmiar elementu <img>
zmienia się, aby wypełnić kontener i dostosowywać się tak, aby wypełnić lukę między uchwytami.
Menu Select?
Ostatni odcinek to zwiastun tego, co czeka nas w przyszłości. Można jednak utworzyć wyskakujące okienko z możliwością zaznaczenia i ustawić pozycjonowanie zakotwiczone. Możesz utworzyć podstawy elementu <select>
z możliwością określenia stylu.
<div class="select-menu">
<button popovertarget="listbox">
Select option
<svg>...</svg>
</button>
<div popover="auto" id="listbox">
<option>A</option>
<option>Styled</option>
<option>Select</option>
</div>
</div>
Uproszczone użycie funkcji anchor
to ułatwi. Kod CSS dla podstawowego punktu początkowego może jednak wyglądać tak:
[popovertarget] {
anchor-name: --select-button;
}
[popover] {
anchor-default: --select-button;
top: anchor(bottom);
width: anchor-size(width);
left: anchor(left);
}
Gdy już to zrobisz, połącz funkcje interfejsu Popover API z pozycjonowaniem za pomocą zakotwiczenia CSS.
Miło jest zacząć prezentować takie rzeczy jak :has()
. Możesz obrócić znacznik przy otwarciu:
.select-menu:has(:open) svg {
rotate: 180deg;
}
Gdzie jeszcze sięgniesz? Co jeszcze potrzebujemy, aby z aplikacją select
można było korzystać? Zapiszemy tę informację w następnym artykule. Bez obaw – wkrótce pojawią się elementy do wyboru z możliwością wyboru. Więcej informacji już wkrótce.
To wszystko.
Platforma internetowa stale się rozwija. Pozycjonowanie zakotwiczonych CSS to kluczowy element ulepszania sposobu opracowywania elementów sterujących interfejsu. Takie podejście pozwoli Ci uwolnić Cię od tych trudnych decyzji. Pozwoli Ci to jednak robić rzeczy, które wcześniej były dla Ciebie zupełnie nowe. Na przykład wybierz styl elementu <select>
. Powiedz nam, co o nim sądzisz.
Zdjęcie: CHUTTERSNAP na stronie Unsplash