你不知道的 CSS 進度條

進度條是一個很是常見的功能,實現起來也不難,通常咱們都會用 div 來實現。html

做爲一個這麼常見的需求, whatwg 確定是不會沒有原生組件提供(雖然有咱們也不必定會用),那麼就讓咱們來康康有哪些有意思的進度條實現方式。git

常規版 — div 一波流

這是比較常規的實現方式,先看效果:github

源碼以下:web

<style>
  .progress1 {
    height: 20px;
    width: 300px;
    background-color: #f5f5f5;
    border-bottom-right-radius: 10px;
    border-top-right-radius: 10px;
  }
  .progress1::before {
    counter-reset: progress var(--percent, 0);
    content: counter(progress) '%\2002';
    display: block;
    height: 20px;
    line-height: 20px;
    width: calc(300px * var(--percent, 0) / 100);
    font-size: 12px;
    color: #fff;
    background-color: #2486ff;
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
    border-bottom-right-radius: 10px;
    border-top-right-radius: 10px;
  }
  .btn {
    margin-top: 30px;
  }
</style>
<div id="progress1" class="progress1"></div>
<button id="btn" class="btn">點我一下嘛~</button>
<script>
  'use strict';
  let startTimestamp = (new Date()).getTime();
  let currentPercentage = 0;
  let maxPercentage = 100;
  let countDelay = 100;
  let timer = null;
  let start = false;
  const percentageChange = () => {
    const currentTimestamp = (new Date()).getTime();
    if (currentTimestamp - startTimestamp >= countDelay) {
      currentPercentage++;
      startTimestamp = (new Date()).getTime();
      progress1.style = `--percent: ${currentPercentage}`;
    };
    if (currentPercentage < maxPercentage) {
      timer = window.requestAnimationFrame(percentageChange);
    } else {
      window.cancelAnimationFrame(timer);
    };
  };
  const clickHander = () => {
    if (!start) {
      start = true;
      percentageChange();
    };
  };
  btn.addEventListener('click', clickHander);
</script>

這種方法的核心就是以當前盒子爲容器,以 ::before 爲內容填充。用 <div> 的好處就是實現簡單,兼容性強,拓展性高,可是美中不足的是標籤語義化不強。瀏覽器

進階版 — input type="range"

<input /> 是一個很是實用的替換元素,不一樣的 type 能夠作不一樣的事情。第二種就是用 <input type="range" /> 來實現的。首先咱們來看看效果:app

源碼以下:ide

<style>
  .progress2[type='range'] {
    display: block;    
    font: inherit;
    height: 20px;
    width: 300px;
    pointer-events: none;
    background-color: linear-gradient(to right, #2376b7 100%, #FFF 0%);
  }
  .progress2[type='range'],
  .progress2[type='range']::-webkit-slider-thumb { 
    -webkit-appearance: none;
  };
  .progress2[type='range']::-webkit-slider-runnable-track {
    border: none;
    border-bottom-right-radius: 10px;
    border-top-right-radius: 10px;
    height: 20px;
    width: 300px;
  }
  .btn {
    margin-top: 30px;
  }
</style>
<input id="progress2" class="progress2" type='range' step="1" min="0" max="100" value="0"/>
<button id="btn" class="btn">點我一下嘛~</button>
<script>
  'use strict';
  let startTimestamp = (new Date()).getTime();
  let currentPercentage = 0;
  let maxPercentage = 100;
  let countDelay = 100;
  let timer = null;
  let start = false;
  let percentageGap = 10;
  const percentageChange = () => {
    const currentTimestamp = (new Date()).getTime();
    if (currentTimestamp - startTimestamp >= countDelay) {
      currentPercentage++;
      startTimestamp = (new Date()).getTime();
      progress2.value = currentPercentage;
      progress2.style.background = `linear-gradient(to right, #2376b7 ${currentPercentage}%, #FFF 0%`;
    };
    if (currentPercentage < maxPercentage) {
      timer = window.requestAnimationFrame(percentageChange);
    } else {
      window.cancelAnimationFrame(timer);
    };
  };
  const clickHander = () => {
    if (!start) {
      start = true;
      percentageChange();
    };
  };
  btn.addEventListener('click', clickHander);
</script>

寫完這個 demo 才發現,<input type="range" /> 並不適合作這個功能。。一個是實現困難,這個 type 組件的每一個元件均可以單獨修改樣式,可是效果並非很好。spa

另外一個是由於 range 有專屬語意 —— 範圍,因此它更適合作下面這種事:code

以上demo來自:https://developer.mozilla.org...htm

高級版 — progress 鴨

固然,上述兩種方式都是模擬進度條,實際上咱們並不須要模擬,由於 whatwg 有爲咱們提供原生的進度條標籤 —— <progress>

咱們先看效果:

實現以下:

<style>
  .progress3 {
    height: 20px;
    width: 300px;
    -webkit-appearance: none;
    display: block;
  }
  .progress3::-webkit-progress-value {
    background: linear-gradient(
      -45deg, 
      transparent 33%, 
      rgba(0, 0, 0, .1) 33%, 
      rgba(0,0, 0, .1) 66%, 
      transparent 66%
    ),
      linear-gradient(
        to top, 
        rgba(255, 255, 255, .25), 
        rgba(0, 0, 0, .25)
      ),
      linear-gradient(
        to left,
        #09c,
        #f44);
    border-radius: 2px; 
    background-size: 35px 20px, 100% 100%, 100% 100%;
  }
  .btn {
    margin-top: 30px;
  }
</style>
<progress id="progress3" class="progress3" max="100" value="0"></progress>
<button id="btn" class="btn">點我一下嘛~</button>
<script>
  'use strict';
  let startTimestamp = (new Date()).getTime();
  let currentPercentage = 0;
  let maxPercentage = 100;
  let countDelay = 100;
  let timer = null;
  let start = false;
  const percentageChange = () => {
    const currentTimestamp = (new Date()).getTime();
    if (currentTimestamp - startTimestamp >= countDelay) {
      currentPercentage++;
      startTimestamp = (new Date()).getTime();
      progress3.setAttribute('value', currentPercentage);
    };
    if (currentPercentage < maxPercentage) {
      timer = window.requestAnimationFrame(percentageChange);
    } else {
      window.cancelAnimationFrame(timer);
    };
  };
  const clickHander = () => {
    if (!start) {
      start = true;
      percentageChange();
    };
  };
  btn.addEventListener('click', clickHander);
</script>

雖然有原生的進度條標籤,可是規範裏並無規定它的具體表現,因此各個瀏覽器廠商徹底能夠按照本身的喜愛去定製,樣式徹底不可控,因此標籤雖好。。可用性卻不強,有點惋惜。

終極版 — meter 賽高

固然,可以實現進度條功能的標籤,除了上面所說的,還有 <meter> 標籤。先看效果:

代碼以下:

<style>
  .progress4 {
    display: block;    
    font: inherit;
    height: 50px;
    width: 300px;
    pointer-events: none;
  }
  .btn {
    margin-top: 30px;
  }
</style>
<meter id="progress4" class="progress4" low="60" high="80" min="0" max="100" value="0"></meter>
<button id="btn" class="btn">點我一下嘛~</button>
<script>
  'use strict';
  let startTimestamp = (new Date()).getTime();
  let currentPercentage = 0;
  let maxPercentage = 100;
  let countDelay = 100;
  let timer = null;
  let start = false;
  const percentageChange = () => {
    const currentTimestamp = (new Date()).getTime();
    if (currentTimestamp - startTimestamp >= countDelay) {
      currentPercentage++;
      startTimestamp = (new Date()).getTime();
      progress4.value = currentPercentage;
    };
    if (currentPercentage < maxPercentage) {
      timer = window.requestAnimationFrame(percentageChange);
    } else {
      window.cancelAnimationFrame(timer);
    };
  };
  const clickHander = () => {
    if (!start) {
      start = true;
      percentageChange();
    };
  };
  btn.addEventListener('click', clickHander);
</script>

這個標籤可能比較陌生,實際上它跟 <input type="range"> 的語義是同樣的,用來顯示已知範圍的標量值或者分數值。不同的就是。。。它樣式改起來更麻煩。

總結

本文測評了4種實現進度條的方式,得出的結論就是 —— <div> 賽高。。。雖然有的時候想優雅一點追求標籤語義化,可是資源不支持,也很尷尬。

嗯,萬能的 <div>

以上 demo 均可以個人 codepen 上查看:https://codepen.io/krischan77...

相關文章
相關標籤/搜索