How to write CSS keyframes to indeterminate material design progress bar
I found a good example by Stefano on CodePen:
// Android Material Loading animation with pure css.
// Author: Stefano Ferrara http://androidpc.it/
// Forked from https://codepen.io/chofoo/pen/Abril
// Author: Simon Clavey https://simonclavey.co.uk/body{
background:#ffffff;
margin:50px 300px;
}
.slider{
position:absolute;
width:1000px;
height:5px;
overflow-x: hidden;
}
.line{
position:absolute;
opacity: 0.4;
background:#4a8df8;
width:150%;
height:5px;
}
.subline{
position:absolute;
background:#4a8df8;
height:5px;
}
.inc{
animation: increase 2s infinite;
}
.dec{
animation: decrease 2s 0.5s infinite;
}
@keyframes increase {
from { left: -5%; width: 5%; }
to { left: 130%; width: 100%;}
}
@keyframes decrease {
from { left: -80%; width: 80%; }
to { left: 110%; width: 10%;}
}<div class="slider">
<div class="line"></div>
<div class="subline inc"></div>
<div class="subline dec"></div>
</div>Indeterminate progress bar in HTML+CSS
NO, NO, NO! It is possible
Using CSS
overflow: hidden
andkeyframe
, it can be possible.For the keyframe, I used from
left:-120px
(width of the glowing object) toleft:100%
The structure I used:<div class="loader">
<div class="loader-bg left"></div>
<div class="loader-bg right"></div>
<div class="greenlight"></div>
<div class="gloss"></div>
<div class="glow"></div>
</div>The updated, compact structure using
:before
and:after
:<div class="loader7">
<span></span>
<div class="greenlight"></div>
</div>The gradient, masking, glowing and all the effects cost an expensive structure. If anyone has a better idea, please let me know.
At this date, webkit only solution(the ellipse mask for the glow):Added SVG mask for Firefox and other browsers that do not support
-webkit-mask-image
: http://jsfiddle.net/danvim/8M24k/Is it possible to render indeterminate progress bar with Twitter Bootstrap?
In bootstrap 2:
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet" />
<div class="progress progress-striped active">
<div class="bar" style="width: 100%;"></div>
</div>Sophisticated proportional triple element progress bar design using only CSS
You can do like below. I am using different colorations to better see the result
body {
margin: 100px;
background: #CCC
}
.fullbar {
background-color: blue;
}
.progress {
background: lightgreen;
margin: 10px 0 0 0;
height: 5px;
position:relative; /* relative here */
width:var(--p);
}
.number {
position:absolute; /* absolute here */
background: rgba(255,0,0,0.5);
left:100%; /* push to the right side */
transform:translateX(calc(-1*var(--p))); /* offset to the left based on --p */
top:-10px;
bottom:-10px;
color: #FFF;
padding: 0 2px 1px 3px;
}<div class="fullbar">
<div class="progress" style="--p:0%">
<div class="number">0%</div>
</div>
</div>
<div class="fullbar">
<div class="progress" style="--p:20%">
<div class="number">20%</div>
</div>
</div>
<div class="fullbar">
<div class="progress" style="--p:50%">
<div class="number">50%</div>
</div>
</div>
<div class="fullbar">
<div class="progress" style="--p:80%">
<div class="number">80%</div>
</div>
</div>
<div class="fullbar">
<div class="progress" style="--p:100%">
<div class="number">100%</div>
</div>
</div>Material-UI Progress hickups - css animation stops running
Animations that require a document reflow (changing margin, padding, positioning), tend to freeze when heavy calculation is going on.
The material progress bars make use of these properties to achieve their animations.
They've described this on their limitations section.There are 3 workarounds:
- Animations that use
transform
functions aren't affected by heavy calculations- Move the Heavy calculation of the render thread, using a web worker.
- Batch the calculation using setTimeouts, so the render thread has time to animate.
Material's
circularProgress
has an animation usingtransform
. you could try to use that like :<CircProgress disableShrink={true} />
or try moving the heavy calculations to a webworker.
You should decide for yourself if that's feasable.This is an example using both methods
It's using 'react-webworker-hook' package to make the webworker is bit more accessible.import React, { useState } from "react";
import LinProgress from "@material-ui/core/LinearProgress";
import CircProgress from "@material-ui/core/CircularProgress";
import { useWebWorkerFromScript } from "react-webworker-hook";
const slowFunc = () => {
var start = +new Date();
while (+new Date() - start < 2000) {}
return Math.random();
};
const MyComponent = (props) => {
const [inThreadData, setInThreadData] = useState(0);
//startHeavyRender: will block the render thread, animations will pause
const startHeavyRender = React.useMemo(
() => () => setInThreadData(slowFunc),
[]
);
//postData: will do the same calculation using a webworker, animations will continue
const [workerData = 0, postData] = useWebWorkerFromScript(`
const slowFunc = () => {
var start = +new Date();
while (+new Date() - start < 2000) {}
return Math.random();
};
onmessage = ({ data }) => {
postMessage(slowFunc());
};
`);
const startWorkerRender = React.useMemo(() => () => postData(), [postData]);
return (
<div>
<LinProgress />
<br />
<CircProgress />
<br />
<CircProgress disableShrink={true} />
<br />
<button onClick={startHeavyRender}>
start heavy render. {inThreadData}
</button>
<br />
<button onClick={startWorkerRender}>
start heavy webworker. {workerData}
</button>
</div>
);
};
export default MyComponent;Custom color for a indeterminate progress-tag without a value
Seems like a bug to me...
When you try to apply some styles on it, Chrome seems to define the progress bar like defined, whenever it exists avalue
inside your tag or not.
I tried with Chrome Canary too, but same thing append.It could be a good idea to think, "go to hell you moving item, I will erase you with my own style". But apparently,
Animations don't seem to work anymore on the pseudo elements within a progress element, in Blink. At the time this was published, they did. Brian LePore reported this to me and pointed me toward this thread discussing it and created a reduced test case.
-
Maybe it's the same with the that @keyframes defined outside of the Shadow DOM can't get accessed by an element inside. From the timing it might have changed in Chromium 39/40?
https://css-tricks.com/html5-progress-element/#article-header-id-5
So I tried but yes, animations does not work anymore...
*,*:before,*:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;}
html { font-family: Helvetica, Arial, sans-serif; font-size: 100%; background: #333;}
#page-wrapper { width: 640px; background: #FFFFFF; padding: 1em; margin: 1em auto; border-top: 5px solid #69c773; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.8);}
h1 { margin-top: 0;}
progress { width: 100%;}
.styled progress { /* Reset the default appearance */ -webkit-appearance: none; -moz-appearance: none; appearance: none; width: 100%; height: 15px; /* Firefox */ border: none; background: #EEE; border-radius: 3px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2) inset;}
/* lest apply somes styles on it */.styled progress:not([value])::-webkit-progress-bar { background: blue; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2) inset; border-radius: 3px; background-image: -webkit-linear-gradient(-45deg, transparent 33%, rgba(0, 0, 0, .1) 33%, rgba(0,0, 0, .1) 66%, transparent 66%), -webkit-linear-gradient(top, rgba(255, 255, 255, .25), rgba(0, 0, 0, .25)), -webkit-linear-gradient(left, #09c, #f44); -webkit-animation: animate-stripes 5s linear infinite; animation: animate-stripes 5s linear infinite;}
/* this seems to does not work anymore */@-webkit-keyframes animate-stripes { 100% { background-position: -100px 0px; }}@keyframes animate-stripes { 100% { background-position: -100px 0px; }}
.styled progress::-webkit-progress-value { background-color: blue; border-radius: 3px;}
.styled progress::-moz-progress-bar { background-color: blue; border-radius: 3px;}<div id="page-wrapper"> <p>Default</p> <p> <progress max="100"></progress> </p>
<p>Styled defined</p> it does not move: <p class="styled"> <progress max="100" value="50"></progress> </p> <p>Styled defined</p> this should move: <p class="styled"> <progress max="100"></progress> </p>How can I smoothly animate a Material UI LinearProgress over a fixed time period?
The example below uses CSS rather than JS to animate the progress bar over 60 seconds. It accomplishes this by using the
indeterminate
variant, but then customizing its CSS. Theindeterminate
variant leverages two bars in its animation. This example suppresses the second bar and changes the first bar to animate over 60 seconds once instead of 2.1 seconds infinitely repeating. This example also changes the keyframes part of the animation so that it ends with a full bar, rather than ending with the bar disappearing. Usingforwards
in the animation causes the final state to stick when the animation finishes.import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import LinearProgress from "@material-ui/core/LinearProgress";
const useStyles = makeStyles({
root: {
width: "100%"
},
bar1Indeterminate: {
width: "auto",
animation: "$indeterminate1 60s linear forwards"
},
bar2Indeterminate: {
display: "none"
},
"@keyframes indeterminate1": {
"0%": {
left: "-35%",
right: "100%"
},
"100%": {
left: "0%",
right: "0%"
}
}
});
export default function LinearDeterminate() {
const classes = useStyles();
return (
<div className={classes.root}>
<LinearProgress
classes={{
bar1Indeterminate: classes.bar1Indeterminate,
bar2Indeterminate: classes.bar2Indeterminate
}}
variant="indeterminate"
/>
</div>
);
}Relevant documentation:
- https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode
- https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes
Here's an equivalent example using v5 of Material-UI leveraging
styled
and Emotion'skeyframes
:import React from "react";
import { styled } from "@material-ui/core/styles";
import LinearProgress from "@material-ui/core/LinearProgress";
import { keyframes } from "@emotion/react";
const indeterminate1Keyframes = keyframes({
"0%": {
left: "-35%",
right: "100%"
},
"100%": {
left: "0%",
right: "0%"
}
});
const StyledLinearProgress = styled(LinearProgress)({
"& .MuiLinearProgress-bar1Indeterminate": {
width: "auto",
animation: `${indeterminate1Keyframes} 60s linear forwards`
},
"& .MuiLinearProgress-bar2Indeterminate": {
display: "none"
}
});
export default function LinearDeterminate() {
return (
<div style={{ width: "100%" }}>
<StyledLinearProgress variant="indeterminate" />
</div>
);
}
Related Topics
Twitter-Bootstrap-Rails on Heroku: Glyphicons Displayed as Squares
Can Visual Studio 2013 Generate CSS Files from .Less Files
Calculating Square-Roots with CSS
How to Make a Bullet List Align with Text in CSS
Svg/CSS Stroke Dashed Line with Two Colors - Is It Possible
Gulp SASS - How to Properly Name The Output CSS
Lesscss Method with Ie Filter Alpha Opacity CSS
Rotating Glyphicons/Font Awesome in Bootstrap
Bootstrap Container-Fluid - Remove Margins The Right Way (Overflow)
Using CSS Variables as SASS Function Arguments
Change Font Sizes with Style Sheets for Rstudio Presentation
Fontawesome Instagram Icon - Colorized
Iframe Border Showing in Webview React Native
Update Source File When CSS Is Changed Through Chrome Developer Tools
Susy: How to Extend Content Box to Cover Grid-Padding as Well