The <progress>
element doesn't always play nice.
It doesn't have a consistent appearance across the popular browsers. In addition, different browsers impose different limitations on the <progress>
element.
Because of this, it's often overlooked in favor of styled <div>
combos.
ep
tackles this;
- Cross browser reset and styling to pull
<progress>
element in line with modern slim-style bars - CSS helpers that provide classes and attributes to deal with things like positioning, growth style, simulation etc.
- Optional JS helper for better control and interaction with
<progress>
elements. For example; being able to hook into network request status and display this to the end user. - Plays nice wherever the
<progress>
element is supported!
const myEp = new Ep(document.querySelector('progress'));
const makeRequest = () => {
myEp.simulate();
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myEp.complete();
}
};
xhttp.open('GET', '/index.html', true);
xhttp.send();
};
(myEp._VALUE) ? myEp.set(0, makeRequest) : makeRequest();
Chrome | Firefox | Safari | Opera | Edge | IE(10+) |
---|---|---|---|---|---|
π | π | π | π | π | π |
- iOS Safari doesn't like indeterminate
<progress>
elements. Get round this by not setting your<progress>
element to be indeterminate but instead using the helper classep--indeterminate
which will mock the indeterminate state. - In IE, ensure that the
max
attribute is set when using specific values. If nomax
is set, the value won't go higher than1
π’
You have various options with how to use ep
;
- Use the stylesheet by adding
ep.css
to your app. - Include the optional JS helper
ep.js
for some more control. - Integrate the
ep
styles with your own SASS by importing the parts you need.
You can grab a copy of ep
through bower
or npm
;
bower install ep
npm install @jh3y/ep
If you're just using the stylesheet, you just need to include it. No alterations need to be made to your current <progress>
elements unless you want to make use of some of the helper classes and attributes.
<progress value="75" max="100"></progress>
<progress class="ep--fixed ep--top" value="75" max="100"></progress>
<progress data-simulate="true" value="75" max="100"></progress>
Need to change the color of a <progress>
element or something else? Override the rule. For example, change the color to purple
;
progress {
background: purple;
}
progress::-moz-progress-bar {
background: purple;
}
progress::-webkit-progress-bar {
background: purple;
}
progress::-webkit-progress-value {
background: purple;
}
There is also a SASS
mixin included to as a shorthand to do this;
@import '~ep/mixins';
.progress {
@include color-bar(purple);
}
If you choose to use the optional JS helper. You'll have access to the Ep
constructor class. Refer to the JS API for further info.
const el = document.querySleect
const myEp = new Ep()
Say you want to pick and choose pieces of ep
. Simple. This is actually the easiest way to override ep
s configuration variables. ep
makes use of the !default
flag in sass
to make this possible. For example; let's say we only want the core styles but we don't want any opacity and we want the primary color to be be purple.
$ep-fg: purple;
$ep-opacity: 1;
@import '~ep/core'
Without the use of JS, ep
provides some CSS helpers in the form of attributes and classes you can apply to <progress>
elements to define behaviors.
Aesthetic helpers come in the form of classes;
ep--top
- position absolute topep--bottom
- position absolute bottomep--fixed
- position fixedep--spread
- change style of<progress>
bar to spreadep--indeterminate
- show indeterminate state
Behavioural helpers come in the form of attributes that must be applied to your <progress>
elements;
data-complete
- complete progress(set to 100 and hide, more control with JS helper)data-simulate
- slowly simulate progress in steps up to99%
over 30 seconds(request timeout), can be configured/overrodedata-mock="value"
- mock progress for given number of secondsdata-staggered-mock="value"
- mock progress but with staggered styledata-timer="value"
- use progress element as timer for given secondsdata-pause
- pauses any animation in place such as timer, mock etc.
NOTE:: The mock
, staggered-mock
, timer
and simulate
behaviors have duration defaults set in the source. For example; the max duration is set at 4
. This is to keep the size down. But these can easily be altered by building your own version of ep
or adding rules for the durations you require. For example; I want the simulation to only take 10s
and a timer that will take 15s
.
progress[data-simulate] {
animation-duration: 10s;
animation-timing-function: steps(28);
}
progress[data-timer="15"] {
animation-duration: 15s;
}
ep
leverages the !default
flag in Sass so it's easier to override ep
configuration variables. Simply set any of the following variables before importing ep
.
$ep-ns: ep
- set the class helper prefix$ep-height: 6px
- set the height of<progress>
elements$ep-fg: #3498db
- set the primary color of<progress>
elements$ep-indeterminate-fg: $ep-fg
- set the primary color when in indeterminate state$ep-opacity: .6
- set the opacity of<progress>
elements$ep-transition: .25s
- set the duration for<progress>
elements to transition value$ep-timeout-threshold: 30
- the time it takes for simulation to complete in seconds$ep-simulate-max: 99
- at which value should simulation stop$ep-mocks-min: 1
- minimum mocking duration in seconds$ep-mocks-max: 4
- maximum mocking duration in seconds$ep-staggered-mocks-min: 1
- minimum staggered mock duration in seconds$ep-staggered-mocks-max: 4
- maximum staggered mock duration in seconds$ep-timers-min: 1
- minimum timer duration in seconds$ep-timers-max: 4
- maximum timer duration in seconds
$ep-fg: #e74c3c3;
$ep-opacity: .8;
// import with default variables override
@import '~ep/core';
ep
also has a mixin available for coloring progress
elements. Simply pass a color to color-bar
. You may use this without even importing the ep
reset if you just want to color some progress
elements.
@import '~ep/mixins';
.my-progress-element { @include color-bar(#7bff7b); }
ep
also provides an optional Javascript helper/api. This can be used for convenience and also gives a little more control and power when interacting with <progress>
elements. It doesn't create any extra elements, but you must pass a HTMLProgressElement
into the constructor.
const bar = document.querySelector('progress');
const myEp = new Ep(bar);
It's main purpose is that it saves you the burden of having to set/remove attributes/classes. But it also provides some nice to haves such as being able to hook into when progress is complete or set.
The source is quite heavily documented and written with babel
so be sure to check that out here.
As for the methods available(?
denotes an optional parameter);
set({number} val, ? {function} cb)
- Sets<progress>
value with optional callback.setSpread(? {bool} spread)
- Set whether<progress>
element should be spred style. By default will set to false.setIndeterminate(? {bool} indeterminate)
- Set whether<progress>
element is usingindeterminate
helper class. By default, will remove helper class.togglePause
- Toggles pause attribute for play/pause animation.setPosition(? {Array string} positions)
- Takes an optional array of positions that will be applied to the element. For example,['top', 'fixed']
will setep--top ep--fixed
class to the<progress>
element. If no positions are declared, all currently applied will be wiped.increase(? {number} value, ? {function} cb)
- Increase progress value by optional increment with an optional callback. By default, increment is 5.decrease(? {number} value, ? {function} cb)
- Decrease progress value by optional decrement with an optional callback. By default, decrement is 5.reset
- Resets<progress>
value to 0.mock(? {number} duration, ? {bool} staggered, ? {function} cb)
- Mocks progress with a mocking animation. Optional duration in seconds. Optional staggered attribute defines which mock style use. Optional callback can be invoked when mock is complete. By default, duration is 4.time(? {number} duration, ? {function} cb)
- Timing mock for using element as timer. Optional duration in seconds. Optional callback can be invoked when timer is complete. By default, duration is 4.simulate(? {number} step, ? {number} increment, ? {number} max)
- Simulation on the Javascript side is an example where we have more control than we do with CSS. Set a simulation by declaring a step duration inms
, anincrement
and amax
value for the simulation to reach. The default simulation will increment by 5 every second until the<progress>
element has a value of 99.complete(? {function} cb)
- Complete a progress bar by setting value to 100 and then resetting it. Provide optional callback for when complete.
Yep. You can easily integrate ep
to communicate network request status to the end user. The most basic example being something like the following;
const myEp = new Ep(document.querySelector('progress'));
const makeRequest = () => {
myEp.simulate();
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myEp.complete();
}
};
xhttp.open('GET', '/index.html', true);
xhttp.send();
}
(myEp._VALUE) ? myEp.set(0, makeRequest) : makeRequest();
We start with a simple progress
element. Reset it to make sure it starts at 0
and start a simulation. When we get the OK
from our network request, set our element to complete π
For some time, I'd intended to revisit progre(c)ss
with some ideas I had. When I finally got round to it, I went back over the issues and something struck me. Someone had pointed out why not use the <progress>
element?
I'd previously struck this off because I liked being able to add :pseudo
element progress bars to any element with relative ease where the :pseudo
elements were available.
However, using :pseudo
elements to display progress isn't ideal and not very semantic.
It makes more sense to create something that can be integrated without big changes.
progre(c)ss
is still available under the release tab if you really want it but realistically the code for progre(c)ss
is as simple as;
.progrecss {
&:before {
color: green;
content: '';
height: 6px;
left: 0;
opacity: .8;
position: absolute;
top: 0;
}
@for $percent from 1 through 100 {
&[data-progrecss-value='#{$percent}'] {
&:before {
width: $percent * 1%;
}
}
}
}
ep
is developed using webpack
, webpack-dev-server
, babel
and sass
.
It uses a self-documented Makefile
for development.
make
make setup
make develop
Don't hesitate to post and issue, PR or suggestion. Alternatively, get in touch via email or by tweeting me @_jh3y! π
MIT
Made real by @jh3y 2017 π