|
|
很多人以為要做動畫一定要用 SVG。
其實Picture Elements 配 card-mod,就能做出不錯的動畫。

先裝 card-mod
- HACS → 前端 → 搜尋 card-mod → 下載
- 重新整理瀏覽器(Ctrl+F5)
強烈建議:裝成「前端模組」而不是資源
card-mod 有些功能裝成前端模組才會正常運作,
而且效能好很多。
- # configuration.yaml
- frontend:
- extra_module_url:
- - /hacsfiles/lovelace-card-mod/card-mod.js
複製代碼
改完重啟 HA,然後清瀏覽器快取。
card-mod 是什麼
一句話:讓你對任何卡片套用自己的 CSS。
最基本的用法:
- type: picture-elements
- image: /local/floorplan/home.png
- card_mod:
- style: |
- ha-card {
- border-radius: 16px;
- box-shadow: 0 4px 16px rgba(0,0,0,0.12);
- }
- elements:
- - ...
複製代碼
重要限制:card-mod 只對有 `ha-card` 元素的卡片有效。
- 能用:picture-elements、tile、entities、button 等幾乎所有可見的卡片
- 不能用:conditional、entity_filter、vertical-stack、horizontal-stack、grid
那些「容器型」的卡片沒有自己的 ha-card,
但它們裡面包的卡片可以各自用 card-mod。

動畫一:脈動(最常用)
讓警報圖示一閃一閃的:
- - type: conditional
- conditions:
- - entity: binary_sensor.kitchen_leak
- state: "on"
- elements:
- - type: icon
- icon: mdi:water-alert
- style:
- top: 44%
- left: 72%
- color: "#e53935"
- "--mdc-icon-size": 36px
- animation: pulse 1.2s infinite
複製代碼
然後在卡片層定義那個動畫:
- card_mod:
- style: |
- @keyframes pulse {
- 0% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
- 50% { opacity: 0.4; transform: translate(-50%, -50%) scale(1.25); }
- 100% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
- }
複製代碼
這裡有一個非常重要的細節:
keyframes 裡的 transform 一定要包含 `translate(-50%, -50%)`。
為什麼:Picture Elements 預設用 transform: translate(-50%, -50%)
把元素置中在座標上。
如果你的動畫只寫 transform: scale(1.25),
它會覆蓋掉原本的置中,元素就會往右下角跳掉。
這是最多人踩的坑。
動畫二:呼吸燈(柔和的明暗變化)
- style:
- animation: breathe 3s ease-in-out infinite
複製代碼- card_mod:
- style: |
- @keyframes breathe {
- 0%, 100% { opacity: 0.55; }
- 50% { opacity: 1; }
- }
複製代碼
適合:表示「正在運作中」,例如除濕機、洗衣機。
比閃爍溫和很多,不會讓人煩躁。
動畫三:旋轉(風扇、掃地機)
- - type: state-icon
- entity: fan.living_room
- style:
- top: 16%
- left: 12%
- animation: spin 2s linear infinite
複製代碼- @keyframes spin {
- from { transform: translate(-50%, -50%) rotate(0deg); }
- to { transform: translate(-50%, -50%) rotate(360deg); }
- }
複製代碼
讓轉速對應實際風速:
- animation: >
- spin {{ 4 - (state_attr('fan.living_room','percentage') | int(0) / 33) }}s
- linear infinite
複製代碼
風速越快轉越快。這個小細節做出來很有趣。
只在開著時才轉:
- animation: >
- {% if is_state('fan.living_room','on') %}
- spin 2s linear infinite
- {% else %}
- none
- {% endif %}
複製代碼

動畫四:漸變(最實用,也最自然)
這個不是 keyframes 動畫,而是 transition。
差別:
- animation —— 一直重複播放(脈動、旋轉)
- transition —— 狀態改變時,平滑地過渡
transition 是做平面圖最該用的,因為它不吵。
- - type: image
- entity: light.living_room
- image: /local/floorplan/rooms/living_on.png
- style:
- top: 50%
- left: 50%
- width: 100%
- transition: opacity 0.8s ease-in-out
- opacity: >
- {{ 1 if is_state('light.living_room','on') else 0 }}
複製代碼
燈開的時候房間會在 0.8 秒內慢慢亮起來,關的時候慢慢暗下去。
這個效果做出來之後,整張平面圖的質感完全不一樣。
再進一步:亮度也跟著漸變
- opacity: >
- {{ ((state_attr('light.living_room','brightness') | int(0)) / 255)
- | round(2) }}
複製代碼
把燈調到 30%,平面圖上的房間也只有 30% 亮。
完整範例
把上面的東西組合起來:
- type: picture-elements
- image: /local/floorplan/home.png
- card_mod:
- style: |
- ha-card {
- border-radius: 16px;
- overflow: hidden;
- }
- @keyframes pulse {
- 0% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
- 50% { opacity: 0.4; transform: translate(-50%, -50%) scale(1.25); }
- 100% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
- }
- @keyframes spin {
- from { transform: translate(-50%, -50%) rotate(0deg); }
- to { transform: translate(-50%, -50%) rotate(360deg); }
- }
- @keyframes breathe {
- 0%, 100% { opacity: 0.55; }
- 50% { opacity: 1; }
- }
- elements:
- # --- 亮燈圖層(漸變)---
- - type: image
- entity: light.living_room
- image: /local/floorplan/rooms/living_on.png
- style:
- top: 50%
- left: 50%
- width: 100%
- transition: opacity 0.8s ease-in-out
- opacity: >
- {{ ((state_attr('light.living_room','brightness') | int(0)) / 255)
- | round(2) }}
- tap_action:
- action: toggle
- # --- 燈的圖示 ---
- - type: state-icon
- entity: light.living_room
- style:
- top: 24%
- left: 22%
- transition: color 0.5s
- tap_action:
- action: toggle
- hold_action:
- action: more-info
- # --- 漏水警報(脈動)---
- - type: conditional
- conditions:
- - entity: binary_sensor.kitchen_leak
- state: "on"
- elements:
- - type: icon
- icon: mdi:water-alert
- style:
- top: 44%
- left: 72%
- color: "#e53935"
- "--mdc-icon-size": 36px
- animation: pulse 1.2s infinite
- # --- 風扇(旋轉)---
- - type: state-icon
- entity: fan.living_room
- style:
- top: 16%
- left: 12%
- animation: >
- {% if is_state('fan.living_room','on') %}
- spin 2s linear infinite
- {% else %}
- none
- {% endif %}
複製代碼

動畫的五個原則(很重要)
一、預設不要動
一張一直在動的平面圖會讓人很煩。
我的原則:
- 常態 → transition(只在狀態改變時動一下)
- 異常 → animation(持續動,吸引注意)
二、transition 時間 0.3-0.8 秒
- 太快(0.1s)→ 感覺不到
- 太慢(2s)→ 覺得系統很鈍
0.5 秒左右是最舒服的。
三、同時動的東西不要超過兩個
三個圖示同時在閃,眼睛不知道要看哪裡。
四、動畫一定要有意義
- 旋轉 → 表示「正在轉」(風扇、洗衣機)
- 脈動 → 表示「需要注意」(警報)
- 漸變 → 表示「狀態改變了」
純粹為了好看的動畫,兩天後你就會想關掉。
五、在手機上測試效能
太多動畫會讓手機發燙、耗電。
特別注意:
- animation 是持續消耗的(即使你沒在看那個頁面)
- transition 只在改變時消耗,幾乎沒成本
所以能用 transition 就不要用 animation。
除錯:動畫沒作用怎麼辦
- 圖示跳到右下角 → keyframes 少了 translate(-50%, -50%)
- 完全沒動靜 → card-mod 沒裝好,或沒清瀏覽器快取
- 範本沒生效 → style 裡的範本要用 > 區塊,不要用引號
- 在電腦上正常、手機上不動 → 手機的省電模式可能會停用動畫
---
下一篇:要不要升級到 SVG。
我會誠實講 SVG 好在哪、以及什麼情況下你根本不需要。 |
|