13
votes

Im trying to create spinners for Twitter Bootstrap buttons. Spinners should indicate some work in progress (ie. ajax request).

Here is small example: http://jsfiddle.net/AndrewDryga/zcX4h/1/

HTML (full on jsfiddle):

Unknown element (no animation here!):
<p>
  <button class="btn-success has-spinner">
    <span class="spinner"><i class="icon-spin icon-refresh"></i></span>
    Foo
  </button>
</p>

Works when width is defined:
<p>
  <a class="btn btn-success has-spinner">
    <span class="spinner"><i class="icon-spin icon-refresh"></i></span>
    Foo
  </a>
</p>

CSS:

.spinner {
  display: inline-block;
  opacity: 0;
  width: 0;

  -webkit-transition: opacity 0.25s, width 0.25s;
  -moz-transition: opacity 0.25s, width 0.25s;
  -o-transition: opacity 0.25s, width 0.25s;
  transition: opacity 0.25s, width 0.25s;
}

/* ... */

.has-spinner.active .spinner {
  opacity: 1;
  width: auto; /* This doesn't work, just fix for unkown width elements */
}

/* ... */

.has-spinner.btn.active .spinner {
    width: 16px;
}

.has-spinner.btn-large.active .spinner {
    width: 19px;
}

The deal is that css "margin: auto" doesn't produce expected animation and spinner widths for all elements should be defined via css. Is there are any way to solve this problem? Also, maybe there are better way to align/show spinners?

And should i play with buttons padding and make it in way, where button width doesn't change, when spinner is shown or buttons that change width is ok? (If ill put it as snippet somewhere)

4
They are not duplicated questions but they are related to your question: stackoverflow.com/q/3508605/1004046 and stackoverflow.com/q/3149419/1004046Pigueiras
I've already tyed to play with max-width and :not(.active) selector, it seems that you need to set width explicity for all elements... Ill try to play with absolute positioning tommorow.Andrew Dryga
Wow that is a nice looking spinner! You should try to get this into Bootstrap proper!Jon Tirsen

4 Answers

35
votes

I was able to fix this problem by using max-width istead of width. Also this is pure CSS solution, so it can be used pretty much everywhere (for example show X mark on tags, when user hover mouse over it, etc).

Demo: http://jsfiddle.net/AndrewDryga/GY6LC/

New CSS:

.spinner {
  display: inline-block;
  opacity: 0;
  max-width: 0;

  -webkit-transition: opacity 0.25s, max-width 0.45s; 
  -moz-transition: opacity 0.25s, max-width 0.45s;
  -o-transition: opacity 0.25s, max-width 0.45s;
  transition: opacity 0.25s, max-width 0.45s; /* Duration fixed since we animate additional hidden width */
}

/* ... */

.has-spinner.active .spinner {
  opacity: 1;
  max-width: 50px; /* More than it will ever come, notice that this affects on animation duration */
}
4
votes

I have updated @andrew-dryga solution to use the currently latest Bootstrap (3.3.5), font-awesome (4.3.0), jQuery (2.1.3) and slightly modified it.

Here it is:

 <button class="btn btn-success has-spinner">
    <i class="fa fa-spinner fa-spin"></i>
    Foo
 </button>

 $('a.has-spinner, button.has-spinner').click(function() {
     $(this).toggleClass('active');
 });

In addition, you need appropriate CSS modifications (JSFiddle).

0
votes

I found your code to be super helpful. I know it's been a year but I've improved upon the code. I didn't like having to manually add the span and i tags to each element. I tweaked the JavaScript code to add these tags automatically. So all you have to do to add a spinner to a button/link is add the has-spinner class to it and give it a data-spinner="[left|right]" tag (determines which side of your button text the spinner should be placed).

Here's the modified JavaScript:

$(function(){

var spinnerHTML = "<span class='spinner'><i class='fa fa-refresh fa-spin'></i></span>",
    spinnerObjects = $(".has-spinner");

spinnerObjects.filter("[data-spinner=left]").prepend(spinnerHTML + "&nbsp;")
spinnerObjects.filter("[data-spinner=right]").append("&nbsp;" + spinnerHTML)
spinnerObjects.click(function() {
    $(this).toggleClass('active');
});

});

Here's the link to the fiddle with all the changes (CSS,HTML):

http://jsfiddle.net/codyschouten/QKefn/2/

0
votes

Very simple solution worked for me was changing the element from

<i></i>  
with
<em></em>

This was the only change I did.