Tag: Realistic

How to Create a Realistic Motion Blur with CSS Transitions

Before we delve into making a realistic motion blur in CSS, it’s worth doing a quick dive into what motion blur is, so we can have a better idea of what we’re trying to reproduce.

Have you ever taken a photo of something moving quickly, especially under low light, and it turned into a blurry streak? Or maybe the whole camera shook and the whole shot became a series of streaks? This is motion blur, and it’s a byproduct of how a camera works.

Motion Blur 101

Imagine a camera. It’s got a shutter, a door that opens to let light in, and then closes to stop the light from coming in. From the time it opens, to when it closes, is a single photograph, or a single frame of a moving image.

A blurry man wearing a red shirt on a blue bike speeding through the forest.
Real motion blur in action (Photo: Kevin Erdvig, Unsplash)

If the subject of the frame is moving during the time the shutter is open, we end up taking a photo of an object moving through the frame. On film, this shows up as being a steady smear, with the subject being in an infinite number of places between its starting point to its end. The moving object also ends up being semi-transparent, with parts of the background visible behind it.

What computers do to fake this is model several subframes, and then composite them together at a fraction of the opacity. Putting lots of copies of the same object in slightly different places along the path of motion creates a pretty convincing facsimile of a motion blur.

Video compositing apps tend to have settings for how many subdivisions their motion blur should have. If you set this value really low, you can see exactly how the technique works, like this, a frame of an animation of a simple white dot at four samples per frame:

Four overlapping white opaque circles on a black background.
Four samples per frame.
Twelve overlapping white opaque circles on a black background.
Here is 12 samples per frame.
Thirty-two overlapping white opaque circles on a black background.
And by the time we’re at 32 samples per frame, it’s pretty close to fully real, especially when seen at multiple frames per second.

The number of samples it takes to make a convincing motion blur is entirely relative to the content. Something small with sharp edges that’s moving super fast will need a lot of subframes; but something blurry moving slowly might need only a few. In general, using more will create a more convincing effect.

Doing this in CSS

In order to approximate this effect in CSS, we need to create a ton of identical elements, make them semi-transparent, and offset their animations by a tiny fraction of a second.

First, we’ll set up the base with the animation we want using a CSS transition. We’ll go with a simple black dot, and assign it a transform on hover (or tap, if you’re on mobile). We’ll also animate the border radius and color to show the flexibility of this approach.

Here is the base animation without motion blur:

Now, let’s make 20 identical copies of the black dot, all placed in the exact same place with absolute positioning. Each copy has an opacity of 10%, which is a little more than might be mathematically correct, but I find we need to make them more opaque to look solid enough.

The next step is where the magic happens. We add a slightly-increasing transition-delay value for each clone of our dot object. They’ll all run the exact same animation, but they’ll each be offset by three milliseconds. 

The beauty of this approach is that it creates a pseudo-motion blur effect that works for a ton of different animations. We can throw color changes on there, scaling transitions, odd timings, and the motion blur effect still works.

Using 20 object clones will work for plenty of fast and slow animations, but fewer can still produce a reasonable sense of motion blur. You may need to tweak the number of cloned objects, their opacity, and the amount of transition delay to work with your particular animation. The demo we just looked at has the blur effect slightly overclocked to make it more prominent.


Eventually, with the progress of computer power, I expect that some of the major browsers might start offering this effect natively. Then we can do away with the ridiculousness of having 20 identical objects. In the meantime, this is a reasonable way to approximate a realistic motion blur.


The post How to Create a Realistic Motion Blur with CSS Transitions appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,

Making a Realistic Glass Effect with SVG

I’m in love with SVG. Sure, the code can look dense and difficult at first, but you’ll see the beauty in the results when you get to know it. The bonus is that those results are in code, so it can be hooked up to a CMS. Your designers can rest easy knowing they don’t have to reproduce an effect for every article or product on your site.

Today I would like to show you how I came up with this glass text effect.

The word Kyoto that is translucent and stacked on top an image of the city.

Step 0: Patience and space

SVG can be a lot to take on, especially when you’re just starting to learn it (and if you are, Chris’ book is a good place to start). It’s practically a whole new language and, especially for people who lack design chops, there are lots of new techniques and considerations to know about. Like HTML, though, you’ll find there are a handful of tools that we can reach for to help make SVG much easier to grasp., so be patient and keep trying!

Also, give yourself space. Literally. SVG code is dense so I like to use two or three new lines to space things out. It makes the code easier to read and helps me see how different pieces are separated with less visual distraction. Oh, and use comments to mark where you are in the document, too. That can help organize your thoughts and document your findings.

I’ve made demos for each step we’re going to cover in the process of learning this glass effect as a way to help solidify the things we’re covering as we go.

OK, now that we’re mentally prepared, let’s get into the meat of it!

Step 1: Get the basic image in place

First things first: we need an image as the backdrop for our glass effect. Here we have an <svg> element and an <image> within it. This is similar to adding an <img> in HTML. You’ll notice the dimensions of the viewBox attribute and <image> element in the SVG element are the same. This ensures that the <image> is exactly the same size as the actual picture we’re linking to.

That’s a key distinction to note: we’re linking to an image. The SVG file itself does not draw a raster image, but we can reference one in the SVG code and make sure that asset is in the location we point to. If you’ve worked with Adobe InDesign before, it’s a lot like linking to an image asset in a layout — the image is in the InDesign layout, but the asset itself actually lives somewhere else.

See the Pen
SVG Glass Text Effect – basic image in place
by David Fitzgibbon (@loficodes)
on CodePen.

Step 2: Distort the image

Straightforward so far, but this is where things get complicated because we’re going to add a filter to the image we just inserted. This filter is going to distort the image. If you look closely at the difference between the demo in the last step and the one in this step, you’ll see that the edges of objects in the image are a little rough and wavy. That’s the filter at work!

First, we create another <svg> to hold filter. This means that if we ever want to reuse our filter — for example on multiple elements on the page — then we totally can!

Our first filter (#displacement) is going to distort our image. We’re going to use feTurbulence and feDisplacementMap, each explained by Sara Soueidan much better than I can in this post. Beau Jackson also wrote up a nice piece that shows how they can be used to make a cloud effect. Suffice to say, these two filters tend to go together and I like to think of them as when something needs to appear “wobbly.”

With our filter container in place, we just need to apply that filter to our image with a filter attribute on the <image>, magic!

<svg>    <!-- more stuff -->      <!-- DISTORTION IMAGE: clipped -->   <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 clip-path="url(#clip)" filter= "url(#distortion)"></image>      <!-- FILTER: wobbly effect -->   <filter id="distortion">     <feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="2" result="turbulence"/>     <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="20" xChannelSelector="R" yChannelSelector="G"/>   </filter>    <!-- more stuff -->  </svg>

See the Pen
SVG Glass Text Effect – image distorted
by David Fitzgibbon (@loficodes)
on CodePen.

Step 3: Clip the text

We don’t want the entire image to be distorted though. We’re going to clip the shape of our distorted <image> to the shape of some text. This will essentially be the portion of the picture seen “through” the glass.

To do this, we need to add a <text> element in a <clip-path> and give it an id. Calling this id in the clip-path of our <image> now restricts its shape to that of our <text>. Wonderful!

See the Pen
SVG Glass Text Effect – text clipped
by David Fitzgibbon (@loficodes)
on CodePen.

Step 4: Reveal the full image

OK, so it’s bueno that we have the distorted <image> clipped to the <text>, but now the rest of the image is gone. No bueno.

We can counteract this by adding a copy of the same <image> but without the clip-path or filter attributes before our existing <image>. This is where I like to add some nice comments to keep things neat. The idea is like placing a transparent layer over what we have so far.

Illustration showing one image overlaid on the other.

I know, I know, this isn’t very neat, and we’re repeating ourselves. Ideally, we would set our filter straight on the <text> element and use the in="BackgroundImage property for feDisplacementMap to warp what’s behind the text, without the need for extra elements. Unfortunately, this has poor browser support, so we’re going to go with multiple images.

<svg>    <!-- more stuff -->    <!-- BACKGROUND IMAGE - visible -->   <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 ></image>              <!-- DISTORTION IMAGE - clipped -->   <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 clip-path="url(#clip)" filter= "url(#distortion)"></image>    <!-- more stuff -->  </svg>

See the Pen
SVG Glass Text Effect – warp complete
by David Fitzgibbon (@loficodes)
on CodePen.

Step 5: Place the text… again

Next, we’re going to duplicate our text just as we did for the image in the last step. Unfortunately, because the text is in a clip-path, it’s now not available for rendering. This is the last time we’re going to duplicate content like this, I promise!

Now we should have something that looks like a normal image with black text over it. If the distortion filter on the <image> we’ve already made is what we can see “through” the glass, then our new <text> is going to be the glass itself.

<svg>    <!-- more stuff -->    <!-- TEXT - clipped -->   <clipPath id="clip">     <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle">KYOTO</text>   </clipPath>            <!-- TEXT - visible -->   <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle">KYOTO</text>  <!-- more stuff -->  </svg>

See the Pen
SVG Glass Text Effect – text in place again
by David Fitzgibbon (@loficodes)
on CodePen.

Step 6: Creating the dark edge of the text

This is where things start to get exciting, at least for me! 🤓

We want to create a dark edge along the text element which, when paired with a light edge (we’ll look at that next), will add depth to the appearance of the text against the image.

We want a new filter for our <text>, so let’s create one in our filter’s SVG element and give it an id="textFilter and link it to the filter attribute of the <text> element.

SVG works from the background to the foreground, so the first thing we’re going put in our filter is the shadow that the glass would have, as that is furthest back. I’m gonna level with you, this one is pretty complex, but we’re going to go through it one step at a time.

For this effect, we’re using four filter primitives: feMorphology, feOffset, feFlood and feComposite.

feMorphology is first. We’re using this to make the text fatter. In the demo below, comment out the next three primitives ( feOffset, feFlood, feComposite ) and play with it. I have the value radius="4" to achieve the glass effect, but see what happens if you set it to 1… or 100!

feOffset is used to move all the “pixels” in the previous primitive ( feMorphology ) across the x- or y-axis. The values dx="5" and dy="5" move the “pixels” right on the x-axis and y-axis, respectively. The higher the number, the further they move. Put in negative numbers for dx and the “pixels” will move left. Negative dy and they’ll move up! Again, the is the sort of thing you start to learn as you play around with them.

The reason I have quotes around “pixels” is because they’re not screen pixels like you might expect in CSS. Rather, they refer to the dimensions we set on the parent <svg>. I think of them as percentages. We have used these settings viewBox="0 0 1890 1260" in our example. This means our <svg> is 1890 “pixels” wide. If we set dx="189" it means we’ll move our element 10% of the way across the SVG (1890 divided by 189).

feFlood is great. If you want to fill the screen with color, this is the primitive you need! You might wonder why we can’t read our text now when we apply it. That’s because you can only see the result of the last filter primitive that was created. The result of each of the previous primitives was related to our <text> element. The result of feFlood is just like its name: a flood of color. It doesn’t know what you did before and it doesn’t care — it’s merely going to fill an area with color.

This is where some people start getting frustrated with SVG. It’s hard to work on something when you can’t see it! Trust me, as you work with SVG more you’ll get used to this. In fact, the next few steps will need us to rely on this and trust that everything is still in place.

feComposite is going to solve this issue for us. What does it do? MDN describes it as:

The SVG filter primitive performs the combination of two input images pixel-wise in image space using one of the Porter-Duff compositing operations: over, in, atop, out, xor, and lighter.

That to me is jibba-jabba. I think of it as affecting the alpha layer of in with the color/alpha of in2.

With this in place we can once again see our text spelled out and, because the color we used is slightly transparent, we can even see the distorted “glass” effect coming through. Great!

<svg>    <!-- more stuff -->        <!-- dark edge -->   <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="dark_edge_01" />     <feConvolveMatrix order="3,3" kernelMatrix=       "1 0 0        0 1 0       0 0 1" in="dark_edge_01" result="dark_edge_02" />     <feOffset dx="5" dy="5" in="dark_edge_02" result="dark_edge_03"/>     <feFlood flood-color="rgba(0,0,0,.5)" result="dark_edge_04" />     <feComposite in="dark_edge_04" in2="dark_edge_03" operator="in" result="dark_edge" />        </filter>    <!-- more stuff -->  </svg>

See the Pen
SVG Glass Text Effect – dark edge
by David Fitzgibbon (@loficodes)
on CodePen.

Step 7: Let’s do the light edge

This is essentially the same as what we literally just did, but we’re going to shift the shape up and to the left using negative dx/dy values. We’re also setting a slightly white color this time. We’re aiming for a nice depth effect.

We’re again in a position where what we can see is the most recent result from a filter primitive, but we can’t see our dark edge! feComposite isn’t what we want to use to bring them together because we don’t want the alpha of the dark edge colored by the light edge… we want to see both! Which leads us to…

<svg>   <filter id="textFilter">      <!-- more stuff -->        <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="light_edge_01" />       <feConvolveMatrix order="3,3" kernelMatrix=       "1 0 0          0 1 0         0 0 1" in="light_edge_01" result="light_edge_02" />       <feOffset dx="-2" dy="-2" in="light_edge_02" result="light_edge_03"/>       <feFlood flood-color="rgba(255,255,255,.5)" result="light_edge_04" />       <feComposite in="light_edge_04" in2="light_edge_03" operator="in" result="light_edge" />      <!-- more stuff -->      </filter> </svg>

See the Pen
SVG Glass Text Effect – light edge
by David Fitzgibbon (@loficodes)
on CodePen.

Step 8: Combine the edges

feMerge! It’s a hero. It lets us take any number of primitive results and merge them, making a new image. Woohoo, we can now see both dark and light edges together!

However, we do want them to be edges rather than both filling up the entire text, so we need to remove the space that the original <text> takes up. What we need next is another feComposite to chop out the original SourceGraphic. Because we used feMorphology to fatten the letters for our edges, we can now chop the original letter shapes out of the result of our feMerge.

<svg>   <filter id="textFilter">      <!-- more stuff -->      <feMerge result="edges">       <feMergeNode in="dark_edge" />       <feMergeNode in="light_edge" />     </feMerge>     <feComposite in="edges" in2="SourceGraphic" operator="out" result="edges_complete" />    </filter> </svg>

See the Pen
SVG Glass Text Effect – edges combined
by David Fitzgibbon (@loficodes)
on CodePen.

Now we’re starting to look like glass, with just one piece missing.

Step 9: Yes, a bevel

We have a pretty good 3D-looking glass effect. However, the letters look flat. Let’s add one more effect and make them look more rounded.

To achieve this we’re going to create a bevelled effect.

First we’re going to use feGaussianBlur. This will blur our existing filters slightly. We’re going to use this blurred result as basis to add some feSpecularLighting. As usual, feel free to play with the numbers here and see what effects you can get! The main one you might want to change is the lighting-color attribute. The image that we’re using here is slightly dark, so we’re using a bright lighting-color. If your image was very bright, this would make the letters hard to read, so you might use a darker lighting-color in that case.

<svg>   <filter id="textFilter">        <!-- more stuff -->      <feGaussianBlur stdDeviation="5" result="bevel_blur" />     <feSpecularLighting result="bevel_lighting" in="bevel_blur" specularConstant="2.4" specularExponent="13" lighting-color="rgba(60,60,60,.4)">       <feDistantLight azimuth="25" elevation="40" />     </feSpecularLighting>     <feComposite in="bevel_lighting" in2="SourceGraphic" operator="in" result="bevel_complete" />    </filter> </svg>

See the Pen
SVG Glass Text Effect – bevel
by David Fitzgibbon (@loficodes)
on CodePen.

Step 10: All together now!

Finally, with all the pieces ready, we do one last feMerge to get everything in place for the finished effect!

<svg>   <filter id="textFilter">      <!-- more stuff -->      <feMerge result="complete">       <feMergeNode in="edges_complete" />       <feMergeNode in="bevel_complete" />     </feMerge>   </filter> </svg>

Here’s everything together, nicely spaced out and commented:

<!-- VISIBLE SVG --> <svg viewBox="0 0 1890 1260">            <!-- BACKGROUND IMAGE - visible -->   <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 ></image>        <!-- DISTORTION IMAGE - clipped -->   <image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/5946/kyoto.jpg" width="1890" x=0 height="1260" y=0 clip-path="url(#clip)" filter= "url(#distortion)"></image>        <!-- TEXT - clipped -->   <clipPath id="clip">     <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle">KYOTO</text>   </clipPath>        <!-- TEXT - visible -->   <text x="50%" y ="50%" dominant-baseline="middle" text-anchor="middle" filter="url(#textFilter)">KYOTO</text>      </svg>  <!-- FILTERS --> <svg>   <filter id="distortion">     <feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="2" result="turbulence"/>     <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="20" xChannelSelector="R" yChannelSelector="G"/>   </filter>        <filter id="textFilter">                  <!-- dark edge -->     <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="dark_edge_01" />     <feOffset dx="5" dy="5" in="dark_edge_01" result="dark_edge_03"/>     <feFlood flood-color="rgba(0,0,0,.5)" result="dark_edge_04" />     <feComposite in="dark_edge_04" in2="dark_edge_03" operator="in" result="dark_edge" />                       <!-- light edge -->     <feMorphology operator="dilate" radius="4" in="SourceAlpha" result="light_edge_01" />     <feOffset dx="-2" dy="-2" in="light_edge_01" result="light_edge_03"/>     <feFlood flood-color="rgba(255,255,255,.5)" result="light_edge_04" />     <feComposite in="light_edge_04" in2="light_edge_03" operator="in" result="light_edge" />                <!-- edges together -->     <feMerge result="edges">       <feMergeNode in="dark_edge" />       <feMergeNode in="light_edge" />     </feMerge>     <feComposite in="edges" in2="SourceGraphic" operator="out" result="edges_complete" />                <!-- bevel -->     <feGaussianBlur stdDeviation="5" result="bevel_blur" />     <feSpecularLighting result="bevel_lighting" in="bevel_blur" specularConstant="2.4" specularExponent="13" lighting-color="rgba(60,60,60,.4)">       <feDistantLight azimuth="25" elevation="40" />     </feSpecularLighting>     <feComposite in="bevel_lighting" in2="SourceGraphic" operator="in" result="bevel_complete" />      <!-- everything in place -->     <feMerge result="complete">               <feMergeNode in="edges_complete" />               <feMergeNode in="bevel_complete" />     </feMerge>    </filter> </svg>

See the Pen
SVG Glass Text Effect
by David Fitzgibbon (@loficodes)
on CodePen.

The post Making a Realistic Glass Effect with SVG appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Drawing Realistic Clouds with SVG and CSS

Greek mythology tells the story of Zeus creating the cloud nymph, Nephele. Like other Greek myths, this tale gets pretty bizarre and X-rated. Here’s a very abridged, polite version.

Nephele, we are told, was created by Zeus in the image of his own beautiful wife. A mortal meets Nephele, falls in love with her and, together, they take an adult nap™. Finally, in a strange twist, the cloud gives birth to half-human half-horse Centaur babies.

Weird, right? Personally, I can’t make heads or tails of it. Thankfully, the process for creating clouds in the browser is much more straightforward and far less risqué.

Yuan Chuan’s clouds detail. (Demo)

Recently, I discovered that developer Yuan Chuan has realized code-generated, photorealistic clouds. For me, this notion in the browser had long been the stuff of myth.

With one glance at the code in this pen we can imagine that convincing individual clouds are achievable through the use of CSS box-shadow with a <filter> element containing two SVG filters as its complement.

The photorealism we want is achieved with a delicate mix of feTurbulence and feDisplacementMap. These SVG filters are powerful, complex and offer very exciting features (including an Oscar winning algorithm)! However, under the hood, their complexity can be a bit intimidating.

While the physics of SVG filters is beyond the scope of this article, there is ample documentation available on MDN and w3.org. A very informative page on feTurbulence and feDisplacement is freely available (and offered as a chapter of this amazing book).

For this article, we will focus on learning to use these SVG filters to get spectacular results. We don’t need to delve too deeply into what is happening behind the scenes algorithmically, much in the way an artist isn’t required know the molecular structure of paint to render a stunning landscape.

Instead, let’s pay close attention to small handful of SVG attributes that are essential for drawing convincing clouds in the browser. Their use will enable us to bend these powerful filters to our will and learn how to customize them with precision in our own projects.

Let’s start with some basics

The CSS box-shadow property has five values that deserve close attention:

box-shadow: <offsetX> <offsetY> <blurRadius> <spreadRadius> <color>;

Let’s crank these values up (probably higher than what any sane developer would so that this shadow becomes a player on the stage in its own right.

(Demo)
#cloud-square {   background: turquoise;   box-shadow: 200px 200px 50px 0px #000;   width: 180px;   height: 180px; }  #cloud-circle {   background: coral;   border-radius: 50%;   box-shadow: 200px 200px 50px 0px #000;   width: 180px;   height: 180px; }

You’ve either made or seen shadow puppets, right?

Credit: Double-M

In the same way that a hand changes shape to alter the shadow, a “source shape” in the our HTML can move and morph to move and alter the shape of a shadow rendered in the browser. box-shadow duplicates the “morphing” features on the original size and border-radius. SVG filters get applied to both the element and its shadow.

<svg width="0" height="0">    <filter id="filter">     <feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="10" />     <feDisplacementMap in="SourceGraphic" scale="10" />   </filter> </svg>

This is the markup for our SVG so far. It won’t render because we haven’t defined anything visual (not to mention the zero width and height). It’s sole purpose is to hold a filter that we feed our SourceGraphic (aka our <div>). Our source <div> and its shadow are both being distorted independently by the filter.

We’ll add the essential CSS rule linking the HTML element (`#cloud-circle`) to the SVG filter using its ID:

#cloud-circle {   filter: url(#filter);   box-shadow: 200px 200px 50px 0px #fff; }

Et Voilà!

OK, so admittedly, adding the SVG filter is pretty underwhelming.

(Demo)

No worries! We have only just scratched the surface and have a lot more good stuff to look at.

Experimenting with the feDisplacementMap scale attribute

A few un-scientific experiments with this one attribute can yield dramatic results. For the moment, let’s keep the all values in feTurbulence constant and simply adjust the scale attribute of DisplacementMap.

As scale increases (by increments of 30) our source <div> becomes distorted and casts a shadow to mirror the stochastic form in which clouds appear in the sky.

<feDisplacementMap in="SourceGraphic" scale="180"/>
The scale attribute incremented by values of 30. (Demo)

OK, we’re getting somewhere! Let’s change the colors a bit to produce a more convincing cloud and to “sell” the effect.

body {   background: linear-gradient(165deg, #527785 0%, #7FB4C7 100%); }  #cloud-circle {     width: 180px;     height: 180px;     background: #000;     border-radius: 50%;     filter: url(#filter);     box-shadow: 200px 200px 50px 0px #fff; }

Now we’re getting closer to a realistic cloud effect!

Modifying the box-shadow blur value

The following suite of images shows the influence that the blur value has on box-shadow. Here, blur is increased by 10 pixels incrementally.

The cloud becomes “softer” as the blur value increases.

To give our cloud a bit of a cumulus-like effect, we can widen our source <div> a bit.

#cloud-circle {   width: 500px;   height: 275px;   background: #000;   border-radius: 50%;   filter: url(#filter);   box-shadow: 200px 200px 60px 0px #fff; }
Great, now the source element is getting in the way. 😫

Wait! We’ve widened the source element and now it’s in the way of our of the white shadow we’re calling a cloud. Let’s “re-cast” the shadow at a greater distance so that our cloud is no longer obscured by the source image. (Think of this as moving your hand away further from the wall so it doesn’t block the view of your shadow puppet.)

This is nicely achieved with a bit of CSS positioning. The <body> is the parent element for our cloud, which is statically positioned by default. Let’s “tuck” our source <div> up and out of the way with some absolute positioning. Initially, that will reposition our shadow as well, so we’ll also need to increase the distance of the shadow from the element and nudge the element a bit more.

#cloud-circle {   width: 500px;   height: 275px;   background: #000;   border-radius: 50%;   filter: url(#filter);   box-shadow: 400px 400px 60px 0px #fff; /* Increase shadow offset */   position: absolute; /* Take the parent out of the document flow */   top: -320px; /* Move a little down */   left: -320px; /* Move a little right */ }

Yes! We’ve arrived at a pretty persuasive cloud.

See the Pen
by Beau Haus (@beauhaus)
on CodePen.

What is painted to the browser is a pretty decent depiction of a cloud–But, I’m not sure…does this cloud really do justice the cloud nymph, Nephele? I’m sure we can do better!

Conveying depth with layers

Here’s what we want:

A photo of clouds against a blue sky. The clouds have shades of gray that provide depth.
Credit: pcdazero

From the look of the depth, texture and richness of the clouds in this photograph, one thing is clear: Zeus went to art school. At the very least, he must have read the The Universal Principles of Design which illustrates a powerful–yet, deceptively ordinary–concept:

[…] lighting bias plays a significant role in the interpretation of depth and naturalness, and can be manipulated in a variety of ways by designers…Use the level of contrast between light and dark areas to vary the appearance of depth.

This passage provides for us a hint as to how to we can vastly improve our own code-generated cloud. We can render our cloud with a good deal of fidelity to the clouds in our reference image by stacking layers of differing form, size and color on top of each other. All that takes is calling our filter as many times as we want layers.

<svg width="0" height="0">     <!-- Back Layer -->     <filter id="filter-back">       <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" />       <feDisplacementMap  in="SourceGraphic" scale="170" />     </filter>     <!-- Middle Layer -->     <filter id="filter-mid">       <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" />       <feDisplacementMap  in="SourceGraphic" scale="150" />     </filter>     <!-- Front Layer -->     <filter id="filter-front">       <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" />       <feDisplacementMap  in="SourceGraphic" scale="100" />     </filter> </svg>

Applying our layers will afford us an opportunity to explore feTurbulence and realize its versatility. We’ll choose the smoother type available to us: fractalNoise with numOctaves cranked up to 6.

<feTurbulence type="fractalNoise" baseFrequency="n" numOctaves="6"/>

What does all that mean? For now, let’s focus specifically on the baseFrequency attribute. Here’s what we get as we increase the value of n:

The lower the value, the rounder and fuzzier we get. The higher the value, the rounder and more rigid we get.

Words like turbulence, noise, frequency, and octave may seem odd and even confusing. But fear not! It’s actually perfectly accurate to analogize this filter’s effects to sound waves. We may equate a low frequency (baseFrequency=0.001) with a low, muffled noise and a rising frequency (baseFrequency=0.1) with a higher, crisper pitch.

We can see that our sweet spot for a cumulus-like effect may lie comfortably around the ~0.005 and ~0.01 range for the baseFrequency.

Adding detail with numOctaves

Incrementing numOctaves allows us to render our image in extremely granular detail. This requires a great deal of calculation, so be warned: high values are a significant performance hit. Try to resist the temptation to pump up this value unless your browser is wearing a helmet and knee-pads.

The higher the value we put into numOctaves the more granular detail give to our cloud.

The good news is that we don’t have to crank this value too high in order to produce detail and delicacy. As the array of images above shows, we can satisfy ourselves with a numOctavesvalue of 4 or 5.

Here’s the result

See the Pen
by Beau Haus (@beauhaus)
on CodePen.

Infinite variety with the seed attribute

There is much to say about the seed attribute as it offers a hint into the magic happening behind the scenes. But, for our purposes, the utility of seed can be reduced to four words: “different value, different shape.”

The Perlin Noise function (mentioned earlier) uses this value as the starting point for its random number generator. Choosing not to include this attribute will default seed to zero. When included, however, whatever value we give seed, we don’t need to worry about a performance hit.

Animation showing thr shape of a cloud changing as the seed value changes.
Different seed values produce different shapes.

The GIF above represents some of what seed has to offer. Keep in mind that each of those clouds is a layered, composite cloud. (While I have tweaked attributes for each layer, I have kept their respective seed values uniform.)

Credit: Brockenhexe

Here, with a close look at the reference image, I’ve layered 3 cloud-<div>s (of differing in opacity) onto a single base div. Through trial and error and punching in arbitrary seed values, I eventually arrived at a shape resembling the shape of the cloud in the photograph.

See the Pen
Nephele Reference Image study
by BEAU.HAUS (@beauhaus)
on CodePen.

Sky’s the limit

Of course, it would be hubris to think that the <div>s that we paint to the browser could be superior to Zeus’s, Nephele.

However, the more mystery we are able to tease out of CSS and SVG filters, the more we are empowered create something visually stunning with a high degree of fidelity to the Thunder God’s original creation. We can, then, can go on experiment further!

Reflecting Mist

Animated Reflecting mist

Alto-Cirrus Clouds

Alto-Cirrus clouds

In this article, we have just dipped our toe in an ocean of power and complexity. SVG filters can often seem overwhelming and unapproachable.

However, much like the examples found in the A Single Div project project or Diana Smith’s painting techniques, a playful and experimental approach will always rewarded with spectacular results!

I hope this gets you excited about creating a bit of photorealism on the web. I developed a little tool to help put them all to use and experiment a bit. Any questions, suggestions or advice? Ping me in the twitterverse drop a comment here.


Many thanks to Amelia Bellamy-Royds for her kind advice on this article.

The post Drawing Realistic Clouds with SVG and CSS appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]