Seamless animation between states, and some of animations break outside the container. Select the weather icons on the top to see each state.
A Pen by Steve Gardner on CodePen.
Seamless animation between states, and some of animations break outside the container. Select the weather icons on the top to see each state.
A Pen by Steve Gardner on CodePen.
| <div class="background"> | |
| <div class="container"> | |
| <svg id="back"> | |
| <radialGradient id="SVGID_1_" cx="0" cy="0" r="320.8304" gradientUnits="userSpaceOnUse"> | |
| <stop offset="0" style="stop-color:#FFDE17;stop-opacity:0.7"/> | |
| <stop offset="1" style="stop-color:#FFF200;stop-opacity:0"/> | |
| </radialGradient> | |
| <path id="sunburst" style="fill:url(#SVGID_1_);" d="M0,319.7c-18.6,0-37.3-1.6-55.5-4.8L-7.8,41.4c5.1,0.9,10.6,0.9,15.7,0L56,314.8C37.6,318,18.8,319.7,0,319.7z | |
| M-160.8,276.6c-32.5-18.8-61.3-42.9-85.5-71.6L-34,26.2c3.4,4.1,7.4,7.4,12,10.1L-160.8,276.6z M161.3,276.4L22.1,36.2 | |
| c4.5-2.6,8.6-6,12-10.1l212.6,178.5C222.5,233.4,193.8,257.6,161.3,276.4z M-302.5,108.3C-315.4,73-321.9,36-322-1.8l277.6-0.5 | |
| c0,5.3,0.9,10.4,2.7,15.2L-302.5,108.3z M302.6,107.8L41.8,12.8c1.7-4.7,2.6-9.7,2.6-14.9c0-0.3,0-0.6,0-1H322l0-1.3l0,1.9 | |
| C322,35.4,315.5,72.5,302.6,107.8z M-41.8-17.5l-261-94.5c12.8-35.4,31.6-68,55.8-96.9L-34.1-30.8C-37.5-26.8-40.1-22.3-41.8-17.5z | |
| M41.7-17.7c-1.8-4.8-4.4-9.3-7.8-13.3l212-179.2c24.3,28.8,43.3,61.3,56.3,96.6L41.7-17.7z M-22.2-40.8l-139.6-240 | |
| c32.7-19,68.1-32,105.2-38.6L-8-46.1C-13-45.2-17.8-43.4-22.2-40.8z M22-40.9c-4.4-2.6-9.2-4.3-14.2-5.1l47.1-273.6 | |
| c37.2,6.4,72.7,19.2,105.4,38L22-40.9z"/> | |
| </svg> | |
| <nav> | |
| <ul> | |
| <li><a id="button-snow" class="active"><i class="wi wi-snow"></i></a></li> | |
| <li><a id="button-wind"><i class="wi wi-strong-wind"></i></a></li> | |
| <li><a id="button-rain"><i class="wi wi-rain"></i></a></li> | |
| <li><a id="button-thunder"><i class="wi wi-lightning"></i></a></li> | |
| <li><a id="button-sun"><i class="wi wi-day-sunny"></i></a></li> | |
| </ul> | |
| </nav> | |
| <div id="card" class="weather"> | |
| <svg id="inner"> | |
| <defs> | |
| <path id="leaf" d="M41.9,56.3l0.1-2.5c0,0,4.6-1.2,5.6-2.2c1-1,3.6-13,12-15.6c9.7-3.1,19.9-2,26.1-2.1c2.7,0-10,23.9-20.5,25 c-7.5,0.8-17.2-5.1-17.2-5.1L41.9,56.3z"/> | |
| </defs> | |
| <circle id="sun" style="fill: #F7ED47" cx="0" cy="0" r="50"/> | |
| <g id="layer3"></g> | |
| <g id="cloud3" class="cloud"></g> | |
| <g id="layer2"></g> | |
| <g id="cloud2" class="cloud"></g> | |
| <g id="layer1"></g> | |
| <g id="cloud1" class="cloud"></g> | |
| </svg> | |
| <div class="details"> | |
| <div class="temp">20<span>c</span></div> | |
| <div class="right"> | |
| <div id="date">Monday 22 August</div> | |
| <div id="summary"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <svg id="outer"></svg> | |
| </div> | |
| </div> |
| // 📝 Fetch all DOM nodes in jQuery and Snap SVG | |
| var container = $('.container'); | |
| var card = $('#card'); | |
| var innerSVG = Snap('#inner'); | |
| var outerSVG = Snap('#outer'); | |
| var backSVG = Snap('#back'); | |
| var summary = $('#summary'); | |
| var date = $('#date'); | |
| var weatherContainer1 = Snap.select('#layer1'); | |
| var weatherContainer2 = Snap.select('#layer2'); | |
| var weatherContainer3 = Snap.select('#layer3'); | |
| var innerRainHolder1 = weatherContainer1.group(); | |
| var innerRainHolder2 = weatherContainer2.group(); | |
| var innerRainHolder3 = weatherContainer3.group(); | |
| var innerLeafHolder = weatherContainer1.group(); | |
| var innerSnowHolder = weatherContainer1.group(); | |
| var innerLightningHolder = weatherContainer1.group(); | |
| var leafMask = outerSVG.rect(); | |
| var leaf = Snap.select('#leaf'); | |
| var sun = Snap.select('#sun'); | |
| var sunburst = Snap.select('#sunburst'); | |
| var outerSplashHolder = outerSVG.group(); | |
| var outerLeafHolder = outerSVG.group(); | |
| var outerSnowHolder = outerSVG.group(); | |
| var lightningTimeout; | |
| // Set mask for leaf holder | |
| outerLeafHolder.attr({ | |
| 'clip-path': leafMask | |
| }); | |
| // create sizes object, we update this later | |
| var sizes = { | |
| container: {width: 0, height: 0}, | |
| card: {width: 0, height: 0} | |
| } | |
| // grab cloud groups | |
| var clouds = [ | |
| {group: Snap.select('#cloud1')}, | |
| {group: Snap.select('#cloud2')}, | |
| {group: Snap.select('#cloud3')} | |
| ] | |
| // set weather types ☁️ 🌬 🌧 ⛈ ☀️ | |
| var weather = [ | |
| { type: 'snow', name: 'Snow'}, | |
| { type: 'wind', name: 'Windy'}, | |
| { type: 'rain', name: 'Rain'}, | |
| { type: 'thunder', name: 'Storms'}, | |
| { type: 'sun', name: 'Sunny'} | |
| ]; | |
| // 🛠 app settings | |
| // in an object so the values can be animated in tweenmax | |
| var settings = { | |
| windSpeed: 2, | |
| rainCount: 0, | |
| leafCount: 0, | |
| snowCount: 0, | |
| cloudHeight: 100, | |
| cloudSpace: 30, | |
| cloudArch: 50, | |
| renewCheck: 10, | |
| splashBounce: 80 | |
| }; | |
| var tickCount = 0; | |
| var rain = []; | |
| var leafs = []; | |
| var snow = []; | |
| // ⚙ initialize app | |
| init(); | |
| // 👁 watch for window resize | |
| $(window).resize(onResize); | |
| // 🏃 start animations | |
| requestAnimationFrame(tick); | |
| function init() | |
| { | |
| onResize(); | |
| // 🖱 bind weather menu buttons | |
| for(var i = 0; i < weather.length; i++) | |
| { | |
| var w = weather[i]; | |
| var b = $('#button-' + w.type); | |
| w.button = b; | |
| b.bind('click', w, changeWeather); | |
| } | |
| // ☁️ draw clouds | |
| for(var i = 0; i < clouds.length; i++) | |
| { | |
| clouds[i].offset = Math.random() * sizes.card.width; | |
| drawCloud(clouds[i], i); | |
| } | |
| // ☀️ set initial weather | |
| TweenMax.set(sunburst.node, {opacity: 0}) | |
| changeWeather(weather[0]); | |
| } | |
| function onResize() | |
| { | |
| // 📏 grab window and card sizes | |
| sizes.container.width = container.width(); | |
| sizes.container.height = container.height(); | |
| sizes.card.width = card.width(); | |
| sizes.card.height = card.height(); | |
| sizes.card.offset = card.offset(); | |
| // 📐 update svg sizes | |
| innerSVG.attr({ | |
| width: sizes.card.width, | |
| height: sizes.card.height | |
| }) | |
| outerSVG.attr({ | |
| width: sizes.container.width, | |
| height: sizes.container.height | |
| }) | |
| backSVG.attr({ | |
| width: sizes.container.width, | |
| height: sizes.container.height | |
| }) | |
| TweenMax.set(sunburst.node, {transformOrigin:"50% 50%", x: sizes.container.width / 2, y: (sizes.card.height/2) + sizes.card.offset.top}); | |
| TweenMax.fromTo(sunburst.node, 20, {rotation: 0}, {rotation: 360, repeat: -1, ease: Power0.easeInOut}) | |
| // 🍃 The leaf mask is for the leafs that float out of the | |
| // container, it is full window height and starts on the left | |
| // inline with the card | |
| leafMask.attr({x: sizes.card.offset.left, y: 0, width: sizes.container.width - sizes.card.offset.left, height: sizes.container.height}); | |
| } | |
| function drawCloud(cloud, i) | |
| { | |
| /* | |
| ☁️ We want to create a shape thats loopable but that can also | |
| be animated in and out. So we use Snap SVG to draw a shape | |
| with 4 sections. The 2 ends and 2 arches the same width as | |
| the card. So the final shape is about 4 x the width of the | |
| card. | |
| */ | |
| var space = settings.cloudSpace * i; | |
| var height = space + settings.cloudHeight; | |
| var arch = height + settings.cloudArch + (Math.random() * settings.cloudArch); | |
| var width = sizes.card.width; | |
| var points = []; | |
| points.push('M' + [-(width), 0].join(',')); | |
| points.push([width, 0].join(',')); | |
| points.push('Q' + [width * 2, height / 2].join(',')); | |
| points.push([width, height].join(',')); | |
| points.push('Q' + [width * 0.5, arch].join(',')); | |
| points.push([0, height].join(',')); | |
| points.push('Q' + [width * -0.5, arch].join(',')); | |
| points.push([-width, height].join(',')); | |
| points.push('Q' + [- (width * 2), height/2].join(',')); | |
| points.push([-(width), 0].join(',')); | |
| var path = points.join(' '); | |
| if(!cloud.path) cloud.path = cloud.group.path(); | |
| cloud.path.animate({ | |
| d: path | |
| }, 0) | |
| } | |
| function makeRain() | |
| { | |
| // 💧 This is where we draw one drop of rain | |
| // first we set the line width of the line, we use this | |
| // to dictate which svg group it'll be added to and | |
| // whether it'll generate a splash | |
| var lineWidth = Math.random() * 3; | |
| // ⛈ line length is made longer for stormy weather | |
| var lineLength = currentWeather.type == 'thunder' ? 35 : 14; | |
| // Start the drop at a random point at the top but leaving | |
| // a 20px margin | |
| var x = Math.random() * (sizes.card.width - 40) + 20; | |
| // Draw the line | |
| var line = this['innerRainHolder' + (3 - Math.floor(lineWidth))].path('M0,0 0,' + lineLength).attr({ | |
| fill: 'none', | |
| stroke: currentWeather.type == 'thunder' ? '#777' : '#0000ff', | |
| strokeWidth: lineWidth | |
| }); | |
| // add the line to an array to we can keep track of how | |
| // many there are. | |
| rain.push(line); | |
| // Start the falling animation, calls onRainEnd when the | |
| // animation finishes. | |
| TweenMax.fromTo(line.node, 1, {x: x, y: 0- lineLength}, {delay: Math.random(), y: sizes.card.height, ease: Power2.easeIn, onComplete: onRainEnd, onCompleteParams: [line, lineWidth, x, currentWeather.type]}); | |
| } | |
| function onRainEnd(line, width, x, type) | |
| { | |
| // first lets get rid of the drop of rain 💧 | |
| line.remove(); | |
| line = null; | |
| // We also remove it from the array | |
| for(var i in rain) | |
| { | |
| if(!rain[i].paper) rain.splice(i, 1); | |
| } | |
| // If there is less rain than the rainCount we should | |
| // make more. | |
| if(rain.length < settings.rainCount) | |
| { | |
| makeRain(); | |
| // 💦 If the line width was more than 2 we also create a | |
| // splash. This way it looks like the closer (bigger) | |
| // drops hit the the edge of the card | |
| if(width > 2) makeSplash(x, type); | |
| } | |
| } | |
| function makeSplash(x, type) | |
| { | |
| // 💦 The splash is a single line added to the outer svg. | |
| // The splashLength is how long the animated line will be | |
| var splashLength = type == 'thunder' ? 30 : 20; | |
| // splashBounce is the max height the line will curve up | |
| // before falling | |
| var splashBounce = type == 'thunder' ? 120 : 100; | |
| // this sets how far down the line can fall | |
| var splashDistance = 80; | |
| // because the storm rain is longer we want the animation | |
| // to last slighly longer so the overall speed is roughly | |
| // the same for both | |
| var speed = type == 'thunder' ? 0.7 : 0.5; | |
| // Set a random splash up amount based on the max splash bounce | |
| var splashUp = 0 - (Math.random() * splashBounce); | |
| // Sets the end x position, and in turn defines the splash direction | |
| var randomX = ((Math.random() * splashDistance) - (splashDistance / 2)); | |
| // Now we put the 3 line coordinates into an array. | |
| var points = []; | |
| points.push('M' + 0 + ',' + 0); | |
| points.push('Q' + randomX + ',' + splashUp); | |
| points.push((randomX * 2) + ',' + splashDistance); | |
| // Draw the line with Snap SVG | |
| var splash = outerSplashHolder.path(points.join(' ')).attr({ | |
| fill: "none", | |
| stroke: type == 'thunder' ? '#777' : '#0000ff', | |
| strokeWidth: 1 | |
| }); | |
| // We animate the dasharray to have the line travel along the path | |
| var pathLength = Snap.path.getTotalLength(splash); | |
| var xOffset = sizes.card.offset.left;//(sizes.container.width - sizes.card.width) / 2 | |
| var yOffset = sizes.card.offset.top + sizes.card.height; | |
| splash.node.style.strokeDasharray = splashLength + ' ' + pathLength; | |
| // Start the splash animation, calling onSplashComplete when finished | |
| TweenMax.fromTo(splash.node, speed, {strokeWidth: 2, y: yOffset, x: xOffset + 20 + x, opacity: 1, strokeDashoffset: splashLength}, {strokeWidth: 0, strokeDashoffset: - pathLength, opacity: 1, onComplete: onSplashComplete, onCompleteParams: [splash], ease: SlowMo.ease.config(0.4, 0.1, false)}) | |
| } | |
| function onSplashComplete(splash) | |
| { | |
| // 💦 The splash has finished animating, we need to get rid of it | |
| splash.remove(); | |
| splash = null; | |
| } | |
| function makeLeaf() | |
| { | |
| var scale = 0.5 + (Math.random() * 0.5); | |
| var newLeaf; | |
| var areaY = sizes.card.height/2; | |
| var y = areaY + (Math.random() * areaY); | |
| var endY = y - ((Math.random() * (areaY * 2)) - areaY) | |
| var x; | |
| var endX; | |
| var colors = ['#76993E', '#4A5E23', '#6D632F']; | |
| var color = colors[Math.floor(Math.random() * colors.length)]; | |
| var xBezier; | |
| if(scale > 0.8) | |
| { | |
| newLeaf = leaf.clone().appendTo(outerLeafHolder) | |
| .attr({ | |
| fill: color | |
| }) | |
| y = y + sizes.card.offset.top / 2; | |
| endY = endY + sizes.card.offset.top / 2; | |
| x = sizes.card.offset.left - 100; | |
| xBezier = x + (sizes.container.width - sizes.card.offset.left) / 2; | |
| endX = sizes.container.width + 50; | |
| } | |
| else | |
| { | |
| newLeaf = leaf.clone().appendTo(innerLeafHolder) | |
| .attr({ | |
| fill: color | |
| }) | |
| x = -100; | |
| xBezier = sizes.card.width / 2; | |
| endX = sizes.card.width + 50; | |
| } | |
| leafs.push(newLeaf); | |
| var bezier = [{x:x, y:y}, {x: xBezier, y:(Math.random() * endY) + (endY / 3)}, {x: endX, y:endY}] | |
| TweenMax.fromTo(newLeaf.node, 2, {rotation: Math.random()* 180, x: x, y: y, scale:scale}, {rotation: Math.random()* 360, bezier: bezier, onComplete: onLeafEnd, onCompleteParams: [newLeaf], ease: Power0.easeIn}) | |
| } | |
| function onLeafEnd(leaf) | |
| { | |
| leaf.remove(); | |
| leaf = null; | |
| for(var i in leafs) | |
| { | |
| if(!leafs[i].paper) leafs.splice(i, 1); | |
| } | |
| if(leafs.length < settings.leafCount) | |
| { | |
| makeLeaf(); | |
| } | |
| } | |
| function makeSnow() | |
| { | |
| var scale = 0.5 + (Math.random() * 0.5); | |
| var newSnow; | |
| var x = 20 + (Math.random() * (sizes.card.width - 40)); | |
| var endX; // = x - ((Math.random() * (areaX * 2)) - areaX) | |
| var y = -10; | |
| var endY; | |
| if(scale > 0.8) | |
| { | |
| newSnow = outerSnowHolder.circle(0, 0, 5) | |
| .attr({ | |
| fill: 'white' | |
| }) | |
| endY = sizes.container.height + 10; | |
| y = sizes.card.offset.top + settings.cloudHeight; | |
| x = x + sizes.card.offset.left; | |
| //xBezier = x + (sizes.container.width - sizes.card.offset.left) / 2; | |
| //endX = sizes.container.width + 50; | |
| } | |
| else | |
| { | |
| newSnow = innerSnowHolder.circle(0, 0 ,5) | |
| .attr({ | |
| fill: 'white' | |
| }) | |
| endY = sizes.card.height + 10; | |
| //x = -100; | |
| //xBezier = sizes.card.width / 2; | |
| //endX = sizes.card.width + 50; | |
| } | |
| snow.push(newSnow); | |
| TweenMax.fromTo(newSnow.node, 3 + (Math.random() * 5), {x: x, y: y}, {y: endY, onComplete: onSnowEnd, onCompleteParams: [newSnow], ease: Power0.easeIn}) | |
| TweenMax.fromTo(newSnow.node, 1,{scale: 0}, {scale: scale, ease: Power1.easeInOut}) | |
| TweenMax.to(newSnow.node, 3, {x: x+((Math.random() * 150)-75), repeat: -1, yoyo: true, ease: Power1.easeInOut}) | |
| } | |
| function onSnowEnd(flake) | |
| { | |
| flake.remove(); | |
| flake = null; | |
| for(var i in snow) | |
| { | |
| if(!snow[i].paper) snow.splice(i, 1); | |
| } | |
| if(snow.length < settings.snowCount) | |
| { | |
| makeSnow(); | |
| } | |
| } | |
| function tick() | |
| { | |
| tickCount++; | |
| var check = tickCount % settings.renewCheck; | |
| if(check) | |
| { | |
| if(rain.length < settings.rainCount) makeRain(); | |
| if(leafs.length < settings.leafCount) makeLeaf(); | |
| if(snow.length < settings.snowCount) makeSnow(); | |
| } | |
| for(var i = 0; i < clouds.length; i++) | |
| { | |
| if(currentWeather.type == 'sun') | |
| { | |
| if(clouds[i].offset > -(sizes.card.width * 1.5)) clouds[i].offset += settings.windSpeed / (i + 1); | |
| if(clouds[i].offset > sizes.card.width * 2.5) clouds[i].offset = -(sizes.card.width * 1.5); | |
| clouds[i].group.transform('t' + clouds[i].offset + ',' + 0); | |
| } | |
| else | |
| { | |
| clouds[i].offset += settings.windSpeed / (i + 1); | |
| if(clouds[i].offset > sizes.card.width) clouds[i].offset = 0 + (clouds[i].offset - sizes.card.width); | |
| clouds[i].group.transform('t' + clouds[i].offset + ',' + 0); | |
| } | |
| } | |
| requestAnimationFrame(tick); | |
| } | |
| function reset() | |
| { | |
| for(var i = 0; i < weather.length; i++) | |
| { | |
| container.removeClass(weather[i].type); | |
| weather[i].button.removeClass('active'); | |
| } | |
| } | |
| function updateSummaryText() | |
| { | |
| summary.html(currentWeather.name); | |
| TweenMax.fromTo(summary, 1.5, {x: 30}, {opacity: 1, x: 0, ease: Power4.easeOut}); | |
| } | |
| function startLightningTimer() | |
| { | |
| if(lightningTimeout) clearTimeout(lightningTimeout); | |
| if(currentWeather.type == 'thunder') | |
| { | |
| lightningTimeout = setTimeout(lightning, Math.random()*6000); | |
| } | |
| } | |
| function lightning() | |
| { | |
| startLightningTimer(); | |
| TweenMax.fromTo(card, 0.75, {y: -30}, {y:0, ease:Elastic.easeOut}); | |
| var pathX = 30 + Math.random() * (sizes.card.width - 60); | |
| var yOffset = 20; | |
| var steps = 20; | |
| var points = [pathX + ',0']; | |
| for(var i = 0; i < steps; i++) | |
| { | |
| var x = pathX + (Math.random() * yOffset - (yOffset / 2)); | |
| var y = (sizes.card.height / steps) * (i + 1) | |
| points.push(x + ',' + y); | |
| } | |
| var strike = weatherContainer1.path('M' + points.join(' ')) | |
| .attr({ | |
| fill: 'none', | |
| stroke: 'white', | |
| strokeWidth: 2 + Math.random() | |
| }) | |
| TweenMax.to(strike.node, 1, {opacity: 0, ease:Power4.easeOut, onComplete: function(){ strike.remove(); strike = null}}) | |
| } | |
| function changeWeather(weather) | |
| { | |
| if(weather.data) weather = weather.data; | |
| reset(); | |
| currentWeather = weather; | |
| TweenMax.killTweensOf(summary); | |
| TweenMax.to(summary, 1, {opacity: 0, x: -30, onComplete: updateSummaryText, ease: Power4.easeIn}) | |
| container.addClass(weather.type); | |
| weather.button.addClass('active'); | |
| // windSpeed | |
| switch(weather.type) | |
| { | |
| case 'wind': | |
| TweenMax.to(settings, 3, {windSpeed: 3, ease: Power2.easeInOut}); | |
| break; | |
| case 'sun': | |
| TweenMax.to(settings, 3, {windSpeed: 20, ease: Power2.easeInOut}); | |
| break; | |
| default: | |
| TweenMax.to(settings, 3, {windSpeed: 0.5, ease: Power2.easeOut}); | |
| break; | |
| } | |
| // rainCount | |
| switch(weather.type) | |
| { | |
| case 'rain': | |
| TweenMax.to(settings, 3, {rainCount: 10, ease: Power2.easeInOut}); | |
| break; | |
| case 'thunder': | |
| TweenMax.to(settings, 3, {rainCount: 60, ease: Power2.easeInOut}); | |
| break; | |
| default: | |
| TweenMax.to(settings, 1, {rainCount: 0, ease: Power2.easeOut}); | |
| break; | |
| } | |
| // leafCount | |
| switch(weather.type) | |
| { | |
| case 'wind': | |
| TweenMax.to(settings, 3, {leafCount: 5, ease: Power2.easeInOut}); | |
| break; | |
| default: | |
| TweenMax.to(settings, 1, {leafCount: 0, ease: Power2.easeOut}); | |
| break; | |
| } | |
| // snowCount | |
| switch(weather.type) | |
| { | |
| case 'snow': | |
| TweenMax.to(settings, 3, {snowCount: 40, ease: Power2.easeInOut}); | |
| break; | |
| default: | |
| TweenMax.to(settings, 1, {snowCount: 0, ease: Power2.easeOut}); | |
| break; | |
| } | |
| // sun position | |
| switch(weather.type) | |
| { | |
| case 'sun': | |
| TweenMax.to(sun.node, 4, {x: sizes.card.width / 2, y: sizes.card.height / 2, ease: Power2.easeInOut}); | |
| TweenMax.to(sunburst.node, 4, {scale: 1, opacity: 0.8, y: (sizes.card.height/2) + (sizes.card.offset.top), ease: Power2.easeInOut}); | |
| break; | |
| default: | |
| TweenMax.to(sun.node, 2, {x: sizes.card.width / 2, y: -100, leafCount: 0, ease: Power2.easeInOut}); | |
| TweenMax.to(sunburst.node, 2, {scale: 0.4, opacity: 0, y: (sizes.container.height/2)-50, ease: Power2.easeInOut}); | |
| break; | |
| } | |
| // lightning | |
| startLightningTimer(); | |
| } |
| <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script> | |
| <script src="https://codepen.io/steveg3003/pen/zBVakw.js"></script> |
| @import 'https://fonts.googleapis.com/css?family=Lato:300'; | |
| @import 'https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons.min.css'; | |
| $speed: 2s; | |
| html, body, .background | |
| { | |
| width: 100%; | |
| height: 100%; | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Lato', sans-serif; | |
| } | |
| html | |
| { | |
| background: #fff; | |
| } | |
| body | |
| { | |
| background: #eee; | |
| background: linear-gradient(0deg, rgba(0, 0, 200, 0.2) , rgba(0, 0, 200, 0) ); | |
| } | |
| .background | |
| { | |
| background: #eee; | |
| background: linear-gradient(120deg, rgba(50, 150, 100, 0.2) , rgba(0, 0, 100, 0) ); | |
| } | |
| .container | |
| { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| margin: 0; | |
| padding: 0; | |
| height: 100%; | |
| width: 100%; | |
| overflow: auto; | |
| position: relative; | |
| background: #eee; | |
| background: linear-gradient(240deg, rgba(150, 50, 50, 0.3) , rgba(0, 0, 200, 0) ); | |
| &.cloud | |
| { | |
| //background: linear-gradient(360deg, rgba(50, 50, 50, 0.5) , rgba(0, 0, 200, 0) ); | |
| } | |
| &.wind | |
| { | |
| } | |
| } | |
| nav | |
| { | |
| ul | |
| { | |
| margin: 20px 20px 0 20px; | |
| list-style-type: none; | |
| padding: 0; | |
| display: flex; | |
| flex-direction: row; | |
| } | |
| li a | |
| { | |
| display: block; | |
| width: 50px; | |
| text-align: center; | |
| color: #aaa; | |
| cursor: pointer; | |
| &:hover | |
| { | |
| color: #444; | |
| } | |
| &.active | |
| { | |
| color: #4444ff; | |
| } | |
| } | |
| } | |
| #card | |
| { | |
| //background: #fff; | |
| box-shadow: 9px 7px 40px -6px rgba(0,0,0,0.25); | |
| overflow: hidden; | |
| width: 300px; | |
| padding: 0; | |
| height: 400px; | |
| min-height: 300px; | |
| margin: 20px; | |
| border-radius: 5px; | |
| //border: solid 0px #fff; | |
| position: relative; | |
| .details | |
| { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| padding: 16px 20px; | |
| color: #888; | |
| display: flex; | |
| flex-direction: row; | |
| justify-content: space-between; | |
| transition: color $speed ease; | |
| .thunder & | |
| { | |
| color: #ddd; | |
| } | |
| .right | |
| { | |
| text-align: right; | |
| } | |
| #date | |
| { | |
| margin: 4px 0; | |
| } | |
| #summary | |
| { | |
| font-weight: 600; | |
| font-size: 22px; | |
| } | |
| .temp | |
| { | |
| font-size: 60px; | |
| line-height: 60px; | |
| span | |
| { | |
| font-size: 18px; | |
| line-height: 30px; | |
| vertical-align: top; | |
| margin-left: 5px; | |
| } | |
| } | |
| } | |
| } | |
| .weather | |
| { | |
| background-color: #DAE3FD; | |
| transition: background-color $speed ease; | |
| .thunder & | |
| { | |
| background-color: #9FA4AD; | |
| } | |
| .rain & | |
| { | |
| background-color: #D8D8D8; | |
| } | |
| .sun & | |
| { | |
| background-color: #ccccff; | |
| } | |
| #inner | |
| { | |
| background-color: rgba(255,255,255,1); | |
| background: linear-gradient(to bottom, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%); | |
| } | |
| .cloud | |
| { | |
| transition: fill $speed ease; | |
| } | |
| #cloud1 | |
| { | |
| fill: #efefef; | |
| .thunder & | |
| { | |
| fill: #9FA4AD; | |
| } | |
| } | |
| #cloud2 | |
| { | |
| fill: #E6E6E6; | |
| .thunder & | |
| { | |
| fill: #8B8E98; | |
| } | |
| } | |
| #cloud3 | |
| { | |
| fill: #D5D5D5; | |
| .thunder & | |
| { | |
| fill: #7B7988; | |
| } | |
| } | |
| } | |
| #outer, #back | |
| { | |
| position: fixed; | |
| pointer-events: none; | |
| } |