iT邦幫忙

2025 iThome 鐵人賽

DAY 26
2
Modern Web

關於那些有趣的 CSS 效果系列 第 26

( Day 26 ) 純 CSS 雙色立體文字跑馬燈

  • 分享至 

  • xImage
  •  

最近股票一直漲,看著電視牆立體的跑馬燈,有股沒有上到車的不悅一直卡在心裡,一氣之下乾脆用純 CSS 做個立體文字跑馬燈,做完之後怨氣應該也會消去一半吧~ 這個效果印象中是好久以前我在逛 CodePen 時看到的,但覺得沒有寫得很好,索性直接重寫,讓整體程式碼也更好閱讀也更好維護~

純 CSS 雙色立體文字跑馬燈

正文開始

這篇教學會使用 CSS 的虛擬元素選擇器,搭配 CSS animation 動畫、CSS 變數、CSS transform 的 3D 變形和平移,實作非常吸睛又有趣的雙色立體文字跑馬燈。

CSS 教學 - CSS 雙色立體文字跑馬燈

製作雙色文字

CSS 製作雙色文字最常見的方式,是使用具有同樣文字的兩個 div,搭配 overflow: hidden 和文字的定位,就能將不同顏色的文字互相組合成雙色字,但因為這個範例最終需要呈現「會動又立體」的文字,會使用「CSS 變數」和「虛擬元素」互相搭配,讓後續編輯或調整更為方便,主要步驟如下,詳細說明可參考範例註解。

  • 將 CSS 變數設定在 HTML 元素的 style 屬性中
  • 透過虛擬元素讀取 CSS 變數內容,這樣只需撰寫一次內容。
  • 設定元素 overflow: hidden 隱藏超過範圍的虛擬元素。
  • 使用 translateX 搭配百分比單位調整虛擬元素位置,組合成雙色文字 ( 只有 transform 平移的百分比是元素本身寬度 )。
<!-- 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 教學 - CSS 雙色立體文字跑馬燈 - 製作雙色文字

製作雙色文字跑馬燈

將範例程式碼加入 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>

CSS 教學 - CSS 雙色立體文字跑馬燈 - 製作雙色文字跑馬燈

使用 transform 製作雙色立體文字跑馬燈

延伸範例程式碼,在 HTML 裡使用一個類別為「camera」的 div 包覆雙色文字跑馬燈,這個 div 主要會設定 3D 變形的「攝影機視角」,接著將最外層類別為「d」的 div虛擬元素設定為「上蓋」和「陰影」,就能做出漂亮的雙色立體文字跑馬燈。

注意,因為 HTML 元素本身具有「後蓋前」的階層關係,所以需要額外設定 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>

CSS 教學 - CSS 雙色立體文字跑馬燈 - 使用 transform 製作雙色立體文字跑馬燈

如果修改 HTML 裡的變數,跑馬燈的大小也會跟著改變,下圖的變數為:--w:300px--w:200px--w:150px

CSS 教學 - CSS 雙色立體文字跑馬燈 - 使用 transform 製作雙色立體文字跑馬燈

小結

基本上要製作雙色文字跑馬燈並不困難,困難的地方在於要讓整體程式碼容易修改,這個範例仍然存有「超過三層就要稍微修改 CSS」的缺陷,但整體來說已經可以很順利的製作出 3D 立體跑馬燈囉。


上一篇
( Day 25 ) 純 CSS 空心文字、文字水波背景動畫
下一篇
( Day 27 ) 純 CSS 樓梯文字動態效果
系列文
關於那些有趣的 CSS 效果35
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言