CSS3 電池充電
阿新 • • 發佈:2018-10-31
<!DOCTYPE html> <html lang="en"> <meta charset="utf-8"> <head> <style> body { padding: 1em; } /* 這是一種CSS3定義變數的寫法 */ :root { --battery-width: 5em; --battery-height: 10em; --battery-border-width: 1em; --battery-border-color: black; } .battery { width: var(--battery-width); height: var(--battery-height); border: var(--battery-border-width) solid var(--battery-border-color); padding: calc(var(--battery-border-width) / 2); margin-top: var(--battery-border-width); position:relative; /* 對於linear-gradient來說,如果臨近兩個顏色的百分比相同,可以製作出斑馬線的效果,而不是漸變 */ background-image: linear-gradient(0deg, white 15%, black 15%); background-repeat: repeat-y; background-size: 100% 20%; background-clip: content-box; /* 將背景限定在內容區域 */ box-sizing: content-box; transform: rotate(0deg); display: inline-block; } /* 偽元素(Pseudo-elements)*/ .battery::before { content: ''; width: calc(2 * var(--battery-border-width)); height: var(--battery-border-width); background-color: var(--battery-border-color); position: absolute; top: calc(-2 * var(--battery-border-width)); left: calc(50% - var(--battery-border-width)); } /* 偽元素的原始大小和父元素的內容區域一樣 */ .battery::after { content: ''; width: calc(100% - var(--battery-border-width)); height: calc(100% - var(--battery-border-width)); position: absolute; background-color: white; /* CSS3的動畫有一個問題,就是如果重複播放,那麼到達最後一幀時會立馬切到第一幀(或某個值如果再加會達到上限,則返回初始值),導致最後一幀不顯示 解決方法就是在終止狀態前複製一份終止狀態。 */ animation: battery-change 2s steps(5) infinite alternate; animation-play-state: paused; } @keyframes battery-change { from { height: calc(100% - var(--battery-border-width)); } 80% { height: 0px; } to { height: 0px; } } </style> <style id="batteryStyle"></style> <script> window.onload = ()=> { const battery = document.getElementById("battery"); // 偽元素不是一個實際存在於DOM的元素,因此只能用getComputedStyle拿到其計算後的屬性,並且只能獲取不能更改 const batteryAfter = window.getComputedStyle(battery, "::after"); //getPropertyValue拿到的值有可能會帶轉化後的單位px,這樣是不能直接參與運算的 const batteryHeight = parseInt(batteryAfter.getPropertyValue("height")); const batterySteps = 5; const batteryStepPercent = 100 / batterySteps; const batteryStepHeight = batteryHeight / batterySteps; const batteryTmpValue = 100 * batteryStepHeight / batteryHeight; /* 狀態切換的方法有: (1)動態切換class (2)CSSStyleSheet.insertRule()和deleteRule (3)使用現有的style標籤,通過!import來使值生效 */ const batteryStyle = document.getElementById("batteryStyle"); /* offsetWidth(Height): 2*border + 2*padding + content scrollWidth(Height): 1*border + 2*padding + content clientWidth(Height): 0*border + 2*padding + content */ console.log(battery.offsetHeight, battery.scrollHeight, battery.clientHeight); window.setBattery = (value) => { value = 100 - value; //level這裡要跟前面css的step相對應 const currentHeight = parseInt(value / batteryTmpValue) * batteryStepHeight; batteryStyle.innerText = ".battery::after{height: " + currentHeight + "px !important; animation-play-state: paused;}"; } let batteryIntervalId; window.batteryCharging = (type) => { switch(type) { case 'css': if(batteryIntervalId != undefined) { clearInterval(batteryIntervalId); batteryIntervalId = undefined; } batteryStyle.innerText = ".battery::after{animation-play-state: running !important;}"; break; case 'js': let value = 0; if(batteryIntervalId == undefined) { //充電 batteryIntervalId = setInterval(()=> { setBattery(value, type); value += batteryStepPercent; if(value > 100) { value = 0; } }, 300); } break; } } } </script> </head> <body> <div id="battery" class="battery"></div> <button onclick="batteryCharging('css')">CSS3動畫</button> <button onclick="batteryCharging('js')">JS動畫</button> </body> </html>