魔術翻轉卡:解決常見的尺寸問題

已發表: 2022-03-10
快速總結 ↬在本文中,Dan Halliday 回顧了創建動畫翻轉卡片的標準方法,並介紹了一種解決其尺寸問題的改進方法。

您的下一位客戶在介紹他們的項目時使用“互動”這個詞的機會有多大? 以我的經驗,答案是100% ,所以我一直在尋找強大的 CSS 技術來幫助我提供在討論這個目標時出現的各種特性和效果。

我一次又一次地被要求實現的一點交互性是翻轉卡片——內容塊在懸停或點擊時會翻轉以顯示其背面的內容。 這是一種鼓勵有趣瀏覽的簡潔效果,也是無需離開頁面即可顯示更多信息的另一種方式。 但標準方法在適應不同的卡片內容長度時存在問題。

在本教程中,我們將構建一個翻轉卡片網格,它使用一些 CSS 基礎知識來解決這個問題——transforms、flex 和 grid。 你需要熟悉這些,這將有助於很好地掌握 CSS 定位技術。 我們將涵蓋:

  • 翻轉卡片通常如何使用絕對定位來實現;
  • 絕對定位引入的尺寸問題; 和
  • 覆蓋內容自動調整大小的通用解決方案。
跳躍後更多! 繼續往下看↓

創建基本翻轉卡

由於現代瀏覽器對 3D 變換的良好支持,創建基本的翻轉卡片相對簡單。 通常的方法是將正面和背面卡片面放在一個父容器中,並將背面絕對定位,使其可以匹配正面的大小。 在背面添加一個 x 軸變換以使其看起來反轉,在懸停時向卡片本身添加另一個,我們就開始了。

 .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); } 

使用絕對定位的標準翻轉卡片實現(參見 Dan Halliday 的 Pen “[Magic Flip Cards 1: The Standard Implementation](https://codepen.io/smashingmag/pen/JjdPJvo)”)

使用絕對定位的標準翻轉卡片實現(參見 Dan Halliday 的 Pen “Magic Flip Cards 1: The Standard Implementation”)

會出什麼問題?

但是,我們的標準解決方案有一個大問題:當背面需要的空間比正面提供的空間大時,它就不起作用了。 給卡一個大的、固定的尺寸是一種解決方案,但這種方法也保證在某些時候對於某些屏幕尺寸集會失敗。

標準翻轉卡實施如何因較長的返回內容而失敗
這就是標準翻轉卡實施失敗的原因,後面的內容更長。 (大預覽)

設計組合自然具有外觀整潔的框和完美契合的文本。 但是在開始開發時,很難獲得適用於真實內容的頁面和卡片佈局。 當顯示來自 CMS 的動態內容時,這是不可能的! 即使有字數或字符數限制,通常也沒有能夠在所有設備上可靠運行的解決方案。

標準翻轉卡實現如何因較長的背面內容而失敗(參見 Dan Halliday 的 Pen “[Magic Flip Cards 2: How Absolute Positioning Fails](https://codepen.io/smashingmag/pen/QWbLMLz)”)

標準翻轉卡的實施如何因背面內容較長而失敗(請參閱 Dan Halliday 的 Pen “Magic Flip Cards 2: How Absolute Positioning Fails”)

我們應該始終努力創建能夠容忍各種內容長度的佈局實現。 但這並不容易! 我經常有機會回退到使用固定的大小和位置,無論是由於時間限制、瀏覽器支持不足、參考設計薄弱還是我自己的經驗不足。

多年來,我了解到,在解決這些問題時,良好的迭代過程和與設計師的健康對話會大有幫助,而且您通常可以在中間的某個地方會面,以獲得具有一定交互性的穩健佈局。 但回到手頭的任務——它可以完成嗎?

外箱思考

事實上,可以根據正面和背面的內容來調整卡片的大小,而且並不像最初看起來那麼難。 我們只需要有條不紊和堅持不懈!

約束問題

讓我們首先列出我們的佈局要求。 試圖準確地寫下你想要的東西可能看起來像是一件苦差事,但這是發現可以簡化以解決問題的約束的好方法。 比方說:

  • 我們希望看到一張或多張矩形卡片,排列成單列或多列網格;
  • 我們希望卡片在懸停或點擊時翻轉以在背面顯示第二組內容;
  • 我們希望卡片始終足夠大,以顯示其所有正面和背面內容,無論內容長度或樣式如何; 和
  • 在多列的情況下,理想情況下,我們希望所有卡片的大小相同,以便行對齊。

考慮到這些要求,我們可以注意到一些可以簡化問題的事情:

  • 如果卡片要在網格中呈現,我們對它們的寬度有一個限制——也就是說,它們的寬度是視口或網格容器的函數,而不是它們自己的內容;
  • 鑑於我們知道一張卡片的寬度(至少是其父卡片的百分比),我們已經解決了水平尺寸問題,我們只需要擴展卡片的高度以適合其正面或背面的較高者; 和
  • 如果我們可以做到這一點並且每張卡片都是垂直大小的,我們可以使用 CSS Grid 的grid-auto-rows使所有卡片行都與最高卡片一樣高。

弄清楚卡片技巧

那麼,我們如何自行調整卡片大小? 現在我們已經簡化了我們的問題,我們可以得到解決方案。

暫時忘記將內容放在其他內容之上的想法,並專注於我們的新要求:父母與其最高的孩子一樣高。 這很簡單! 使用列,我們可以使父級擴展到其最高子級的高度。 然後,我們只需要使用一點花招來讓孩子們對齊:

  1. 將子項設置為與其父項相同的寬度
  2. 讓第二個孩子向右溢出
  3. 將其向左轉換回其正確位置
.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); } 

通過固定水平溢出進行垂直調整(參見 Dan Halliday 的筆“[Magic Flip Cards 3: Vertical Sizing by Fixed Horizo​​ntal Overflow](https://codepen.io/smashingmag/pen/ExjYvjP)”)

通過固定水平溢出進行垂直調整(參見 Dan Halliday 的筆“Magic Flip Cards 3: Vertical Sizing by Fixed Horizo​​ntal Overflow”)

如果這種方法看起來很明顯,請放心,我花了很多時間研究了一些非常糟糕的想法,然後才想到它。 起初,我計劃在正面打印一個隱藏的重複版本的背面文本,以將卡片擴大到正確的尺寸。 當我確實想到使用列溢出時,我最初是使用overflow:hidden裁剪右側列,並僅在懸停開始的最後一刻對其進行轉換,因為我還沒有意識到我可以保持它的轉換從頭開始並使用另一種方​​法(例如opacitybackface-visibility )根據需要打開和關閉它。

換句話說,顯而易見的解決方案是努力工作的結果! 如果您覺得自己已經為一個佈局問題頭疼了好幾個小時,重要的是退後一步,決定您是否明智地花費了客戶的時間:是否建議他們改變設計,以及是否當壓力消失時,在自己的時間裡尋求解決方案作為學習練習。 但是當你想出簡單的方法時,永遠不要因為花了很長時間而感到愚蠢。 現在,讓我們回顧一下我們的完整解決方案。

 .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); } 

完整的魔法翻轉卡片解決方案(參見 Dan Halliday 的 Pen “[Magic Flip Cards 4: The Complete Solution](https://codepen.io/smashingmag/pen/xxGKLZO)”)

完整的魔法翻轉卡片解決方案(參見 Dan Halliday 的 Pen “Magic Flip Cards 4: The Complete Solution”)

有什麼注意事項嗎?

該解決方案通常運行良好,只需記住一些小警告:

  • 卡片必須出現在網格佈局或其他寬度不依賴於內容的上下文中。
  • 卡片需要某種內容包裝器(我們的card-body ),以便懸停區域在動畫期間不會改變。 如果卡片本身是動畫的,您會看到一些小故障,因為動畫會快速停止並重新啟動。
  • 背景和盒子陰影等樣式最好直接放在正面和背面,因為卡片本身的任何效果都不會被動畫化。 注意卡體上的樣式,例如盒子陰影,因為它們自然會被顛倒過來。
  • 卡片的正面和背面需要它們的box-sizing屬性設置為border-box ,如果它們有自己的填充,由於它們的min-width要求,否則它們會溢出。
  • Safari 仍然需要-webkit-backface-visibility ,以供應商前綴的形式。

添加一些波蘭語

現在我們已經解決了難題,讓我們看看我們可以進行的一些調整,以使整個交互盡可能順利地工作。

首先,檢查翻轉時卡片是否重疊。 這將取決於您是否使用多列、列間距的寬度、翻轉的方向以及卡片的透視值,但這很可能會發生。 您可以增加動畫的持續時間以更清楚地看到事物。 懸停時,懸停的卡片在其後面的鄰居下方翻轉看起來不自然,因此我們需要使用z-index將其放在頂部。 很簡單,但要小心! 在恢復z-index之前,我們需要等到傳出動畫完成。 輸入transition-delay

 .card { transition: z-index; transition-delay: var(--time); z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } }

接下來,考慮為卡片創建一個活動狀態。 我通常會嘗試將這樣的卡片鏈接到相關的地方——即使設計師沒有指定——因為像這樣具有懸停效果的元素感覺非常容易點擊,所以為嘗試運氣的讀者提供一個目的地是很好的。 我喜歡一個簡短而微妙的比例變換,因為無論動畫的後半部分是否被目標頁面的加載切斷,它都能很好地工作(我希望瀏覽器在導航之前乾淨地完成飛行中的動畫,不過我敢肯定,在實踐中實施起來比聽起來要困難得多)。

這也是一個很好的機會來思考我們卡片背面內容的可訪問性。 我們的標記簡潔且有序,因此我們涵蓋了屏幕閱讀器和其他忽略樣式的用例,但是鍵盤用戶呢? 如果我們要讓卡片自己錨定,它們將在鍵盤用戶通過頁面標籤時獲得焦點。 讓我們重用卡片的懸停狀態作為焦點狀態,在鍵盤瀏覽過程中,後面的內容自然會出現。

 .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); } }

最後,不要忘記現在卡片會自動縮放以適應其內容,您可以在前後容器內使用幾乎任何您喜歡的對齊和間距技術。 使用 flex 對齊來居中標題,添加填充,甚至在卡片內放置另一個網格。 這就是隨內容擴展的良好佈局解決方案的美妙之處——減少了孩子與父母的耦合,以及允許您一次專注於一件事的模塊化。

 .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; }

包起來

我希望你發現這個 CSS 技術很有用! 為什麼不嘗試一些動畫變化,例如縮放效果或簡單的交叉淡入淡出? 該技術也不限於卡的外形尺寸。 它可以在垂直尺寸的責任落在一個以上元素的任何地方使用。 想像一個雜誌網站,其中包含帶有重疊標題的大照片——您可以使用它來容納具有高縱橫比的圖像和長動態文本。

最重要的是,請記住花一些時間認真思考是否有一種方法可以實現看起來好像只能在固定尺寸和位置下工作的設計的好處。 通常,無論問題一開始看起來多麼棘手,寫下您的所有需求,留出一些時間來創建一個最小的測試用例,並有條不紊地逐步完成它始終是最好的選擇。