CSS Loading Spinners

CSS Loading Spinners

We all know that CSS3 brings a lot of features which allows you to do a lot of cool stuff that we used to need Javascript for. One of the features that we're going to look at today is creating loading spinners with just CSS and show the variety of spinners we can create.
In the past we had to create the spinners with Javascript to do the animation for you, but now with CSS we can do this without the need of any Javascript.
In this tutorial we're going to create 8 different loading spinners using just CSS. View the demo to see these spinners in action.

Loading Bars

The loading bars spinner is probably the most common loading spinner you will see, it is made up of 8 lines which spin together in a circle, each of the lines will have different opacity. The spinning effect will come from changing the opacity of each of the loading bars, making it look like the entire thing is spinning.
loading-bars

The HTML

First we start off by creating the HTML for the spinner, all you have to do create a parent element with 8 child elements.

The CSS

The CSS starts out by creating the look of the spinner, this means we need to style the parent item to have enough space for all the child bars. Each of the child elements will be styled as bars but with different opacity, we do this by using the nth-child to pick which element to style.
We start off by styling the parent element which we will make a box 100 pixels by 100 pixels.
.loading{
 width:100px;
 height:100px;
 margin:30px auto;
 position:relative;
}
Next we will style each of the bars, for these we are simply creating lines of width 10px and height of 30px, then we will set a background colour of black. This is where we will set the CSS animation of fadeit to all bars, this animation will simply change the opacity from full to blank.
.loading.bar div{
 width: 10px;
 height: 30px;
 background: black;
 position: absolute;
 top: 35px;
 left: 45px;
 opacity:0.05;

 -webkit-animation: fadeit 1.1s linear infinite;
 animation: fadeit 1.1s linear infinite;
}
Once the bars have been styled we can now place these in a circle by using transform rotate and the translate functions. This is done by using the nth-child to pick each bar and position them separately.
.loading.bar div:nth-child(1){
 -webkit-transform: rotate(0deg) translate(0, -30px);
 transform: rotate(0deg) translate(0, -30px);

 -webkit-animation-delay:0.39s;
 animation-delay:0.39s;
}
.loading.bar div:nth-child(2){
 -webkit-transform: rotate(45deg) translate(0, -30px);
 transform: rotate(45deg) translate(0, -30px);

 -webkit-animation-delay:0.52s;
 animation-delay:0.52s;
}
.loading.bar div:nth-child(3){
 -webkit-transform: rotate(90deg) translate(0, -30px);
 transform: rotate(90deg) translate(0, -30px);

 -webkit-animation-delay:0.65s;
 animation-delay:0.65s;
}
.loading.bar div:nth-child(4){
 -webkit-transform: rotate(135deg) translate(0, -30px);
 transform: rotate(135deg) translate(0, -30px);

 -webkit-animation-delay:0.78s;
 animation-delay:0.78s;
}
.loading.bar div:nth-child(5){
 -webkit-transform: rotate(180deg) translate(0, -30px);
 transform: rotate(180deg) translate(0, -30px);

 -webkit-animation-delay:0.91s;
 animation-delay:0.91s;
}
.loading.bar div:nth-child(6){
 -webkit-transform: rotate(225deg) translate(0, -30px);
 transform: rotate(225deg) translate(0, -30px);

 -webkit-animation-delay:1.04s;
 animation-delay:1.04s;
}
.loading.bar div:nth-child(7){
 -webkit-transform: rotate(270deg) translate(0, -30px);
 transform: rotate(270deg) translate(0, -30px);

 -webkit-animation-delay:1.17s;
 animation-delay:1.17s;
}
.loading.bar div:nth-child(8){
 -webkit-transform: rotate(315deg) translate(0, -30px);
 transform: rotate(315deg) translate(0, -30px);

 -webkit-animation-delay:1.3s;
 animation-delay:1.3s;
}
The animation for these bars is named fadeit, which simply changes the opacity from full to blank.
@-webkit-keyframes fadeit{
 0%{ opacity:1; }
 100%{ opacity:0;}
}
@keyframes fadeit{
 0%{ opacity:1; }
 100%{ opacity:0;}
}

Bar Spinner

The bar spinner is similar to the loading bar spinner, but the difference is that instead of changing the opacity of each of the bars we are going to spin the entire parent element so we can see the difference between the first two spinners.
bar-spinner

The HTML

The HTML for the bar spinner is exactly the same as the first spinner we have a parent element with 8 child elements.

The CSS

The styling of these bars are going to be exactly the same as the first spinner, the only difference between them is that the animation will rotate the entire spinner and will not change the individual bars opacity.
Again we start off by styling the outer parent element, by creating a square box of 100px width and 100px height.
.spinner{
 width:100px;
 height:100px;
 margin:30px auto;
 position:relative;
   -webkit-animation: rotateit 1.3s linear infinite;
   animation: rotateit 1.3s linear infinite;
}
Notice the animation of this element is set to rotateit this animation will be used to rotate the element 360 degrees, because this is set to infinite the spinner will continue to rotate.
@-webkit-keyframes rotateit {
  from { -webkit-transform: rotate(360deg); }
  to { -webkit-transform: rotate(0deg); }
}
@keyframes rotateit {
  from { transform: rotate(360deg); }
  to { transform: rotate(0deg); }
}
This will make sure that the parent element will rotate 360 degrees, now we can just style the bars inside the parent element. This will be exactly the same as the first example, except we don't need to add the animation delay.
.spinner.bar div{
 width: 10px;
 height: 30px;
 background: black;
 position: absolute;
 top: 35px;
 left: 45px;
}
.spinner.bar div:nth-child(1){
 -webkit-transform: rotate(0deg) translate(0, -30px);
 transform: rotate(0deg) translate(0, -30px);
}
.spinner.bar div:nth-child(2){
 -webkit-transform: rotate(45deg) translate(0, -30px);
 transform: rotate(45deg) translate(0, -30px);
 opacity:0.7;
}
.spinner.bar div:nth-child(3){
 -webkit-transform: rotate(90deg) translate(0, -30px);
 transform: rotate(90deg) translate(0, -30px);
 opacity:0.6;
}
.spinner.bar div:nth-child(4){
 -webkit-transform: rotate(135deg) translate(0, -30px);
 transform: rotate(135deg) translate(0, -30px);
 opacity:0.5;
}
.spinner.bar div:nth-child(5){
 -webkit-transform: rotate(180deg) translate(0, -30px);
 transform: rotate(180deg) translate(0, -30px);
 opacity:0.4;
}
.spinner.bar div:nth-child(6){
 -webkit-transform: rotate(225deg) translate(0, -30px);
 transform: rotate(225deg) translate(0, -30px);
 opacity:0.3;
}
.spinner.bar div:nth-child(7){
 -webkit-transform: rotate(270deg) translate(0, -30px);
 transform: rotate(270deg) translate(0, -30px);
 opacity:0.2;
}
.spinner.bar div:nth-child(8){
 -webkit-transform: rotate(315deg) translate(0, -30px);
 transform: rotate(315deg) translate(0, -30px);
 opacity:0.1;
}

Circle Spinner

The circle spinner is a spinner that is similar to the bar spinner except we are using circles instead of bars, this is easily done with CSS by using the border-radius property and applying a value of 50% to make the elements rounded.
circle-spinner

The HTML

The circle spinner HTML is exactly the same as the first 2 examples, it has a parent element with 8 child elements inside it. All the work for customising the spinner is done with CSS.

The CSS

The parent element of the circle spinner will be styled the same as the bar spinner, it is a 100 x 100 pixel box which has a animation of rotate will spin the parent element 360 degrees.
.spinner{
 width:100px;
 height:100px;
 margin:30px auto;
 position:relative;
   -webkit-animation: rotateit 1.3s linear infinite;
   animation: rotateit 1.3s linear infinite;
}
@-webkit-keyframes rotateit {
  from { -webkit-transform: rotate(360deg); }
  to { -webkit-transform: rotate(0deg); }
}
@keyframes rotateit {
  from { transform: rotate(360deg); }
  to { transform: rotate(0deg); }
}
The difference between the bar spinner and the circle spinner is the way we style the child elements with the circles being all the same sizes.
.spinner.circles div{
 width: 20px;
 height: 20px;
 border-radius:50%;
 background: black;
 position: absolute;
 top: 35px;
 left: 45px;
}
The next styles for the circles are going to be exactly the same as the bar spinners except for one difference, the scale of the circle. Using the transform scale property we can change the size of the circles to make them smaller around the spinner.
.spinner.circles div:nth-child(1){
 -webkit-transform: rotate(0deg) translate(0, -35px) scale(1.4);
 transform: rotate(0deg) translate(0, -35px) scale(1.4);
}
.spinner.circles div:nth-child(2){
 -webkit-transform: rotate(45deg) translate(0, -35px) scale(1.2);
 transform: rotate(45deg) translate(0, -35px) scale(1.2);
 opacity:0.7;
}
.spinner.circles div:nth-child(3){
 -webkit-transform: rotate(90deg) translate(0, -35px) scale(1.1);
 transform: rotate(90deg) translate(0, -35px) scale(1.1);
 opacity:0.6;
}
.spinner.circles div:nth-child(4){
 -webkit-transform: rotate(135deg) translate(0, -35px) scale(0.9);
 transform: rotate(135deg) translate(0, -35px) scale(0.9);
 opacity:0.5;
}
.spinner.circles div:nth-child(5){
 -webkit-transform: rotate(180deg) translate(0, -35px) scale(0.7);
 transform: rotate(180deg) translate(0, -35px) scale(0.7);
 opacity:0.4;
}
.spinner.circles div:nth-child(6){
 -webkit-transform: rotate(225deg) translate(0, -35px) scale(0.5);
 transform: rotate(225deg) translate(0, -35px) scale(0.5);
 opacity:0.3;
}
.spinner.circles div:nth-child(7){
 -webkit-transform: rotate(270deg) translate(0, -35px) scale(0.3);
 transform: rotate(270deg) translate(0, -35px) scale(0.3);
 opacity:0.2;
}
.spinner.circles div:nth-child(8){
 -webkit-transform: rotate(315deg) translate(0, -35px) scale(0.1);
 transform: rotate(315deg) translate(0, -35px) scale(0.1);
 opacity:0.1;
}

Facebook Loader

If your a user of Facebook then you most likely have seen the Facebook loader, which is made up of 3 bars which grow from left to right.
facebook-loader

The HTML

The HTML for the Facebook loader is very simple it has a parent element with 3 elements inside. The child elements will be used as the 3 bars that will grow as part of the animation.

The CSS

For the CSS we are going to simply style each of the bars exactly the same, as 3 blue bars.
On each of the bars we are going to add the CSS animation, all the animation will do is scale the element and change the opacity of bar. This will fade out the bars and grow them at the sametime.
.facebook div{
 height:50px;
 width:20px;
 display:inline-block;
 background-color: #56bbdb;
 border:1px solid #217c99;

 -webkit-animation:facebook_loader 1.3s linear infinite;
 animation:facebook_loader 1.3s linear infinite;

 -webkit-transform: scale(0.91);
 transform: scale(0.91);
}
For each of the bars we are going to change the animation delay to make the animation run at different times, this makes the bars load in a wave.
.facebook div:nth-child(1){
 -webkit-animation-delay:0.39s;
 animation-delay:0.39s;
}
.facebook div:nth-child(2){
 -webkit-animation-delay:0.52s;
 animation-delay:0.52s;
}
.facebook div:nth-child(3){
 -webkit-animation-delay:0.65s;
 animation-delay:0.65s;
}
Next we can create the CSS animation, all we are doing is changing the scale and the opacity of the element.
@-webkit-keyframes facebook_loader{
 0%{
  -webkit-transform:scale(1.2);
  opacity:1
 }

 100%{
  -webkit-transform:scale(0.7);
  opacity:0.1
 }
}

@keyframes facebook_loader{
 0%{
  transform:scale(1.2);
  opacity:1
 }

 100%{
  transform:scale(0.7);
  opacity:0.1
 }
}

SpinKit

The following spinners can be found on the github project SpinKit.

Spinning Square

The spinning square animation will simply take a square and rotate it vertically and then horizontally.
square-spinner

The HTML

As this is just one element the HTML is going to be just one div.

The CSS

First the CSS is used to style the square then we can add the animation to spin the square.
The square is simply going to be a black square of 60 x 60 pixels, then add the CSS animation of rotatesquare.
.spinning-square {
    width: 60px;
    height: 60px;
    background-color: #333;

    margin: 0 auto;
    -webkit-animation: rotatesquare 1.2s infinite ease-in-out;
    animation: rotatesquare 1.2s infinite ease-in-out;
}
The CSS animation rotatesquare will take the CSS perspective function to change the position of the element from the z-index, this will allow us to rotate the element on the Y-axis to flip it vertically. Then we can use the rotateX function to rotate the element on the X-axis.
@-webkit-keyframes rotatesquare {
    0% { -webkit-transform: perspective(120px) }
    50% { -webkit-transform: perspective(120px) rotateY(180deg) }
    100% { -webkit-transform: perspective(120px) rotateY(180deg)  rotateX(180deg) }
}

@keyframes rotatesquare {
  0% { transform: perspective(120px) rotateX(0deg) rotateY(0deg); } 
  50% { transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); } 
  100% { transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); }
}

Spinner Bounce Circle

The spinner bounce circle will take 2 circles and bounce them inside each other.
circle-spinner2

The HTML

The HTML for this spinner is a parent element with 2 child elements inside, these child elements will be used for the bouncing circles.

The CSS

The parent element will be styled as an area to add the circles in, we just need to add a width and height to the area.
.spinner-bounce-circle
{
    width: 60px;
    height: 60px;

    position: relative;
    margin: 0 auto;
}
Then we can style each of the circles, this will mean adding a size of 100% to the element, adding a border-raduis of 50% will make the element rounded. Then we can add a background colour to the circle with an opacity of 0.6.
Here is where we add the CSS animation of circlebounce which is used to change the scale of the element from nothing to full. As the scale of the element will need to happen at different times we are going to add an animation-delay to the first element.
.spinner-bounce-circle div
{
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: #333;
    opacity: 0.6;
    position: absolute;
    top: 0;
    left: 0;

    -webkit-animation: circlebounce 2.0s infinite ease-in-out;
    animation: circlebounce 2.0s infinite ease-in-out;
}

.spinner-bounce-circle div:nth-child(1) {
    -webkit-animation-delay: -1.0s;
    animation-delay: -1.0s;
}
The CSS circlebounce animation will simply change the scale of the element from nothing to full sized.
@-webkit-keyframes circlebounce {
    0%, 100% { -webkit-transform: scale(0.0) }
    50% { -webkit-transform: scale(1.0) }
}

@keyframes circlebounce {
    0%, 100% { transform: scale(0.0); }
    50% { transform: scale(1.0); }
}

Wave Loader

The wave loader is similar to the facebook loader as it will take a number of bars and change the scale of the elements in a row to make a wave effect.
wave-spinner

The HTML

The HTML is made up of one parent element with five child elements inside it, the child elements are going to be used as the bars for the wave.

The CSS

The CSS of the wave will start by setting up a box area of the bars to be included, this is simply a 100 x 100 box.
.spinner-wave {
    margin: 0 auto;
    width: 100px;
    height: 50px;
    text-align: center;
}
Next we can style the child elements, these will be 5 bars with a black background and a wave animation added to all the elements. As we need these elements to run at different times then we can set the delay of the elements to be different times. We do this by using the nth-child selector with the animation-delay to pick different delays for each element.
.spinner-wave > div {
    background-color: #333;
    height: 100%;
    width: 6px;
    display: inline-block;

    -webkit-animation: wave 1.2s infinite ease-in-out;
    animation: wave 1.2s infinite ease-in-out;
}

.spinner-wave div:nth-child(2) {
    -webkit-animation-delay: -1.1s;
    animation-delay: -1.1s;
}

.spinner-wave div:nth-child(3) {
    -webkit-animation-delay: -1.0s;
    animation-delay: -1.0s;
}

.spinner-wave div:nth-child(4) {
    -webkit-animation-delay: -0.9s;
    animation-delay: -0.9s;
}

.spinner-wave div:nth-child(5) {
    -webkit-animation-delay: -0.8s;
    animation-delay: -0.8s;
}
The wave animation is going to be similar to the bounce circle animation it will simply scale the element from small to large, with each of the elements starting at different times it will create the wave effect.
@-webkit-keyframes wave {
    0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
    20% { -webkit-transform: scaleY(1.0) }
}

@keyframes wave {
    0%, 40%, 100% { transform: scaleY(0.4); }
    20% { transform: scaleY(1.0); }
}

Rotating Cubes

The rotating cubes loader will take two cubes and spin them around each other in a small circle, they will grow and shrink depending on position of the cubes.
cube-spinner

The HTML

The HTML for the cubes is very simple you just need a parent element and two child elements, these child elements will be used to style the cubes for the spinner.

The CSS

The styling of the parent element will create an area of 60 x 60 pixels for the cubes to stay within.
.spinner-cube
{
    margin: 0 auto;
    width: 60px;
    height: 60px;
    position: relative;
}
The child elements will need to be styled the same as each other, they have a black background and a width and height of 20 x 20 pixels. Next will be the CSS animation ofcuberotate which will run on both elements. We want to start the cubes animation at different times so it creates the effect of spinning around each other.
.spinner-cube > div
{
    background-color: #333;
    width: 20px;
    height: 20px;
    position: absolute;
    top: 0;
    left: 0;

    -webkit-animation: cuberotate 1.8s infinite ease-in-out;
    animation: cuberotate 1.8s infinite ease-in-out;
}

.spinner-cube div:nth-child(2)
{
    -webkit-animation-delay: -0.9s;
    animation-delay: -0.9s;
}
Next we can add the cuberotate CSS animation which will be used to move the elements, rotate them and change the scale of each of the elements.
@-webkit-keyframes cuberotate {
    25% { -webkit-transform: translateX(22px) rotate(-90deg) scale(0.5) }
    50% { -webkit-transform: translateX(22px) translateY(22px) rotate(-180deg) }
    75% { -webkit-transform: translateX(0px) translateY(22px) rotate(-270deg) scale(0.5) }
    100% { -webkit-transform: rotate(-360deg) }
}

@keyframes cuberotate {
    25% { transform: translateX(42px) rotate(-90deg) scale(0.5); } 
    50% { transform: translateX(42px) translateY(42px) rotate(-179deg); } 
    50.1% { transform: translateX(42px) translateY(42px) rotate(-180deg); } 
    75% { transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5); } 
    100% { transform: rotate(-360deg); }
}
If you want to see these spinners in action just click the link below to view the demo.

jQuery编程的最佳实践

加载jQuery

1.坚持使用CDN来加载jQuery,这种别人服务器免费帮你托管文件的便宜干嘛不占呢。点击查看使用CDN的好处,点此查看一些主流的jQuery CDN地址。



2.安全起见,最好还是提供一个本地备份以便在无法从远程CDN服务器获取jQuery时网站也能工作,如上面代码所示。详情见此。
3.使用裸协议的URL(也就是说去掉http:或者https:),如上面代码展示的那样。
4.如果可能,尽量将你的JavaScript和jQuery代码放到页面底部。详情移步这里,或者查看一个HTML5页面标准模板。
5.该使用哪个版本?
  • 如果你想兼容IE678请表用2.x的版本
  • 针对极少数不用考虑兼容性的幸运儿,极力推荐使用最新版本的jQuery
  • 当从CDN服务器加载jQuery时,最好把版本写全(比如1.11.0而不是1.11或者直接写个1)
  • 千万莫重复加载
6.如果你同时还使用了其他JS框架诸如Prototype, MooTools, Zepto云云,因为他们也使用了$符号,所以你就表再用美刀符号来进行jQuery 编码了,而请用'jQuery'代替。并且调用$.noConflict()保证不会有冲突出现。
7.要检测浏览器对一些新特性是否支持,请用Modernizr。插播广告:论为毛不检测浏览器

关于变量

1.jQuery类型的变量最好加个$前缀。
2.时常将jQuery选择器返回的内容存进变量以便重用
var $products = $("div.products"); // 慢
var $products = $(".products"); // 快
3.使用驼峰命名

关于选择器

1.尽量ID选择器。其背后机理其实是调用原生的document.getElementById(),所以速度较其他选择器快。
2.使用类选择器时表指定元素的类型。不信你看这个性能比较
var $products = $("div.products"); // 慢
var $products = $(".products"); // 快
3.ID父亲容器下面再查找子元素请用.find()方法。这样做快的原因是通过id选择元素不会使用Sizzle引擎。详情看这里 
4.多级查找中,右边尽量指定得详细点而左边则尽量简单点。了解更多
// 丑陋
$("div.data .gonzalez");

// 优化后
$(".data td.gonzalez");
5.避免冗余。详情或者查看性能比较
$(".data table.attendees td.gonzalez");
 
// 好的方式:去掉了中间的冗余
$(".data td.gonzalez");
6.指定选择的上下文。
// 劣质的代码:因为需要遍历整个DOM来找到.class
$('.class');

// 高品代码:因为只需在指定容器范围内进行查找
$('.class', '#class-container');
7.表使用万能选择器。查看具体阐释
$('div.container > *'); // 差
$('div.container').children(); // 棒
8.警惕隐式的万能选择器。省略的情况下其实使用的就是*号通配符。更多信息
$('div.someclass :radio'); // 差
$('div.someclass input:radio'); // 棒
9.ID已经表示唯一了,背后使用的是document.getElementById(),所以表跟其他选择器混搭了。
$('#outer #inner'); // 脏
$('div#inner'); // 乱
$('.outer-container #inner'); // 差
$('#inner'); // 干净利落,后台只需调用document.getElementById()

DOM操作相关

1.操作任何元素前先将其从文档卸载,完了再贴回去。这事儿还能说细点
var $myList = $("#list-container > ul").detach();
//...一大堆对$myList的处理
$myList.appendTo("#list-container");
2.代码里将HTML组织好后再一次性贴到DOM中去。具体来说,性能比较
// 这样不好
var $myList = $("#list");
for(var i = 0; i < 10000; i++){
    $myList.append("
  • "
  • +i+"
    "); } // 这样好 var $myList = $("#list"); var list = ""; for(var i = 0; i < 10000; i++){ list += "

  • "
  • +i+""; } $myList.html(list); // 但这样更好 var array = []; for(var i = 0; i < 10000; i++){ array[i] = "
  • "
  • +i+""; } $myList.html(array.join(''));
    3.不要处理不存在的元素。详情
    // 无良的做法:jQuery后台要跑完三个函数后才会知道这个元素其实根本不存在
    $("#nosuchthing").slideUp();
    // 应该这样
    var $mySelection = $("#nosuchthing");
    if ($mySelection.length) {
        $mySelection.slideUp();
    }

    事件相关

    1.一个页面只写一个文档ready事件的处理程序。这样代码既清晰好调试,又容易跟踪代码的进程。
    2.表用匿名函数来做事件的回调。匿名函数不易调试维护测试和复用。或许你想较真,看看这里吧
    $("#myLink").on("click", function(){...}); // 表这样
     
    // 这样
    function myLinkClickHandler(){...}
    $("#myLink").on("click", myLinkClickHandler);
    
    3.处理文档ready事件的回调也表用匿名函数,匿名函数不易调试维护测试和复用:(
    $(function(){ ... }); // 糟糕的做法:无法利用此函数也无法为其写测试用例
     
    // 好的做法
    $(initPage); // 抑或 $(document).ready(initPage);
    function initPage(){
        // 这里你可以进行程序的初始化了
    }
    
    4.进一步,最好也将ready事件的处理程序放到外部文件中引入到页面,而页面中内嵌的代码只需调用即可。
    
    
    
    5.千万表写内联到HTML的JS代码,这是调试的梦魇!应该总是用jQuery来绑定事件自带程序,这样也方便随时动态地取消绑定。
    $("#myLink").on("click", myEventHandler); // GOOD
    
    6.如果可能尽量在绑定事件处理程序时使用一个命名空间,这样可以方便地取消绑定而不会影响其他绑定。
    $("#myLink").on("click.mySpecialClick", myEventHandler); // 不错
    // 之后,让我们优雅地解除绑定
    $("#myLink").unbind("click.mySpecialClick");
    

    异步操作

    1.直接用$.ajax()而表去用.getJson() 或 .get(),因为jQuery内部还是将其转为前者
    2.表对HTTPS站点使用HTTP去发起请求,最好干脆就表指定(将HTTP或者HTTPS从你的URL中移除)
    3.表在链接里面嵌参数,请使用专门的参数设置来传递
    // 不易阅读的代码...
    $.ajax({
        url: "something.php?param1=test1&param2=test2",
        ....
    });
     
    // 更易阅读...
    $.ajax({
        url: "something.php",
        data: { param1: test1, param2: test2 }
    });
    
    4.尽量指明数据类型以便你自己清楚要处理什么样的数据(见下方会提到的Ajax模板)
    5.对于异步动态加载的内容,最好使用代理来绑定事件处理程序。这样的好处是对于之后动态加载的元素事件同样有效。你或许想了解更多
    $("#parent-container").on("click", "a", delegatedClickHandlerForAjax);
    
    6.使用Promise模式。更多例子
    $.ajax({ ... }).then(successHandler, failureHandler);
     
    // 抑或
    var jqxhr = $.ajax({ ... });
    jqxhr.done(successHandler);
    jqxhr.fail(failureHandler);
    
    7.标准的Ajax模板一分。追寻根源
    var jqxhr = $.ajax({
        url: url,
        type: "GET", // 默认为GET,你可以根据需要更改
        cache: true, // 默认为true,但对于script,jsonp类型为false,可以自行设置
        data: {}, // 将请求参数放这里.
        dataType: "json", // 指定想要的数据类型
        jsonp: "callback", // 指定回调处理JSONP类型的请求
        statusCode: { // 如果你想处理各状态的错误的话
            404: handler404,
            500: handler500
        }
    });
    jqxhr.done(successHandler);
    jqxhr.fail(failureHandler);
    

    动画与特效

    1.保持一个始终如一风格统一的动画实现
    2.紧遵用户体验,表滥用动画特效
    • 使用简洁的显示隐藏,状态切换,滑入滑出等效果来展示元素
    • 使用预设值来设置动画的速度'fast','slow',或者400(中等速度)

    插件相关

    1.始终选择一个有良好支持,完善文档,全面测试过并且社区活跃的插件
    2.注意所用插件与当前使用的jQuery版本是否兼容
    3.一些常用功能应该写成jQuery插件。一分jQuery插件的编写模板

    链式句法

    1.除了用变量将jQuery选择器返回的结果保存,还可以利用好链式调用。
    $("#myDiv").addClass("error").show();
    
    2.当链式调用多达3次以上或代码因绑定回调略显复杂时,使用换行和适当的缩进来提高代码的可读性。
    $("#myLink")
        .addClass("bold")
        .on("click", myClickHandler)
        .on("mouseover", myMouseOverHandler)
        .show();
    
    3.对于特别长的调用最好还是用变量保存下中间结果来简化代码。

    其他

    1.使用对象字面量来传递参数
    $myLink.attr("href", "#").attr("title", "my link").attr("rel", "external"); // 糟糕:调用了三次attr
    // 不错,只调用了一次attr
    $myLink.attr({
        href: "#",
        title: "my link",
        rel: "external"
    });
    
    2.表将CSS与jQuery杂揉
    $("#mydiv").css({'color':red, 'font-weight':'bold'}); // 不好
    .error {/* 不错 */
        color: red;
        font-weight: bold;
    }
    $("#mydiv").addClass("error"); 
    
    3.时刻关注官方Changelog,表使用摒弃了的方法。点此查看所有废弃的方法
    4.适时地使用原生JavaScript。一些与此有关的性能比较
    $("#myId"); // 多少还是会逊色于...
    document.getElementById("myId");
    

    REFERENCE

    原文:Coding Standards & Best Practices http://lab.abhinayrathore.com/jquery-standards/
    原文的reference

    fanotify与inotify的区别

    fanotify在2.6.36版本(2010-10-21)并入Linux内核(同时增加了CIFS本地缓存),它与原有的inotify的区别在于以下:

    1、inotify最麻烦的一点就是不能监控子目录,要自己去弄n多个监控。fanotify也不能自动监控子目录,但它有一个Global模式,可以监控整个文件系统的所有事件。这样就可以监控所有事件,然后在程序里判断,这样也算是个比之前好一些的解决方案;

    2、inotify只能接受事件。fanotify不仅可以接受事件,还可以阻塞事件,甚至进一步阻止事件执行成功。并且可以持续地给这个文件设置上acl,且不用每次触发都判断一次(省去麻烦,增加性能);

    3、fanotify允许多个程序同时监控同一个文件系统对象,并且可以设置优先级(消息到达前后)。这个机制可以处理通过fanotify机制本身做出的动态文件;

    4、fanotify可以指定不监控某些pid对文件的操作,这是inotify做不到的。使用场景例子:可以让监控程序自己不会触发事件,避免了让程序员自己去处理死循环的麻烦;

    5、fanotify相对于inotify的致命缺陷:fanotify可以触发的事件比inotify少,尤其是缺乏MOVE、ATTRIB、CREATE、DELETE事件(有ACCESS、MODIFY、CLOSE)。

    Why the results from nslookup are different to the operation of ping

    Why the results from nslookup are different to the operation of ping

    You've come to this page because you've asked a question similar to the following:
    When I pass a domain name to ping it ends up communicating with one particular IP address/reporting a non-existent domain. Why, therefore, when I look up that domain name with nslookup do I see something entirely different to that ?
    This is the Frequently Given Answer to that question.
    ping is not a tool for diagnosing DNS problems. It is a tool for diagnosing IP connectivity problems. If you are trying to use it for the former task, stop.
    Moreover, nslookup is a bad tool and there are better DNS diagnostic tools. Stop using it.
    The reason that nslookup can operate differently to ping when it comes to converting domain names to IP addresses is that ping uses the system-supplied library, as used by other applications, for name-to-address mapping whereas nslookup has its own, built in, DNS client library. The system-supplied library consults sources other than one's configured proxy DNS servers, when performing name-to-address mappings. The DNS client library built in to nslookup consults only the DNS. If, therefore, those other sources contain relevant information, the results obtained by using the system-supplied lookup facilities, and thus the operation of ping, will be different to the results obtained via nslookup.
    For examples:
    • On Windows, the system-supplied lookup routines also consult WINS and a HOSTS file, if one has one. If any information is available from either source about the name being looked up, ping will use that information whereas nslookup will not.
    • On Unix and on Linux, if information is available via NIS or in /etc/hosts, ping will use that information whereas nslookup will not. (On many Unices and on Linux, this behaviour is controllable via /etc/nsswitch.conf and one can tell the system-supplied lookup facilities to consult only the DNS if one wishes to.)
    • On Windows, on Unix, and on Linux, the system-supplied lookup routines mechanisms may involve local caching (nscd on Unix and on Linux, the caching in the DNS Client service on Windows), whereas nslookup will not. (The difference is often most noticable when it comes to negative answers to lookups.)
    Incidentally: The version of nslookup supplied with HP/UX by the vendor has been altered to use these extraneous sources of information in addition to the DNS. However, this makes it unsuitable for use in DNS problem diagnosis.

    Presenting the Permanent Generation

    Presenting the Permanent Generation

    Have you ever wondered how the permanent generation fits into our generational system? Ever been curious about what's in the permanent generation. Are objects ever promoted into it? Ever promoted out? We'll you're not alone. Here are some of the answers.
    Java objects are instantiations of Java classes. Our JVM has an internal representation of those Java objects and those internal representations are stored in the heap (in the young generation or the tenured generation). Our JVM also has an internal representation of the Java classes and those are stored in the permanent generation. That relationship is shown in the figure below.
    The internal representation of a Java object and an internal representation of a Java class are very similar. From this point on let me just call them Java objects and Java classes and you'll understand that I'm referring to their internal representation. The Java objects and Java classes are similar to the extent that during a garbage collection both are viewed just as objects and are collected in exactly the same way. So why store the Java objects in a separate permanent generation? Why not just store the Java classes in the heap along with the Java objects?
    Well, there is a philosophical reason and a technical reason. The philosophical reason is that the classes are part of our JVM implementation and we should not fill up the Java heap with our data structures. The application writer has a hard enough time understanding the amount of live data the application needs and we shouldn't confuse the issue with the JVM's needs.
    The technical reason comes in parts. Firstly the origins of the permanent generation predate my joining the team so I had to do some code archaeology to get the story straight (thanks Steffen for the history lesson).
    Originally there was no permanent generation. Objects and classes were just stored together.
    Back in those days classes were mostly static. Custom class loaders were not widely used and so it was observed that not much class unloading occurred. As a performance optimization the permanent generation was created and classes were put into it. The performance improvement was significant back then. With the amount of class unloading that occur with some applications, it's not clear that it's always a win today.
    It might be a nice simplification to not have a permanent generation, but the recent implementation of the parallel collector for the tenured generation (aka parallel old collector) has made a separate permanent generation again desirable. The issue with the parallel old collector has to do with the order in which objects and classes are moved. If you're interested, I describe this at the end.
    So the Java classes are stored in the permanent generation. What all does that entail? Besides the basic fields of a Java class there are
    • Methods of a class (including the bytecodes)
    • Names of the classes (in the form of an object that points to a string also in the permanent generation)
    • Constant pool information (data read from the class file, see chapter 4 of the JVM specification for all the details).
    • Object arrays and type arrays associated with a class (e.g., an object array containing references to methods).
    • Internal objects created by the JVM (java/lang/Object or java/lang/exception for instance)
    • Information used for optimization by the compilers (JITs)
    That's it for the most part. There are a few other bits of information that end up in the permanent generation but nothing of consequence in terms of size. All these are allocated in the permanent generation and stay in the permanent generation. So now you know.
    This last part is really, really extra credit. During a collection the garbage collector needs to have a description of a Java object (i.e., how big is it and what does it contain). Say I have an object X and X has a class K. I get to X in the collection and I need K to tell me what X looks like. Where's K? Has it been moved already? With a permanent generation during a collection we move the permanent generation first so we know that all the K's are in their new location by the time we're looking at any X's.
    How do the classes in the permanent generation get collected while the classes are moving? Classes also have classes that describe their content. To distinguish these classes from those classes we spell the former klasses. The classes of klasses we spell klassKlasses. Yes, conversations around the office can be confusing. Klasses are instantiation of klassKlasses so the klassKlass KZ of klass Z has already been allocated before Z can be allocated. Garbage collections in the permanent generation visit objects in allocation order and that allocation order is always maintained during the collection. That is, if A is allocated before B then A always comes before B in the generation. Therefore if a Z is being moved it's always the case that KZ has already been moved.
    And why not use the same knowledge about allocation order to eliminate the permanent generations even in the parallel old collector case? The parallel old collector does maintain allocation order of objects, but objects are moved in parallel. When the collection gets to X, we no longer know if K has been moved. It might be in its new location (which is known) or it might be in its old location (which is also known) or part of it might have been moved (but not all of it). It is possible to keep track of where K is exactly, but it would complicate the collector and the extra work of keeping track of K might make it a performance loser. So we take advantage of the fact that classes are kept in the permanent generation by collecting the permanent generation before collecting the tenured generation. And the permanent generation is currently collected serially.