Magiczne karty flip: rozwiązywanie typowego problemu z rozmiarem
Opublikowany: 2022-03-10Jakie są szanse, że Twój następny klient użyje słowa interaktywny podczas przedstawiania swojego projektu? Z mojego doświadczenia wynika, że odpowiedź brzmi 100% , więc zawsze szukam solidnych technik CSS, które pomogą mi dostarczyć różne funkcje i efekty, które pojawiają się podczas omawiania tego celu.
Trochę interaktywności, o którą ciągle jestem proszony, to odwracanie kart — bloki treści, które obracają się po najechaniu lub stuknięciu, aby odsłonić zawartość na ich odwrocie. To zgrabny efekt, który zachęca do zabawnego przeglądania i jest kolejnym sposobem na pokazanie większej ilości informacji bez opuszczania strony. Ale standardowa metoda ma problem, jeśli chodzi o uwzględnienie różnych długości zawartości kart.
W tym samouczku zbudujemy siatkę z odwracanymi kartami, która rozwiąże ten problem z niektórymi podstawami CSS — transforms, flex i grid. Musisz się z nimi zapoznać, a dobre zrozumienie technik pozycjonowania CSS pomoże. Omówimy:
- W jaki sposób odwracane karty są zwykle implementowane przy użyciu pozycjonowania bezwzględnego;
- Problem doboru rozmiaru, który wprowadza pozycjonowanie bezwzględne; oraz
- Ogólne rozwiązanie do automatycznego określania rozmiaru nałożonej zawartości.
Tworzenie podstawowej karty flip
Dzięki dobrej obsłudze nowoczesnych przeglądarek dla trójwymiarowych przekształceń, tworzenie podstawowej karty flip jest stosunkowo proste. Zwykłą metodą jest umieszczenie przedniej i tylnej strony karty w kontenerze nadrzędnym i bezwzględnie umieść tylną stronę tak, aby pasowała do rozmiaru przedniej strony. Dodaj transformację osi X do tylnej ściany, aby wyglądała na odwróconą, dodaj kolejną do samej karty po najechaniu kursorem i zaczynamy.
.cards { display: grid; } .card { perspective: 40rem; } .card-body { transform-style: preserve-3d; transition: var(--time) transform; .card:hover & { transform: rotateX(-180deg); } } .card-front, .card-back { backface-visibility: hidden; } .card-back { position: absolute; top: 0; right: 0; bottom: 0; left: 0; transform: rotateX(-180deg); }
Co mogłoby pójść źle?
Nasze standardowe rozwiązanie ma jednak duży problem: nie działa, gdy tylna ścianka potrzebuje więcej miejsca niż zapewnia przednia ścianka. Nadanie karcie dużego, stałego rozmiaru jest jednym z rozwiązań, ale takie podejście gwarantuje również niepowodzenie w pewnym momencie dla niektórych rozmiarów ekranu.
Kompozycje projektowe naturalnie zawierają ładnie wyglądające pola z idealnie dopasowanym tekstem. Ale kiedy zaczynasz programować, może być trudno uzyskać układ strony i karty, który będzie pasował do prawdziwej treści. A podczas wyświetlania dynamicznej treści z CMS może to być niemożliwe! Nawet przy ograniczeniach dotyczących słów lub znaków często nie ma rozwiązania, które działałoby niezawodnie na wszystkich urządzeniach.
Zawsze powinniśmy dążyć do tworzenia implementacji układu, które tolerują szeroki zakres długości treści. Ale to nie jest łatwe! Często miałem okazję wrócić do używania stałych rozmiarów i pozycji, czy to z powodu ograniczeń czasowych, niewystarczającej obsługi przeglądarek, słabego projektu referencyjnego, czy po prostu własnego braku doświadczenia.
Przez lata nauczyłem się, że dobry proces iteracyjny i zdrowy dialog z projektantem mogą bardzo pomóc w rozwiązywaniu tych problemów i często można spotkać się gdzieś pośrodku, aby uzyskać solidny układ z pewną interaktywnością. Ale wracając do aktualnego zadania — czy można to zrobić?
Myśleć poza szablonowo
W rzeczywistości możliwe jest dobranie rozmiaru kart w oparciu o zawartość zarówno przednią, jak i tylną, i nie jest to tak trudne, jak się wydaje na początku. Po prostu musimy być metodyczni i wytrwali!
Ograniczanie problemu
Zacznijmy od sporządzenia listy wymagań naszego layoutu. Próba zapisania dokładnie tego, czego chcesz, może wydawać się obowiązkiem, ale jest to świetny sposób na odkrycie ograniczeń, które można uprościć, aby rozwiązać problem. Powiedzmy:
- Chcemy zobaczyć jedną lub więcej prostokątnych kart ułożonych w siatkę jedno- lub wielokolumnową;
- Chcemy, aby karty odwróciły się po najechaniu kursorem lub dotknięciu, aby odsłonić drugi zestaw treści na tylnej stronie;
- Chcemy, aby karty zawsze były wystarczająco duże, aby pokazywać całą ich przednią i tylną zawartość, niezależnie od długości treści lub stylu; oraz
- W przypadku wielu kolumn najlepiej byłoby, gdyby wszystkie karty miały ten sam rozmiar, aby rzędy ładnie się pokrywały.
Zastanawiając się nad tymi wymaganiami, możemy zauważyć kilka rzeczy, które upraszczają problem:
- Jeśli karty mają być prezentowane w siatce, mamy ograniczenie dotyczące ich szerokości — to znaczy, że ich szerokości są funkcjami okna widoku lub kontenera siatki, a nie ich własną zawartością;
- Biorąc pod uwagę, że znamy szerokość karty (przynajmniej jako procent jej rodzica), rozwiązaliśmy wymiar poziomy i musimy tylko rozszerzyć wysokość karty, aby pasowała do wyższej z jej przedniej lub tylnej strony; oraz
- Jeśli możemy to zrobić, a każda karta ma własny rozmiar w pionie, możemy użyć
grid-auto-rows
CSS Grid, aby wszystkie rzędy kart były tak wysokie, jak najwyższa karta.
Obmyślanie sztuczki karcianej
Jak więc samodzielnie dopasowujemy rozmiar kart? Teraz uprościliśmy nasz problem, jesteśmy w zasięgu rozwiązania.
Zapomnij na chwilę o pomyśle umieszczania treści na wierzchu innych treści i skup się na naszym nowym wymaganiu: rodzic, który jest tak wysoki, jak jego najwyższe dziecko. To łatwe! Używając kolumn, możemy spowodować, że rodzic rozszerzy się do wysokości swojego najwyższego dziecka. Następnie wystarczy trochę sztuczki, aby wyrównać dzieci:
- Ustaw dzieci na taką samą szerokość jak ich rodzic
- Pozwól drugiemu dziecku przelać się w prawo
- Przekształć go w lewo z powrotem na właściwe miejsce
.cards { display: grid; } .card-body { display: flex; } .card-front, .card-back { min-width: 100%; mix-blend-mode: multiply; // Preview both faces } .card-back { transform: translate(-100%, 0); }
Jeśli to podejście wydaje się oczywiste, zapewniam, że spędziłem wiele godzin na przemyślaniu kilku naprawdę okropnych pomysłów, zanim o tym pomyślałem. Początkowo planowałem wydrukować ukrytą kopię tekstu awersu wewnątrz awersu, aby powiększyć kartę do właściwego rozmiaru. A kiedy pomyślałem o użyciu przepełnienia kolumny, pierwotnie przycinałem kolumnę po prawej stronie za pomocą overflow:hidden
i przekształcałem ją tylko w ostatnim momencie, gdy zaczął się najechanie kursorem, ponieważ jeszcze nie zdawałem sobie sprawy, że mogę po prostu go przekształcić od początku i użyj innej metody, takiej jak opacity
lub backface-visibility
aby włączyć lub wyłączyć ją w razie potrzeby.
Innymi słowy oczywiste rozwiązania są wynikiem ciężkiej pracy! Jeśli masz wrażenie, że godzinami walisz głową o biurko z powodu problemu z układem, ważne jest, aby cofnąć się o krok i zdecydować, czy mądrze spędzasz czas swojego klienta: czy zasugerować zmianę projektu i czy poszukiwanie rozwiązania we własnym czasie jako ćwiczenie uczenia się, gdy nie ma presji. Ale kiedy wymyślasz proste metody, nigdy nie czuj się głupio, ponieważ zajęło to dużo czasu . Przyjrzyjmy się teraz naszemu kompletnemu rozwiązaniu.
.cards { display: grid; } .card { perspective: 40rem; } .card-body { display: flex; transform-style: preserve-3d; transition: var(--time) transform; .card:hover & { transform: rotateX(-180deg); } } .card-front, .card-back { backface-visibility: hidden; min-width: 100%; } .card-back { transform: rotateX(-180deg) translate(-100%, 0); }
Czy są jakieś zastrzeżenia?
Rozwiązanie ogólnie działa dobrze, z kilkoma drobnymi zastrzeżeniami, o których należy pamiętać:
- Karty muszą być obecne w układzie siatki lub w innym kontekście, w którym ich szerokość nie jest zależna od treści.
- Karty wymagają pewnego rodzaju opakowania zawartości (naszego
card-body
), aby obszar najechania nie zmieniał się podczas animacji. Jeśli sama karta jest animowana, zobaczysz pewne zakłócenia, ponieważ animacja szybko się zatrzymuje i uruchamia ponownie. - Stylizacje, takie jak tła i cienie, najlepiej umieszczać bezpośrednio na przedniej i tylnej ściance, ponieważ żadne efekty na samej karcie nie będą animowane. Uważaj na stylizacje, takie jak box-shadows na ciele karty, ponieważ naturalnie zostaną odwrócone do góry nogami.
- Przednie i tylne awersy kart wymagają ustawienia
box-sizing
naborder-box
, jeśli mają własne dopełnienie, ze względu na wymaganiemin-width
, w przeciwnym razie zostaną przepełnione. - Safari nadal wymaga
-webkit-backface-visibility
, w formie z przedrostkiem dostawcy.
Dodanie trochę polskiego
Teraz rozwiązaliśmy trudny problem, przyjrzyjmy się kilku poprawkom, które możemy wprowadzić, aby cała interakcja działała tak płynnie, jak to tylko możliwe.
Najpierw sprawdź, czy karty zachodzą na siebie podczas odwracania. Będzie to zależeć od tego, czy używasz wielu kolumn, szerokości rynny kolumnowej, orientacji odwrócenia i wartości perspektywy karty, ale prawdopodobnie tak się stanie. Możesz wydłużyć czas trwania animacji, aby zobaczyć rzeczy wyraźniej. Po najechaniu kursorem wydaje się nienaturalne, że najechana karta odwraca się pod swoich późniejszych sąsiadów, więc musimy umieścić ją na górze, używając z-index
. Łatwo, ale uważaj! Musimy poczekać, aż animacja wychodząca zostanie ukończona, zanim przywrócimy z-index
. Wprowadź transition-delay
:
.card { transition: z-index; transition-delay: var(--time); z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } }
Następnie rozważ utworzenie stanu aktywnego dla kart. Zazwyczaj staram się tworzyć takie karty, aby prowadziły do odpowiednich miejsc — nawet jeśli nie zostały określone przez projektanta — ponieważ elementy z takimi efektami najechania jak ten są bardzo łatwe do dotknięcia, więc dobrze jest zapewnić miejsce docelowe dla czytelników, którzy próbują szczęścia. Podoba mi się krótka, subtelna transformacja skali, ponieważ działa ona całkiem dobrze niezależnie od tego, czy druga połowa animacji jest odcinana przez wczytanie strony docelowej (chciałbym, aby przeglądarki czysto uzupełniały animacje podczas lotu przed nawigacją, Jestem pewien, że byłoby to o wiele trudniejsze do wdrożenia w praktyce niż się wydaje).
To także świetna okazja, aby zastanowić się, jak przystępna jest zawartość rewersów naszych kart. Nasze znaczniki są zwięzłe i dobrze uporządkowane, więc omówiliśmy czytniki ekranu i inne przypadki użycia, które ignorują stylizację, ale co z użytkownikami klawiatury? Jeśli zamierzamy sprawić, by karty same się zakotwiczyły, będą one skoncentrowane jako zakładka użytkowników klawiatury na stronie. Użyjmy ponownie stanu najechania karty jako stanu skupienia, a tylna zawartość pojawi się naturalnie podczas przeglądania klawiatury.
.card { transition: z-index, transform calc(var(--time) / 4); transition-delay: var(--time), 0s; z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } &:active { transform: scale(0.975); } } .card-body { .card:hover &, .card:focus & { transform: rotateX(-180deg); } }
Wreszcie, nie zapominaj, że teraz karta automatycznie skaluje się, aby dopasować swoją zawartość, możesz użyć praktycznie dowolnych technik wyrównania i odstępów, które lubisz wewnątrz kontenera przedniego i tylnego. Użyj elastycznego wyrównania, aby wyśrodkować tytuły, dodaj dopełnienie, a nawet umieść kolejną siatkę wewnątrz karty. Na tym polega piękno dobrych rozwiązań układu, które skalują się wraz z zawartością — zmniejszone łączenie dzieci z rodzicami oraz modułowość, która pozwala skupić się na jednej rzeczy na raz.
.card-front, .card-back { display: flex; align-items: center; background-color: white; box-shadow: 0 5px 10px black; border-radius: 0.25rem; padding: 1.5rem; }
Zawijanie
Mam nadzieję, że ta technika CSS okaże się przydatna! Dlaczego nie wypróbować pewnych odmian animacji, takich jak efekt skali lub proste przejście? Technika ta nie ogranicza się również do formatu karty. Może być stosowany wszędzie tam, gdzie odpowiedzialność za wymiarowanie w pionie spada na więcej niż jeden element. Wyobraź sobie witrynę magazynu zawierającą duże zdjęcia z nałożonymi podpisami — możesz jej użyć, aby pomieścić zarówno obrazy o wysokich proporcjach, jak i długi dynamiczny tekst.
Przede wszystkim pamiętaj o korzyściach płynących z poświęcenia czasu na dokładne przemyślenie, czy istnieje sposób na zaimplementowanie projektu, który wygląda tak, jakby działał tylko przy stałym rozmiarze i pozycji. Często zdarza się, i bez względu na to, jak trudny może się wydawać problem na początku, spisanie wszystkich wymagań, poświęcenie trochę czasu na stworzenie minimalnego przypadku testowego i metodyczne przechodzenie przez niego jest zawsze najlepszym rozwiązaniem.