CSS 捲軸控制放射選單
這篇教學會使用 CSS 的 transform 製作放射形的選單,並透過 step-end 的 CSS 動畫呈現方式搭配 animation-timeline 控制動畫進度,讓使用者拖拉捲軸時,放射形的選單同時會發生改變的動畫效果。
注意,這個效果目前僅支援 Chrome 和 Edge,其他部分瀏覽器或行動裝置瀏覽器可能不支援。
快速導覽:
製作放射形選單
根據下方說明撰寫程式碼,執行後會在畫面看到一個具有七個連結的選單。
- 說明:
- 使用
.main
模擬瀏覽器視窗,當中放置.menu
和.contain
。.main
使用sticky
定位,如果是真實視窗,使用fixed
定位。.menu
內容有七個超連結。.contain
作用是撐高視窗,產生捲軸。- 參考:內容溢出與裁切 overflow、position:sticky 黏貼定位
- 線上展示:https://codepen.io/oxxo/pen/MYWKpPw
<!-- HTML 程式碼 -->
<div class="main">
<div class="menu">
<a href="">Apple</a>
<a href="">Banana</a>
<a href="">Oxxo</a>
<a href="">Coconut</a>
<a href="">Papaya</a>
<a href="">Peach</a>
<a href="">Watermelon</a>
</div>
<div class="contain"></div>
</div>
<!-- CSS 程式碼 -->
<style>
.main {
position: relative;
width: 540px;
height: 400px;
overflow: hidden scroll; /* 超過範圍隱藏,y 方向出現捲軸 */
border: 1px solid #000;
}
.menu {
position: sticky; /* 黏貼定位,如果是瀏覽器視窗改用 fixed */
top: 50px;
left: 50px;
width: 200px;
height: 200px;
border-radius: 50%; /* 讓選單樣式為原形 */
background: #ccc;
}
.menu a {
display: block;
width: 200px;
font-size: 40px;
}
.contain {height: 2000px;}
</style>
使用 CSS transform
將每個超連結旋轉成放射形,注意需要「先移動,再先旋轉在移動」,目的在於先將選單移動到父元素中心點,接著進行旋轉,旋轉後後再往外移動同樣的距離,程式碼中額外使用「變數」,將移動的數值獨立為變數,讓後續修改更為方便。
<!-- HTML 程式碼 -->
<div class="main">
<div class="menu">
<a href="">Apple</a>
<a href="">Banana</a>
<a href="">Oxxo</a>
<a href="">Coconut</a>
<a href="">Papaya</a>
<a href="">Peach</a>
<a href="">Watermelon</a>
</div>
<div class="contain"></div>
</div>
<!-- CSS 程式碼 -->
<style>
.main {
position: relative;
width: 540px;
height: 400px;
overflow: hidden scroll;
border: 1px solid #000;
}
.menu {
position: sticky;
top: 50px;
left: 50px;
width: 200px;
height: 200px;
border-radius: 50%;
background: #ccc;
--x: 220px; /* 變數 */
rotate: 0deg; /* 預設旋轉角度 */
}
.menu a {
position: absolute; /* 改成絕對定位 */
display: block;
width: 200px;
font-size: 40px;
}
.menu a:nth-child(1){
transform: translate(0px,70px) rotateZ(0deg) translateX(var(--x));
}
.menu a:nth-child(2){
transform: translate(0px,70px) rotateZ(30deg) translateX(var(--x));
}
.menu a:nth-child(3){
transform: translate(0px,70px) rotateZ(60deg) translateX(var(--x));
}
.menu a:nth-child(4){
transform: translate(0px,70px) rotateZ(90deg) translateX(var(--x));
}
.menu a:nth-child(5){
transform: translate(0px,70px) rotateZ(120deg) translateX(var(--x));
}
.menu a:nth-child(6){
transform: translate(0px,70px) rotateZ(150deg) translateX(var(--x));
}
.menu a:nth-child(7){
transform: translate(0px,70px) rotateZ(180deg) translateX(var(--x));
}
.contain {height: 2000px;}
</style>
使用捲軸控制放射選單
延伸上方的放射狀選單,加入多個 CSS 變數設定初始透明度,使用變數的目的在於如果後續要修改透明度,只需要修改一次即可,因此如果動畫裡修改了變數,相關樣式就會發生變動。接著撰寫動畫內容,因為有七個選單,所以動畫使用 16.7% 為間隔,每一格中除了旋轉角度,也同時會修改變數內容,執行到該格動畫時,選單透明度就會發生變化。
<!-- HTML 程式碼 -->
<div class="main">
<div class="menu">
<a href="">Apple</a>
<a href="">Banana</a>
<a href="">Oxxo</a>
<a href="">Coconut</a>
<a href="">Papaya</a>
<a href="">Peach</a>
<a href="">Watermelon</a>
</div>
<div class="contain"></div>
</div>
<!-- CSS 程式碼 -->
<style>
.main {
position: relative;
width: 540px;
height: 400px;
overflow: hidden scroll;
border: 1px solid #000;
}
.menu {
position: sticky;
top: 50px;
left: 50px;
width: 200px;
height: 200px;
border-radius: 50%;
background: #ccc;
--x: 220px;
rotate: 0deg;
--o: 0.2; /* 變數,非選擇時的透明度 */
--o1: var(--o); /* 變數,數值與 --o 相同 */
--o2: var(--o); /* 變數,數值與 --o 相同 */
--o3: var(--o); /* 變數,數值與 --o 相同 */
--o4: var(--o); /* 變數,數值與 --o 相同 */
--o5: var(--o); /* 變數,數值與 --o 相同 */
--o6: var(--o); /* 變數,數值與 --o 相同 */
--o7: var(--o); /* 變數,數值與 --o 相同 */
animation: oxxo step-end forwards; /* 使用 step-end 讓進度從第二格開始一格格移動 */
animation-timeline: scroll(); /* 根據捲軸滾動改變動畫進度 */
}
.menu a {
position: absolute; /* 改成絕對定位 */
display: block;
width: 200px;
font-size: 40px;
opacity: var(--o); /* 預設透明度 */
}
.menu a:nth-child(1){
transform: translate(0px,70px) rotateZ(0deg) translateX(var(--x));
opacity: var(--o1); /* 第一個選單的透明度 */
}
.menu a:nth-child(2){
transform: translate(0px,70px) rotateZ(30deg) translateX(var(--x));
opacity: var(--o2); /* 第二個選單的透明度 */
}
.menu a:nth-child(3){
transform: translate(0px,70px) rotateZ(60deg) translateX(var(--x));
opacity: var(--o3); /* 第三個選單的透明度 */
}
.menu a:nth-child(4){
transform: translate(0px,70px) rotateZ(90deg) translateX(var(--x));
opacity: var(--o4); /* 第四個選單的透明度 */
}
.menu a:nth-child(5){
transform: translate(0px,70px) rotateZ(120deg) translateX(var(--x));
opacity: var(--o5); /* 第五個選單的透明度 */
}
.menu a:nth-child(6){
transform: translate(0px,70px) rotateZ(150deg) translateX(var(--x));
opacity: var(--o6); /* 第六個選單的透明度 */
}
.menu a:nth-child(7){
transform: translate(0px,70px) rotateZ(180deg) translateX(var(--x));
opacity: var(--o7); /* 第七個選單的透明度 */
}
.contain {height: 2000px;}
/* 動畫過程中除了旋轉角度,也改變變數數值 */
@keyframes oxxo {
0% {
rotate: 0deg;
--o1: 1;
}
16.7% {
rotate: -30deg;
--o1: var(--o);
--o2: 1;
}
33.4% {
rotate: -60deg;
--o2: var(--o);
--o3: 1;
}
50.1% {
rotate: -90deg;
--o3: var(--o);
--o4: 1;
}
66.8% {
rotate: -120deg;
--o4: var(--o);
--o5: 1;
}
83.5% {
rotate: -150deg;
--o5: var(--o);
--o6: 1;
}
100% {
rotate: -180deg;
--o6: var(--o);
--o7: 1;
}
}
</style>
小結
使用捲軸控制放射選單是個滿有趣的效果,雖然目前只有 Chrome 和 Edge 支援,但相信不久的將來,相關 CSS 功能應該就能普及化,也就能做出更多有趣的效果了。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~