Progress Button Styles

A set of flat and 3D progress button styles where the button itself serves as a progress indicator. 3D styles are used for showing the progress indication on one side of the button while rotating the button in perspective.

From our sponsor: Ship fast and never break a thing with Shortcut (formerly

Today we’d like to share some progress button styles with you. You surely know “Ladda” by Hakim El Hattab, a UI concept that indicates progress directly on the button that invokes a loading action. Some of the buttons have a built-in progress bar and today we’d like to explore that idea with some creative progress button styles. Using perspective will allow us to create some fun 3D effects besides the flat “filling” styles. For a complete solution, please take a better look at Ladda.

Please note that we’ll be using transitions on pseudo-elements which are still not supported in some browsers (e.g. Safari and Mobile Safari).

Also note that we need transform-style: preserve-3d support for the 3D styles, which neither IE10 nor IE11 support.

With the script that we’ve created for showing the button styles, we take a simple button markup

<button class="progress-button" data-style="rotate-angle-bottom" data-perspective data-horizontal>Submit</button>

and transform it into the following structure:

<button class="progress-button" data-style="rotate-angle-bottom" data-perspective data-horizontal>
	<span class="progress-wrap">
		<span class="content">Submit</span>
		<span class="progress">
			<span class="progress-inner"></span>

If we don’t set the data-perspective attribute, then we’ll make this structure:

<button class="progress-button" data-style="fill" data-horizontal>
	<span class="content">Submit</span>
	<span class="progress">
		<span class="progress-inner"></span>

We also indicate if we have a style that needs horizontal or vertical progress bar filling. This will be used in our CSS to specify the regarding styles.
The following styles are the general and common styles for all buttons (note that perspective styles are only needed for the buttons with 3D transforms):

*, *:after, *::before { box-sizing: border-box; }

@font-face {
	font-weight: normal;
	font-style: normal;
	font-family: 'icomoon';
	src:url('../fonts/icomoon/icomoon.eot?#iefix') format('embedded-opentype'),
		url('../fonts/icomoon/icomoon.ttf') format('truetype'),
		url('../fonts/icomoon/icomoon.woff') format('woff'),
		url('../fonts/icomoon/icomoon.svg#icomoon') format('svg');

.progress-button {
	position: relative;
	display: inline-block;
	padding: 0 60px;
	outline: none;
	border: none;
	background: #1d9650;
	color: #fff;
	text-transform: uppercase;
	letter-spacing: 1px;
	font-size: 1em;
	line-height: 4;

.progress-button[disabled].state-loading {
	cursor: default;

.progress-button .content {
	position: relative;
	display: block;

.progress-button .content::before,
.progress-button .content::after  {
	position: absolute;
	right: 20px;
	color: #0e7138;
	font-family: "icomoon";
	opacity: 0;
	transition: opacity 0.3s 0.3s;

.progress-button .content::before {
	content: "e600"; /* Checkmark for success */

.progress-button .content::after {
	content: "e601"; /* Cross for error */

.progress-button.state-success .content::before,
.progress-button.state-error .content::after {
	opacity: 1;

.notransition {
	transition: none !important;

.progress-button .progress {
	background: #148544;

.progress-button .progress-inner {
	position: absolute;
	left: 0;
	background: #0e7138;

.progress-button[data-horizontal] .progress-inner {
	top: 0;
	width: 0;
	height: 100%;
	transition: width 0.3s, opacity 0.3s;

.progress-button[data-vertical] .progress-inner {
	bottom: 0;
	width: 100%;
	height: 0;
	transition: height 0.3s, opacity 0.3s;

/* Necessary styles for buttons with 3D transforms */

.progress-button[data-perspective] {
	position: relative;
	display: inline-block;
	padding: 0;
	background: transparent;
	perspective: 900px;

.progress-button[data-perspective] .content {
	padding: 0 60px;
	background: #1d9650;

.progress-button[data-perspective] .progress-wrap {
	display: block;
	transition: transform 0.2s;
	transform-style: preserve-3d;

.progress-button[data-perspective] .content,
.progress-button[data-perspective] .progress {
	outline: 1px solid rgba(0,0,0,0); /* Smoothen jagged edges in FF */

We are using the pseudo-elements ::before and ::after for the success or error icons which we fade in once loading is finished. The span with the class progress is used as the main wrapper for the progress bar itself which is the span with class progress-inner. Sometimes we use the progress span with a background color, while other times we will just style the child span. We’ll also provide some general styles for the vertical and horizontal case.

Note that for the 3D examples, we’ll use the button as a “shell” that will serve to add the perspective value. The content span will contain the button styles like the background color and the padding, and everything will be wrapped into a span with the class progress-wrap which will be the element that we transform.

An example of an individual button style is the following:

/* Rotate bottom 3d */
/* ====================== */

.progress-button[data-style="rotate-angle-bottom"] .progress {
	position: absolute;
	top: 100%;
	left: 0;
	width: 100%;
	height: 20px;
	box-shadow: 0 -1px 0 #148544; /* fix the blurriness that causes a gap */
	transform: rotateX(-90deg);
	transform-origin: 50% 0%;

.progress-button[data-style="rotate-angle-bottom"].state-loading .progress-wrap {
	transform: rotateX(45deg);

The button will have one of the three states (or none): state-loading, state-success and state-error.

For browsers that don’t support necessary properties, we’ll provide the default fallback of the first style (fill horizontal).

Icons are by IcoMoon and the icon font was created with the IcoMoon app.

We hope that you find these button styles inspiring and useful!

Tagged with:

Mary Lou

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 52

Comments are closed.
  1. Very cool! I don’t usually comment, but have been following your blog for years, and always excited to see what you will come up with next, great stuff!

  2. Thanks, Mary. How it will works with real loading? Should I manual set length of an element (for uploading on server for example)?

  3. Great article!! but how do i go about this adding this to a simple ajax contact form? or is it only for file uploading?

  4. Awesome demo, thanks! One question though, which is the best way to control the loading progress, for example, using Ajax to load an image. Which would be the best way to link JavaScript in with this?

  5. Awesome buttons.!! will be feature in my future projects. Thanks a ton for sharing with us.

  6. SO SWEET!
    Looks really, really nice.
    I would love a tutorial on how to utilize these loading buttons in a form, to make them work properly! 🙂

  7. Please note that we’ll be using transitions on pseudo-elements which are still not supported in some browsers (e.g. Safari and Mobile Safari).

    Transitions on pseudo-elements work in Safari 7.0 and Mobile Safari in iOS 7 (finally!) 🙂