Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

Dynamic-CSS Styles and Animations - Jquery Plugin

5.00/5 (4 votes)
11 Nov 2014CPOL8 min read 22.4K  
Jquery plugin to create dynamic css animations and transitions.

Download

you can download sources from github.

Introduction

CSS scripts are very cool for styling and animating html DOM ojbect. you can apply the same style to multiple elements, to create awesome web pages. however applying these styles to multiple objects has no way to apply object specific values without creating another CSS class.

CSS
/*creating class for some objects*/
.style1{
    width : 100%;
}

/*creating another class for another object to change one property*/
style2{
    width : 50%;
}


LESS and SASS  (css pre-processors)  tried to solve some problems by creating varibles, inheritance and other pre-processor code optimizations, but the final result is a statically typed css script added to the web page.

Problem

   thier is no way to creating element specific values inside css (till now) as it is one way only (selected elements are affected by properties inside the class). but you cannot generate values specefic for each element.

Ways to Solve

   If we want to create element specific values. we ways like:

  • create multiple css classes.
  • Use pre-processors
  • apply inline styles to element's style attribute.
  • use java script to change style properties.
  • use jquery to apply styles to target elements.

         But.... .

creating multiple css classes is quite with small number of variants, but with more than 10,20 .... elements , you will sink in classes that have the same function :( :( .

inline styles are quite for only one object that differ from other object. and also you have lost the power of selectors.

javascript itself will be hard to deal with selectors and writing  prefixes for every browser.

jquery in my opinion is the most benificial tool for this job.It has built is selector system and also it is javascript library so you are in computational media to deal with elements so elements can affect css style values and style can affect element layout and also it has a .css property that is cross browser and removes the headache of prefixes.
 

    Dynamic-CSS plugin

    before going to code. it is to be noted that jquery can produce css values for selected elements.but it is hard and need to be managed and that what is done by Dynamic-CSS.

Download and Install

  1. create new project or new file in your ide
  2. add index.html
  3. download jquery
  4. include script in index.html
  5. download the plugin
  6. include in index.html
  7. add new empty <script>
  8. add some html elements and css styles.

    The index.html file may be a thing like index.html in download packages

Begin with dynamic-CSS

Applying css properties to elements with  jquery

JavaScript
$('#container').children().filter('div').css(
    {   
        transform : 'translate(0%,0%)  scale(.5,.5)',
​        transition : 'all .5s .1s linear'
    });

This is a simple query whitch apply some static values to all selected elements.

now to make this property dynamic we will replace the following

.css   ---->  .dcss       /*dynamic css function*/

-----------------------------------------------------------
transition : 'all .1s <delay>s linear'  

replace  ".1"  value with <delay> dynamic value to be replaced by  the plugin .

-----------------------------------------------------------
.dcss accepts 2 params so we will add another param which define the value of  the <delay>variable

{
    delay : .1
}

Code:

JavaScript
//example1
 $('#container').children().filter('div').dcss(
 {
     transform : 'translate(0%,0%)  scale(.5,.5)',
     transition : 'all .5s <delay>s linear'
 },
 {
     delay : .1
 });

Live Preview

now the plugin will read the value of delay and apply it to all occurrence of <delay> in provided css properties .so value delay is a variable used inside dcss function.

Till now it is just a separation of the style and values, but if we replaced the  ".1" value with a function that return the dynamic value, the code will be like :

JavaScript
//example2
$('#container').children().filter('div').dcss(
    {   
    transform : 'translate(0%,0%)  scale(.5,.5)',
    transition : 'all 1s <delay>s linear' 
    },
    {
        delay : function(i,el,c){ return i * .1;}
    });
}; 

Live Preview

Now for every object in the array the plugin will call "delay" function and replace each  <delay> variable with the value produced.


Params of called function (i ,el , c)

i  =  index of target element in the jquery array of elements.
el = element itself.
c = length of selected array.

these 3 arguments are passed to the function to do calculations and return a value specific to "el"  element.

in this example we return  ( i * .1)   

that means each element will delay .1 more than the previous element.

Adding multiple variables

JavaScript
//example 3
$('#container').children().filter('div').dcss(
    {   
    transform : 'translate(<transX>%,<transY>%)  scale(.5,.5)',
    transition : 'all 1s <delay>s linear' 
    },
    { 
        delay  : function(i,el,c){ return i * .1;},
        transX : function(){ return 50 - Math.random()*100;},
        transY : function(){ return 50 - Math.random()*100;}
    });

Live Preview


transX function return  a value from  -50  --> 50   and transY as well applied to "transform" property.

It is to be noted that all variables are computed one time for every element. So we have separated transX and transY.
 

Multi-occurrence of variable

JavaScript
//example 4 
$('#container').children().filter('div').dcss(
    {   
    width : '<len>px',
    height : '<len>px' 
    },
    { 
        len : function(i,el,c){return 30 + Math.random() * 100;}
    });
    
}; 

Live Preview

here we have resized all element with the len function.
As we explained before 'len' will be calculated one time only so width = height and all results will be randomly sized squares.

Calling key frames

Modifing keyframes is one of limitations of dynamic css that we are trying to fix. It cannot modify values in css style cheat but only, we can use them.

css keyframes

CSS
//example 5
@-webkit-keyframes test{
            
            0%{
                background : red;
            }
            50%{
                background:green;
            }
            100%{
                background : blue;
            }
        };

javascript

CSS
$('#container').children().filter('div').dcss(
{
    animation : 'test <dur>s 0s ease-in-out alternate infinite'
},
{
    dur   : function(i,el,c){return 1 + Math.random() * 5;},
});

this will produce different durations for each element using the same keyframes.

Live Preview


String values

JavaScript
//example 6
$('#container').children().filter('div').dcss(
    {   
    height : '400px',
    transition : 'all 1s 0s ease<in><out>'
    },
    { 
        in : function(i,el,c){return (i % 2 == 0) ? '-in':''; },
        out : function(i,el,c){return (i % 2 == 1) ? '-out':''; }
    });
    
}; 

Live Preview

if  "i" is even so we will push "-in" else push "-out"  so :

  • even elements will have "ease-in" function.
  • odd elements will have "ease-out" function.

Grid Functions

All previous illustrations are basic usage of dynamic-CSS plugin. Grid functions will push the usability of the code to a new level.

Grid mathimaticaly converts 1d array to 2d array with rows and cols .

"grid" function returns a new index for the current element according to its distance from the provided center point.

"gridRowCol" returns the current row and col for provided index.

function 

dcss.grid(index,count,cols , centerX , centerY,invert);

index = index of current element.
count = count of grid cells
cols = count of grid columns
centerX,centerY = center point of the grid have value from 0 to 1.
invert = invert the first element to be last and vice versa.
 

Usage

   Assume we have a 5 x 5 grid of <div> elements and we want to create transition animation from the bottom-left corner to the top-right corner.
 

JavaScript
//example 7
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        pointerEvents:'none',
        borderRadius:'100px',
        transform : 'translate(0%,0%)  scale(.5,.5)',
        opacity   : '0',
        transition : 'all 1s <time>s ease-in'
    },
    {
        //values to be applied to property values
        time : function(i,el,c){ 
            var ii = dcss.grid(i,c,5,0,1);
            return  ii * .1;
        } 
    }
);

Live Preview

ii = new generated index for the current element in the virtual grid.

dcss.grid(i,c,5,0,1,false)

i = true index of current element.
c = 25 /*  count of grid cells*/

0,1 = center point of the grid (set to bottom,left);

ii * .1   ==>  for each item in the grid  increase the delay with .1 sec

there is something here:

if we start calculation from top,left point so the grid cells    2,3 and  3,2 will have the same distance and hence the same grid index.
this will create a smooth animation.

the code above will hide the grid elements with transition .and the following code will show it again with different params.

JavaScript
//example 7
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        pointerEvents:'all',
        borderRadius:'20px',
        transform : 'translate(0%,0%) scale(1,1)',
        opacity   : '1',
        transition : 'all .5s <time>s ease-out',
        display:'block'
    },
    {
        //values to be applied to property values
        time : function(i,el,c){ 
            return dcss.grid(i,c,5,.5,1) * .1;
        } 
    });

Live Preview

Pure vertical or horizontal animation

center point affect cells in both directions vertical and horizontal.

to disable animation gradient in one direction just pass null instead of 0.0-1.0 value.

dcss.grid(i,c,5,0,null);

all elements in the same column will have the same index and hence the same delay.
 

JavaScript
//example 8
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        pointerEvents:'none',
        borderRadius:'100px',
        transform : 'translate(0%,0%)  scale(.5,.5)',
        opacity   : '0',
        transition : 'all 1s <time>s ease-in'
    },
    {
        //values to be applied to property values
        time : function(i,el,c){ 
            var ii = dcss.grid(i,c,5,0,null);
            return  ii * .1;
        } 
    }
);

Live Preview

Invert parameter

As grid selects elements near center point first so if we set center to  0.5,0.5 , first element will be the centeral element and it will always start animation before others. Setting "invert" param to true will select the farest element first then the nearer till the centeral element to be last selected element.

Normal animation :

JavaScript
 //example 9 
function showNormal(){
    
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        pointerEvents:'all',
        borderRadius:'20px',
        transform : 'translate(0%,0%) scale(1,1)',
        opacity   : '1',
        transition : 'all 1s <time>s ease-out',
        display:'block'
    },
    {
        //values to be applied to property values
        time : function(i,el,c){ 
            return dcss.grid(i,c,5,.5,.5,false) * .1;
        } 
    });
}

Live Preview

and with "Invert" enabled

JavaScript
//example 9
function showInvert(){
    
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        pointerEvents:'all',
        borderRadius:'20px',
        transform : 'translate(0%,0%) scale(1,1)',
        opacity   : '1',
        transition : 'all 1s <time>s ease-out',
        display:'block'
    },
    {
        //values to be applied to property values
        time : function(i,el,c){ 
            return dcss.grid(i,c,5,.5,.5,true) * .1;
        } 
    });
}

Live Preview

Playing with 3d : 

  we will create one dcss call for the container and another call for the grid.

JavaScript
//example 10
//animating container element
    $('#container').dcss({
        transform  : 'perspective( 600px ) rotateY(<ang>deg)',
        transition : 'all 2s 0s ease-in-out',
        transformStyle: 'preserve-3d'
    },
    {
        ang : function(){
            var rnd = Math.random() * 360;
            //if (rnd > 90) rnd +=180 ;
            return -180 + rnd;
        },
    });
    
//animating grid elements
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        pointerEvents:'none',
        transform : 'translate3d(0px,0px,<z>px) scale(1,1)',
        opacity   : '0',
        transition : 'all <time>s <delay>s ease-in-out'
    },
    {
        //values to be applied to property values
        z     : function(i){
            return -200 + Math.random() * 400;
        },
        
        delay : function(i){ 
            return Math.random() * .5;
        },
        time  : function(i){ 
            return .5 + Math.random() * .5;
        } 
    }
);

Live Preview


Other dcss functions

  Other functions return value for custom usage .

dcss.gridRowCol(index,cols);

where 

index = true index of current element.
cols = number of columns in the grid.

return  object with .row and .col properties providing the grid position.

Ex

set background position to each element to get a fragement effect on image.

JavaScript
//example 11
//setup background image
$('#container').children().filter('div').dcss(
        //css properties to be processed and applied to object
    {
        background: 'url(../images/1.jpg)',
        backgroundPosition: '<l>% <t>%',
        backgroundSize: '500% 500%'
    },
    {
        l :  function(i,el,c){
            var rc =  dcss.gridRowCol(i,5);
            return rc.col / (5-1) * 100;
        },
        t :  function(i,el,c){
            var rc =  dcss.gridRowCol(i,5);
            return rc.row / (5-1) * 100;
        }
        
    });

Normal Image:

With animation applied to each grid cell dynamically

Live Preview

 

dcss.ease(s2,s3,r);

basic ease function accepts 2 control float values and  ratio value.


Points of Interest

Pros
  • customize css properties with ease
  • apply per-element style values.
  • compute values on demand
  • flexible as you still can use keyframe rules and classes.
  • add only few lines of code to your page
  • no performance load.
Cons
  • Use of jquery selectors so you have lost the auto selection for newly added elements.
  • still cannot change keyframe values.
Remember

This plugin is not made to replace css,less or sass. The aim of the plugin is to solve some css limitations.
 

Behind the scene

It may be easy to professionals to guess how plugin works. The idea itself is very simple. Only all what the plugin do is replacing the <var> with a var .  

before you read the plugin code please read how to create a basic jquery plugin here.

function is only 1 file separated into 2 parts

  • jquery plugin
  • dcss object holds the helper functions.

Jquery Function

JavaScript
if(jQuery){
    (function ( $ ) {
        // replace all occurrence of 'token' inside 'text' by 'value'.
        var  replaceAll=function(text,token,value){
            var index=-1;
            string = text;
            while((index = string.indexOf(token,index+1)) > -1){
                    string = string.replace(token, value);
            };
            return string;
        }
        //register our 'dcss' function as jquery plugin.
        $.fn.dcss = function(props,values) {
            //holder for modified property values
            var p;       
            //hold property value till modifing all args
            var v;      
            //count of elements
            var c = this.length;
            this.each(function(index){
                //create new object to hold specific values for the current selected element
                p = {};
                //compute values
                var vals = {};
                for (var vkey in values) {    
                    //get current value object  {value : 1,added : 1}.
                    v = values[vkey];
                    //process the value according to its type
                    if ( typeof(v) === 'number'){
                        vals[vkey] = v;
                    }else if ( typeof(v) === 'function'){
                        vals[vkey] = v(index,this,c);
                    }else if ( typeof(v) === 'string'){
                        vals[vkey] = v;
                    }
                }
                //loop throw properties to change values inside them
                for (var pkey in props) {
                        //set pre-processed value to holder 'p' object.
                        p[pkey] = props[pkey];      
                        //loop throw all actual value to change them in p object.
                        for (var vkey in values) {    
                                //replace all occurence of keys in the property value.
                                p[pkey] = replaceAll(p[pkey],'<'+ vkey + '>', vals[vkey] );
                        }
                    }
                    //apply the css.
                    $(this).css(p);
            });
            //return jquery object again to allow Chaining.
            return this;
        };
    }( jQuery ));
}

dcss Object

JavaScript
dcss = {
    grid : function (index,count,cols , centerX , centerY,invert){
        var row = Math.floor(  index/ cols);   
        var col = (index - (row * cols));
        var rows = Math.ceil(count/cols);   
        if(centerX != null){
           col = col - (cols-1) * centerX;
        }else
        {
            cols = 0;
            col  = 0;
        }
        if(centerY != null){
            row = row - (rows-1) * centerY;
        }else{
            row  = 0;
            rows = 0;
        }
        if(row < 0) row = -row;
        if(col < 0) col = -col;
        var res = row+col;
        if(invert ===true){
            res = (cols+rows-2) -res;
        }
        return res ; 
    },
    gridRowCol: function(index,cols){
        var row = Math.floor(  index/ cols);   
        var col = (index - (row * cols));
        return {row:row,col:col};
    },
    ease : function ( c1,c2,  r) {
        var s2,s3;
        s2 = c1;
        s3 = c2;
        var s1;
        s1 = 0 + (s2 - 0) * r;
        s2 = s2 + (s3 - s2) * r;
        s3 = s3 + (1 - s3) * r;
        s1 = s1 + (s2 - s1) * r;
        s2 = s2 + (s3 - s2) * r;
        return s1 + (s2 - s1) * r;
    }
};

 

Feedback

Feel free to leave any feedback on this article; it is a pleasure to see your comments and vote about this code. If you have any questions, please do not hesitate to ask me here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)