構建一個交互式的3D旋轉輪播圖,使用CSS 3D轉換和JavaScript增強網頁圖像或內容的動態展示效果。本文將逐步指導您如何創建這個組件。
我最初研究這個主題時,並不需要一個3D輪播圖,而更關注其具體的實現細節。核心技術當然是來自CSS Transforms Module Level 1,但在此過程中,將應用許多其他前端開發技術,涉及CSS、Sass和客戶端JavaScript的各個方面。
這個CodePen展示了不同版本的組件,我將向您展示如何構建它們。
為了說明CSS 3D轉換的設置,我將向您展示組件的純CSS版本。然後,我將向您展示如何使用JavaScript增強它,開發一個簡單的組件腳本。
關鍵要點
輪播圖的標記
對於標記,組件內的圖像被包裝在一個<figure></figure>
元素中,它提供了一個基本的框架:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
這將是我們的起點。
輪播圖的幾何結構
在查看CSS之前,讓我們概述一下將在以下部分開發的計劃。
<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173967151412585.jpg" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /></p>
<p>因此,這種多邊形的邊數與輪播圖中的圖像數量相同:三個圖像的多邊形是等邊三角形;四個圖像是正方形;五個是五邊形;等等:</p>
<p>如果輪播圖中的圖像少於三個怎麼辦?多邊形無法定義,以下過程無法按原樣應用。無論如何,只有一個圖像的情況相當沒用;兩個圖像稍微更可能,它們可以放置在圓圈上兩個直徑相對的點上。為簡單起見,這些特殊情況未處理,並假定至少有三個圖像。但是,相關的代碼修改並不難。 </p><p>這個虛構的參考多邊形將位於3D空間中,垂直於視口的平面,並且其中心向屏幕後推,距離等於其旁心距(多邊形的一條邊到其中心的距離),如下圖所示:</p>
<p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173967151540038.jpg" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /></p>
<p>這樣,當前面向觀看者的邊將位於屏幕平面z = 0處,而前部圖像不受透視縮短的影響,將具有其普通的2D大小。圖片中的d字母代表CSS perspective屬性的值。 </p>
<p><strong>構建輪播圖幾何結構</strong></p>
<p>在本節中,我將向您展示關鍵的CSS規則,我將逐步講解。 </p>
<p>在以下代碼片段中,使用一些Sass變量來使組件更易於配置。我將使用<code>$n
表示輪播圖中的圖像數量,使用$item-width
指定圖像的寬度。
<figure>
元素是第一個圖像的包含框,也是其他圖像圍繞其定位和轉換的參考元素。假設現在輪播圖只有一個圖像要展示,我可以從大小和對齊開始:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
<figure>
元素具有規定的輪播項目寬度,並且具有與圖像相同的高度(它們可以具有不同的尺寸,但必須具有相同的縱橫比)。這樣,輪播容器高度會根據圖像高度自動調整。此外,<figure>
在輪播容器中水平居中。
第一個圖像不需要額外的轉換,因為它已經在其目標位置,即輪播圖的正面。
可以通過對<figure>
元素應用旋轉變換來在3D空間中旋轉輪播圖。此旋轉必須圍繞多邊形的中心進行,因此我將更改<figure>
的默認transform-origin:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
此值取反,因為在CSS中,z軸的正方向是離開屏幕,朝向觀看者。需要括號以避免Sass語法錯誤。多邊形旁心距的計算將在後面解釋。
轉換了<figure>
元素的參考系統後,整個輪播圖可以通過其(新的)y軸旋轉來旋轉:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
我稍後將返回此旋轉的詳細信息。
讓我們繼續進行其他圖像的轉換。使用絕對定位,圖像堆疊在<figure>
內部:
.carousel figure { transform: rotateY(/* some amount here */rad); }
z-index值被忽略,因為這只是後續轉換的初步步驟。事實上,現在每個圖像都可以圍繞輪播圖的y軸旋轉一個角度,該角度取決於分配圖像的多邊形邊。首先,與<figure>
元素一樣,修改圖像的默認transform-origin,將其移動到多邊形的中心:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
然後,圖像可以圍繞其新的y軸旋轉一個量,該量由($i - 1) * $theta
弧度給出,其中$i
是圖像的索引(從1開始),$theta = 2 * $PI / $n
,其中$PI
表示數學常數π。因此,第二個圖像將旋轉$theta
,第三個旋轉2 * $theta
,依此類推,直到最後一個圖像旋轉($n - 1) * $theta
。
由於嵌套CSS轉換的層次性質,在輪播圖旋轉(即圍繞<figure>
修改後的y軸旋轉)期間,圖像的這種相對排列將被保留。
可以使用Sass @for
控制指令分配此每個圖像的旋轉量:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
這是使用for...through
結構而不是for...to
,因為對於for...to
,分配給索引變量$i
的最後一個值將是n-1而不是n。
請注意Sass的#{}
插值語法的兩個實例。在第一個實例中,它用於:nth-child()
選擇器的索引;在第二個實例中,它用於設置旋轉屬性值。
計算旁心距
多邊形旁心距的計算取決於邊數和邊的寬度,即取決於$n
和$item-width
變量。公式是:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
其中tan()
是正切三角函數。
這個公式可以通過一些幾何和三角學推導出來。在筆的源代碼中,此公式未按原樣實現,因為正切函數在Sass中不可用,因此使用了硬編碼值。相反,該公式將在JavaScript演示中完全實現。
間隔輪播項目
此時,輪播圖像並排“縫合”,形成所需的多邊形形狀。但是在這裡,它們緊密地堆積在一起,而在3D輪播圖中,它們之間通常會有空間。這種距離增強了3D空間的感知,因為它允許您看到輪播圖背面朝後的圖像。
可以通過引入另一個配置變量$item-separation
並將其用作每個<img alt="用CSS和JavaScript構建3D旋轉的輪播" >
元素的水平填充來可選地添加圖像之間的此間隙。更準確地說,取此值的一半作為左填充和右填充:
.carousel figure { transform: rotateY(/* some amount here */rad); }
最終結果可以在以下演示中看到:(此處應插入CodePen鏈接,展示間隔輪播項目)
圖像使用opacity
屬性變為半透明以更好地說明輪播結構,並且輪播根元素上的flex佈局用於將其在視口中垂直居中。
旋轉輪播圖
為了方便測試輪播圖旋轉,我將添加一個UI控件來在圖像之間來回導航。 (此處應插入CodePen鏈接,展示旋轉輪播圖)
我們使用一個currImage
整數變量來指示哪個圖像位於輪播圖的前面。當用戶與上一個/下一個按鈕交互時,此變量會增加或減少一個單位。
更新currImage
後,輪播圖旋轉將通過以下方式執行:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
(此處以及以下代碼片段中,使用ES6模板字面量在字符串中插入表達式;如果您願意,可以使用傳統的“ ”連接運算符)
其中theta
與之前相同:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
旋轉是-theta
,因為要導航到下一個項目,需要逆時針旋轉,並且這種旋轉值在CSS轉換中為負值。
請注意,currImage
值不受限於[0, numImages – 1]
範圍,而是可以無限增長,在正方向和負方向上都可以。事實上,如果前面的圖像是最後一個(所以currImage == n-1
),並且用戶單擊下一個按鈕,如果我們將currImage
重置為0以前進到第一個輪播圖像,則旋轉角度將從(n-1)*theta
轉換為0,這將使輪播圖在所有之前的圖像上向相反方向旋轉。當單擊上一個按鈕時,如果前面的圖像是第一個,則會出現類似的問題。
為了挑剔,我甚至應該檢查currentImage
的潛在溢出,因為Number
數據類型不能取任意大的值。這些檢查未在演示代碼中實現。
使用JavaScript增強
在看到構成輪播圖核心的基本CSS之後,現在可以使用JavaScript以多種方式增強組件,例如:
首先,我從樣式表中刪除與轉換原點和旋轉相關的變量和規則,因為這些將使用JavaScript完成:(此處應插入更新後的CSS代碼)
接下來,腳本中的carousel()
函數負責實例的初始化:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
root
參數指的是保存輪播圖的DOM元素。
通常,此函數將是一個構造函數,為頁面上的每個輪播圖生成一個對象,但在這裡我沒有編寫輪播庫,因此簡單的函數就足夠了。
為了在同一頁面上實例化多個組件,代碼等待所有圖像加載,為window
對象註冊load
事件的偵聽器,然後為每個具有carousel
類的元素調用carousel()
:
.carousel figure { transform: rotateY(/* some amount here */rad); }
carousel()
執行三個主要任務:
在檢查轉換設置代碼之前,我將介紹一些關鍵變量以及如何根據實例配置初始化它們:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
圖像數量(n)根據<figure>
元素的子元素數量初始化。幻燈片之間的間距(gap)從HTML5 data-gap
屬性(如果設置)初始化。背面可見性標誌(bfc)使用HTML5的dataset
API讀取。這將在稍後用於確定輪播圖背面的圖像是否可見。
設置CSS轉換
設置CSS轉換相關屬性的代碼封裝在setupCarousel()
中。此嵌套函數有兩個參數。第一個是輪播圖中的項目數量,即上面介紹的n變量。第二個參數s是輪播圖多邊形的邊長。正如我前面提到的,這等於圖像的寬度,因此可以使用getComputedStyle()
讀取其中一個的當前寬度:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
這樣,圖像寬度可以使用百分比值設置。
為了保持輪播圖自適應,我註冊了一個窗口大小調整事件的偵聽器,該偵聽器再次使用(可能已修改的)圖像大小調用setupCarousel()
:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
為簡單起見,我沒有去抖動大小調整偵聽器。
setupCarousel()
做的第一件事是使用傳遞的參數和前面討論的公式計算多邊形的旁心距:
.carousel figure { transform: rotateY(/* some amount here */rad); }
然後,此值用於修改<figure>
元素的transform-origin
,以獲得輪播圖的新旋轉軸:
.carousel figure img:not(:first-of-type) { position: absolute; left: 0; top: 0; }
接下來,應用圖像的樣式:
.img:not(:first-of-type) { transform-origin: 50% 50% (-$apothem); }
第一個循環為輪播項目之間的空間分配填充。第二個循環設置3D轉換。最後一個循環處理背面,如果在輪播圖配置中指定了相關標誌。
最後,調用rotateCarousel()
以將當前圖像移到前面。這是一個小的輔助函數,給定要顯示的圖像的索引,它會圍繞其y軸旋轉<figure>
元素以將目標圖像移動到前面。導航代碼也使用它來回移動:
.carousel figure img { @for $i from 2 through $n { &:nth-child(#{$i}) { transform: rotateY(#{($i - 1) * $theta}rad); } } }
這是最終結果,一個演示,其中實例化了幾個輪播圖,每個輪播圖都有不同的配置:(此處應插入最終CodePen鏈接)
來源和結論
在結束之前,我只是想感謝一些用於研究本教程的來源:(此處應列出參考來源)
如果您對代碼或輪播圖的功能有任何疑問或意見,請隨時在下面留言。
關於使用CSS和JavaScript構建3D旋轉輪播圖的常見問題解答(FAQ)
使您的3D旋轉輪播圖自適應涉及在CSS中使用媒體查詢。媒體查詢允許您根據設備的屏幕尺寸為不同的設備應用不同的樣式。您可以調整輪播圖元素的大小和位置以適應較小的屏幕。此外,還要考慮移動設備的觸摸事件,因為它們不像台式機那樣具有懸停狀態。
是的,您可以向輪播圖添加更多幻燈片。在HTML結構中,您可以在無序列表中添加更多列表項。每個列表項代表一個幻燈片。請記住調整CSS中每個幻燈片的旋轉角度以正確地在3D空間中定位它們。
可以使用HTML和JavaScript向輪播圖添加導航按鈕。在您的HTML中,添加兩個用於上一個和下一個導航的按鈕。在您的JavaScript中,向這些按鈕添加事件偵聽器。單擊時,它們應該更新輪播圖的旋轉以顯示上一個或下一個幻燈片。
當然,您可以使用圖像作為幻燈片。不要在CSS中設置背景顏色,而是可以為每個幻燈片設置背景圖像。確保圖像具有正確的大小和分辨率,以獲得最佳視覺效果。
可以使用JavaScript添加自動播放功能。您可以使用setInterval
函數在一段時間後自動更新輪播圖的旋轉。請記住在用戶與輪播圖交互時清除間隔,以防止出現意外行為。
是的,您可以使用CSS向輪播圖添加過渡效果。 transition
屬性允許您在指定持續時間內動畫化CSS屬性的變化。您可以將其應用於transform
屬性以動畫化輪播圖的旋轉。
使輪播圖無限循環涉及一些JavaScript。當輪播圖到達最後一個幻燈片時,您可以將其旋轉重置為第一個幻燈片。這給人一種無限循環的錯覺。
是的,您可以在幻燈片上添加文本。在您的HTML中,您可以在每個列表項中添加文本元素。在您的CSS中,根據幻燈片的位置定位文本元素並根據需要對其進行樣式設置。
可以使用CSS添加淡入淡出效果。您可以將opacity
屬性與transition
屬性結合使用以動畫化淡入淡出效果。根據幻燈片在輪播圖中的位置調整其opacity
以創建所需的效果。
是的,您可以使用不同的形狀作為輪播圖。輪播圖的形狀由CSS中的transform
屬性確定。通過調整transform
屬性的值,您可以創建立方體、圓柱體或任何其他3D形狀的輪播圖。
以上是用CSS和JavaScript構建3D旋轉的輪播的詳細內容。更多資訊請關注PHP中文網其他相關文章!