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.

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:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

👾 Hey! Looking for the latest in frontend? Twice a week, we'll deliver the freshest frontend news, website inspo, cool code demos, videos and UI animations right to your inbox.

Zero fluff, all quality, to make your Mondays and Thursdays more creative!

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!) 🙂

  8. If you’re using jQuery to generate it dynamically prepare for it not to work, it automatically removes the span tags inside the button because it doesnt meet the HTML spec.

  9. They js that is used causes an issue that doesn’t allow to submit on Chrome. Only browser, I’ve been having issues with.

  10. You make web a better place. I’m stunned every time I see something from you, and I’ve learnt so much, Thank you!

  11. Awesome work, thanks a lot!

    Same as Danilo Vaz i would like to know, how to integrate this with AJAX. Have I change transition-duration or … ?

  12. Hi !
    I try to use your submit on my form but i’ve a problem 🙁
    I use required on my fields, i try to do not activate the effect of submit if required appears. is it possible to do it ?

  13. Olá, sou novo aqui no site e já estou gostando de mais.
    Tô com uma dúvida: Como é que eu faço redirecionar para outra página após o término do progresso?
    Quero que quando eu clicar no botão, o progresso acabe e eu seja redirecionado.

    Atenciosamente, Vitor.

  14. Hello, I’m new here on the site and I’m enjoying it more.
    ‘m With a doubt: How do I redirect to another page after the progress?
    I want that when I Vclick the button, the progress finish and I will be redirected.
    Regards, Vitor.

  15. Good day, I want to ask how can I use this in form as a submit? I’ve tried to remake it but it didn’t work. Thank you

  16. CHALLENGE,Is there any way to use this these perfect buttons as an upload button where the progress bar does show the condition of the uploading file(how far the uploading goes)

  17. Hi there,

    Has anyone been able to include form validation? It doesn’t seem to work, as it’s a button tag rather than an input submit. Other than that, it works beautifully. 🙂

  18. Has anyone had any luck getting this plugin to work with Contact Form 7?

    When I set it up, the button animates, but the form no longer submits.