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.
.style1{
width : 100%;
}
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
- create new project or new file in your ide
- add index.html
- download jquery
- include script in index.html
- download the plugin
- include in index.html
- add new empty <script>
- 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
$('#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:
$('#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 :
$('#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
$('#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
$('#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
@-webkit-keyframes test{
0%{
background : red;
}
50%{
background:green;
}
100%{
background : blue;
}
};
javascript
$('#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
$('#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.
$('#container').children().filter('div').dcss(
{
pointerEvents:'none',
borderRadius:'100px',
transform : 'translate(0%,0%) scale(.5,.5)',
opacity : '0',
transition : 'all 1s <time>s ease-in'
},
{
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.
$('#container').children().filter('div').dcss(
{
pointerEvents:'all',
borderRadius:'20px',
transform : 'translate(0%,0%) scale(1,1)',
opacity : '1',
transition : 'all .5s <time>s ease-out',
display:'block'
},
{
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.
$('#container').children().filter('div').dcss(
{
pointerEvents:'none',
borderRadius:'100px',
transform : 'translate(0%,0%) scale(.5,.5)',
opacity : '0',
transition : 'all 1s <time>s ease-in'
},
{
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 :
function showNormal(){
$('#container').children().filter('div').dcss(
{
pointerEvents:'all',
borderRadius:'20px',
transform : 'translate(0%,0%) scale(1,1)',
opacity : '1',
transition : 'all 1s <time>s ease-out',
display:'block'
},
{
time : function(i,el,c){
return dcss.grid(i,c,5,.5,.5,false) * .1;
}
});
}
Live Preview
and with "Invert" enabled
function showInvert(){
$('#container').children().filter('div').dcss(
{
pointerEvents:'all',
borderRadius:'20px',
transform : 'translate(0%,0%) scale(1,1)',
opacity : '1',
transition : 'all 1s <time>s ease-out',
display:'block'
},
{
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.
$('#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;
return -180 + rnd;
},
});
$('#container').children().filter('div').dcss(
{
pointerEvents:'none',
transform : 'translate3d(0px,0px,<z>px) scale(1,1)',
opacity : '0',
transition : 'all <time>s <delay>s ease-in-out'
},
{
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.
$('#container').children().filter('div').dcss(
{
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
if(jQuery){
(function ( $ ) {
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;
}
$.fn.dcss = function(props,values) {
var p;
var v;
var c = this.length;
this.each(function(index){
p = {};
var vals = {};
for (var vkey in values) {
v = values[vkey];
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;
}
}
for (var pkey in props) {
p[pkey] = props[pkey];
for (var vkey in values) {
p[pkey] = replaceAll(p[pkey],'<'+ vkey + '>', vals[vkey] );
}
}
$(this).css(p);
});
return this;
};
}( jQuery ));
}
dcss Object
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.