立体双色跑马灯
这篇教学会使用 CSS 的虚拟元素选择器,搭配 CSS animation 动画、CSS 变数、CSS transform 的 3D 变形和平移,实作非常吸睛又有趣的双色立体文字跑马灯。
快速导览:
制作双色文字
CSS 制作双色文字最常见的方式,是使用具有同样文字的两个 div,搭配 overflow: hidden 和文字的定位,就能将不同颜色的文字互相组合成双色字,但因为这个范例最终需要呈现“会动又立体”的文字,会使用“CSS 变数”和“虚拟元素”互相搭配,让后续编辑或调整更为方便,主要步骤如下,详细说明可参考范例注解。
- 将 CSS 变数设定在 HTML 元素的
style属性中。- 透过虚拟元素读取 CSS 变数内容,这样只需撰写一次内容。
- 设定元素
overflow: hidden隐藏超过范围的虚拟元素。- 使用
translateX搭配百分比单位调整虚拟元素位置,组合成双色文字 ( 只有transform平移的百分比是元素本身宽度 )。- 更多参考:CSS 变数、虚拟元素选择器、translate() 平移、calc() 基本数学运算
<!-- HTML 程式碼 -->
<!-- 設定兩個變數 --text 和 --w 負責文字和一半的寬度 -->
<div class="d" style="--text:'OXXO.STUDIO'; --w: 250px;">
<div style="--c1: #f00; --ct1: #fff;"></div>
<div style="--c2: #0c0; --ct2: #050;"></div>
</div>
<br>
<div class="d" style="--text:'TAIWAN'; --w: 200px;">
<div style="--c1: #fff; --ct1: #0a0;"></div>
<div style="--c2: #0a0; --ct2: #fff;"></div>
</div>
<br>
<div class="d" style="--text:'YES'; --w: 100px;">
<div style="--c1: #fc0; --ct1: #000;"></div>
<div style="--c2: #000; --ct2: #fc0;"></div>
</div>
<!-- CSS 程式碼 -->
<style>
.d {
display: inline-block; /* 改為 inline-block 讓浮動內容可以撐開高度 */
width: max-content; /* 寬度為內容最大寬度 */
font-family: impact, arial-black; /* 設定成比較粗的字體 */
font-size: 80px;
}
.d div {
position: relative; /* 讓內容絕對定位 */
width: var(--w); /* 寬度為變數 --w 寬度 */
float: left; /* 左右浮動 */
overflow: hidden; /* 超過範圍隱藏 */
border: 1px solid #000; /* 邊框 */
}
.d div:nth-child(1) {
background: var(--c1); /* 左邊 div 背景紅色,讀取變數 --c1 內容 */
}
.d div:nth-child(2) {
background: var(--c2); /* 右邊 div 背景綠色,讀取變數 --c2 內容 */
}
.d div::before {
width: max-content; /* 虛擬元素寬度為最大內容寬度 */
display: block; /* 改為 block ( 預設為 inline ) */
content: var(--text); /* 內容是變數 --text 內容 */
line-height: 1; /* 行高和字體大小相同 */
}
.d div:nth-child(1)::before {
color: var(--ct1); /* 左邊文字白色,讀取變數 --ct1 內容 */
/* 運用 translateX 計算定位,特別注意此處的百分比單位是乘以「元素本身寬度」,並非父元素 */
transform: translateX(calc(-50% + var(--w)));
}
.d div:nth-child(2)::before {
color: var(--ct2); /* 右邊文字深綠色,讀取變數 --ct2 內容 */
/* 運用 translateX 計算定位,特別注意此處的百分比單位是乘以「元素本身寬度」,並非父元素 */
transform: translateX(-50%);
}
</style>
制作双色文字跑马灯
将范例程序码加入 CSS 动画 animation 让“虚拟元素”进行平移,为了方便调整,在 HTML 元素里新增一个 --s 变数作为动画持续时间,并照下方规则设定动画位置:
| 左边 div | 右边 div | |
|---|---|---|
| 起始位置 | 父元素宽度 x 2 | 父元素宽度 |
| 结束位置 | 虚拟元素本身宽度 x -100% | 虚拟元素本身宽度 x -100% - 父元素宽度 |
<!-- HTML 程式碼 -->
<!-- 設定兩個變數 --text 和 --w 和 --s 負責文字和一半的寬度 -->
<div class="d" style="--text:'OXXO.STUDIO'; --w: 250px; --s: 5s;">
<div style="--c1: #f00; --ct1: #fff;"></div>
<div style="--c2: #0c0; --ct2: #050;"></div>
</div>
<br>
<div class="d" style="--text:'TAIWAN'; --w: 200px; --s: 10s;">
<div style="--c1: #fff; --ct1: #0a0;"></div>
<div style="--c2: #0a0; --ct2: #fff;"></div>
</div>
<br>
<div class="d" style="--text:'YES'; --w: 100px; --s: 2s;">
<div style="--c1: #fc0; --ct1: #000;"></div>
<div style="--c2: #000; --ct2: #fc0;"></div>
</div>
<!-- CSS 程式碼 -->
<style>
.d {
display: inline-block; /* 改為 inline-block 讓浮動內容可以撐開高度 */
width: max-content; /* 寬度為內容最大寬度 */
font-family: impact, arial-black; /* 設定成比較粗的字體 */
font-size: 80px;
}
.d div {
position: relative; /* 讓內容絕對定位 */
width: var(--w); /* 寬度為變數 --w 寬度 */
float: left; /* 左右浮動 */
overflow: hidden; /* 超過範圍隱藏 */
border: 1px solid #000; /* 邊框 */
}
.d div:nth-child(1) {
background: var(--c1); /* 左邊 div 背景紅色,讀取變數 --c1 內容 */
}
.d div:nth-child(2) {
background: var(--c2); /* 右邊 div 背景綠色,讀取變數 --c2 內容 */
}
.d div::before {
width: max-content; /* 虛擬元素寬度為最大內容寬度 */
display: block; /* 改為 block ( 預設為 inline ) */
content: var(--text); /* 內容是變數 --text 內容 */
line-height: 1; /* 行高和字體大小相同 */
}
.d div:nth-child(1)::before {
color: var(--ct1); /* 左邊文字白色,讀取變數 --ct1 內容 */
/* 運用 translateX 計算定位,特別注意此處的百分比單位是乘以「元素本身寬度」,並非父元素 */
animation: oxxo1 var(--s) infinite linear;
}
.d div:nth-child(2)::before {
color: var(--ct2); /* 右邊文字深綠色,讀取變數 --ct2 內容 */
/* 運用 translateX 計算定位,特別注意此處的百分比單位是乘以「元素本身寬度」,並非父元素 */
animation: oxxo2 var(--s) infinite linear;
}
@keyframes oxxo1 {
0% {transform: translateX(calc( 2 * var(--w)));} /* 左邊虛擬元素起始值 */
100% {transform: translateX(-100%);}
}
@keyframes oxxo2 {
0% {transform: translateX(var(--w));} /* 右邊虛擬元素起始值 */
100% {transform: translateX(calc(-100% - var(--w)));}
}
</style>
使用 transform 制作双色立体文字跑马灯
延伸范例程序码,在 HTML 里使用一个类别为“camera”的 div 包覆双色文字跑马灯,这个 div 主要会设定 3D 变形的“摄影机视角”,接着将最外层类别为“d”的 div 的虚拟元素设定为“上盖”和“阴影”,就能做出漂亮的双色立体文字跑马灯。
- 注意,因为 HTML 元素本身具有“后盖前”的阶层关系,所以需要额外设定
z-index才能让下方元素覆盖上方元素。- 参考:CSS transform 转换函数、图层关系:z-index
<!-- HTML 程式碼 -->
<!-- 使用 camera 包覆剛剛的 HTML -->
<div class="camera">
<div class="d" style="--text:'OXXO.STUDIO'; --w: 250px; --s: 5s;">
<div style="--c1: #f00; --ct1: #fff;"></div>
<div style="--c2: #0c0; --ct2: #050;"></div>
</div>
<br>
<div class="d" style="--text:'TAIWAN'; --w: 250px; --s: 10s;">
<div style="--c1: #fff; --ct1: #0a0;"></div>
<div style="--c2: #0a0; --ct2: #fff;"></div>
</div>
<br>
<div class="d" style="--text:'YES'; --w: 250px; --s: 2s;">
<div style="--c1: #fc0; --ct1: #000;"></div>
<div style="--c2: #000; --ct2: #fc0;"></div>
</div>
</div>
<!-- CSS 程式碼 -->
<style>
.camera {
width: max-content;
margin: 50px auto;
perspective: 500px; /* 攝影機視角 */
perspective-origin: 50% 20%; /* 攝影機中心 */
}
.d {
display: inline-block;
position: relative;
width: max-content;
font-family: impact, arial-black;
font-size: 80px;
transform-style: preserve-3d; /* 將內容視為同一個 3D 空間 *
transform: rotateX(-10deg); /* 繞 X 軸旋轉 10 deg */
}
.d div {
position: relative;
width: var(--w);
float: left;
overflow: hidden;
border: 1px solid #000;
}
.d::before, .d::after {
position: absolute; /* 虛擬元素作為上蓋和影子進行絕對定位 */
content: "";
width: var(--w); /* 長寬相同,產生一個正方形區域 */
height: var(--w);
top: 0;
left: 0;
background: #666;
}
.d:nth-of-type(1) {z-index: 3;} /* 最上方 */
.d:nth-of-type(1)::after {display: none;} /* 最上方不需要影子 */
.d:nth-of-type(2) {z-index: 2;} /* 中間層 */
.d:nth-of-type(2)::after {display: none;} /* 中間層不需要影子 */
.d:last-of-type {z-index: 1;} /* 最下層 */
.d::before {
transform-origin: 100% 0 0;
transform: translateY(1px) rotateY(-135deg) rotateX(90deg); /* 最上方蓋子 */
}
.d::after {
transform-origin: 100% 0 0;
transform: translateY(1.3em) rotateY(-45deg) rotateX(-90deg); /* 影子 */
}
.d div:nth-child(1) {
background: var(--c1);
transform-origin: 100% 0 0;
transform: rotateY(-45deg); /* 左側 div 旋轉 */
}
.d div:nth-child(2) {
background: var(--c2);
transform-origin: 0 0 0;
transform: rotateY(45deg); /* 右側 div 旋轉 */
}
.d div::before {
width: max-content;
display: block;
content: var(--text);
line-height: 1;
}
.d div:nth-child(1)::before {
color: var(--ct1);
animation: oxxo1 var(--s) infinite linear;
}
.d div:nth-child(2)::before {
color: var(--ct2);
animation: oxxo2 var(--s) infinite linear;
}
@keyframes oxxo1 {
0% {transform: translateX(calc( 2 * var(--w)));}
100% {transform: translateX(-100%);}
}
@keyframes oxxo2 {
0% {transform: translateX(var(--w));}
100% {transform: translateX(calc(-100% - var(--w)));}
}
</style>
如果修改 HTML 里的变数,跑马灯的大小也会跟着改变,下图的变数为:--w:300px、--w:200px 和 --w:150px。
小结
基本上要制作双色文字跑马灯并不困难,困难的地方在于要让整体程序码容易修改,这个范例仍然存有“超过三层就要稍微修改 CSS”的缺陷,但整体来说已经可以很顺利的制作出 3D 立体跑马灯啰。
微信扫码关注
抖音扫码关注