CSS 雙色立體文字跑馬燈
這篇教學會使用 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 立體跑馬燈囉。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~