卷轴控制放射形选单
这篇教学会使用 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 功能应该就能普及化,也就能做出更多有趣的效果了。
微信扫码关注
抖音扫码关注