Плывущие облака на CSS3
Дата публикации: 05.10.2012
Задача
Сделать плывущие «живые» облака.
Решение
Применяем методику используемую для построения облаков в играх. Это не супер-пупер реалистично, но зато производительно. Метод основан на многослойности объекта. Каждый слой — это текстура, к которой применяются случайные трансформации, что в сумме дает объект неплохо напоминающий облако.
<div id="sky"> <div id="world"></div> </div>
#sky {
height: 400px;
position: relative;
-moz-perspective: 1000px; // глубина сцены
-webkit-perspective: 1000px;
perspective: 1000px;
overflow: hidden;
background:-moz-linear-gradient(top, #072ac0, #4466f9);
background:-webkit-linear-gradient(top, #072ac0, #4466f9);
backround-image: linear-gradient(top, #072ac0, #4466f9);
}
#world {
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d; // объекты поддаются 3d траснформациям
position: relative;
height: 100%;
}
#world>div {
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.cloud {
position: absolute;
}
.cloudLayer {
position: absolute;
left: 50%;
top: 50%;
width: 356px; /* размеры не обязательно подстраивать под размеры текстуры */
height: 356px;
margin-left: -178px;
margin-top: -178px;
-webkit-transition: opacity .5s ease-out;
-moz-transition: opacity .5s ease-out;
transition: opacity .5s ease-out;
}
var world = document.getElementById('world'), // сцена
nClouds, // число облаков
arrClouds = [],
arrLayersClouds = []
nSkyWidth = world.offsetWidth,
nSkyHeight = world.offsetHeight;
/* чем меньше экран - тем меньше нужно облаков */
if(world.offsetWidth > 1500) nClouds = 5;
else nClouds = 3;
/* формируем облака */
for(i=0; i<nClouds; i++)
{
arrClouds.push( createCloud(i) );
}
function createCloud(nCloudCount) {
var oCloud = document.createElement( 'div');
oCloud.className = 'cloud';
/* стартовое положение облаков */
var nCloudX = nCloudCount*200 - Math.random()*200, // чтобы была нужная кучность + равномерно распределить облака по небу
nCloudY = nSkyHeight - ( Math.random() * nSkyHeight );
oCloud.style.left = nCloudX + &apospx';
oCloud.style.top = nCloudY+'px';
var nCloudSpeed = Math.random()*.15; // скорость движения облаков
oCloud.data = {
x: nCloudX,
speed: nCloudSpeed
}
world.appendChild( oCloud );
/* формируем слои облака */
var nLayers = 5 + Math.round( Math.random() * 10), // к-во слоев
oCloudLayer,
sCloudTextrure = 'cloud-3.png', // текстура
nCloudLayerX,
nCloudLayerY,
nCloudLayerZ,
nCloudLayerA,
nCloudLayerS,
nCloudLayerSpeed;
for( var j = 0; j < nLayers; j++ ) {
oCloudLayer = document.createElement( 'img' );
oCloudLayer.setAttribute( &apossrc', sCloudTextrure );
oCloudLayer.className = 'cloudLayer';
/* х-ки слоя */
nCloudLayerX = 256 - ( Math.random() * 512 );
nCloudLayerY = 256 - ( Math.random() * 512 );
nCloudLayerZ = 100 - ( Math.random() * 200 ); //
nCloudLayerA = Math.random()*360;
nCloudLayerS = 1.1 + Math.random(); // чем больше коэффициент, тем облако больше (ближе)
if(nCloudLayerS > 0.5) nCloudLayerSpeed = Math.random()*.03; // скорость вращения, чем слой ближе к нам, тем больше скорость вращения
else nCloudLayerSpeed = Math.random()*.02;
nCloudLayerX *= .2; nCloudLayerY *= .2;
oCloudLayer.data = {
nCloudLayerX: nCloudLayerX,
nCloudLayerY: nCloudLayerY,
nCloudLayerZ: nCloudLayerZ,
nCloudLayerA: nCloudLayerA,
nCloudLayerS: nCloudLayerS,
nCloudLayerSpeed: nCloudLayerSpeed
};
var t = 'translateX( ' + nCloudLayerX + 'px ) translateY( ' + nCloudLayerY + 'px ) translateZ( ' + nCloudLayerZ + 'px ) rotateZ( ' + nCloudLayerA + 'deg ) scale( ' + nCloudLayerS + ' )';
oCloudLayer.style.webkitTransform = t;
oCloudLayer.style.MozTransform = t;
oCloudLayer.style.oTransform = t;
oCloud.appendChild( oCloudLayer );
arrLayersClouds.push( oCloudLayer );
}
return oCloud;
}
function update (){
for( var j = arrLayersClouds.length; j--; ) {
var layer = arrLayersClouds[ j ];
layer.data.nCloudLayerA += layer.data.nCloudLayerSpeed;
var t = 'translateX( ' + layer.data.nCloudLayerX + 'px ) translateY( ' + layer.data.nCloudLayerY + 'px ) translateZ( ' + layer.data.nCloudLayerZ + 'px ) rotateZ( ' + layer.data.nCloudLayerA + 'deg ) scale( ' + layer.data.nCloudLayerS + ')';
layer.style.webkitTransform = t;
layer.style.MozTransform = t;
}
for ( var j = arrClouds.length; j--;)
{
var object = arrClouds[j];
if(object.data.x>nSkyWidth+300) object.data.x = -300;
object.data.x+=object.data.speed;
var sCloudT = 'translateX('+ object.data.x+'px )';
object.style.webkitTransform = sCloudT;
object.style.MozTransform = sCloudT;
}
requestAnimationFrame( update );
}
update();
Живой пример. Работает в:
- IE 10
- Firefox
- Safari 5+
- Chrome
- iOs 4+
- Android 3+
Материалы
Показать комментарии
