Framer Classic » Layers » Shadow

Shadow

Layers can have shadows; you can set their type, color, offset, blur and spread.

And when one shadow is not enough, you can add up to nine more multiple shadows.

The different types of shadows: "outer", "inner" and "box"
Open in Framer

Shadow type

The standard, "outer" shadow will drop a shadow underneath the layer, but you can also have "inner" shadows, for when you want an embossed effect.

Plus there’s also "box" (the default shadowType in Code), but this produces a shadow that always follows the layer’s border and ignores the transparency of the layer’s content.

The shadowType is not a numeric value, so to animate from one type of shadow to another you’ll have to add in-between steps.

Outer and inner shadows

This example project has an orange layer with an "outer" shadow:

# Orange layer
layer_A.props =
    shadowType: "outer"
    shadowX: 5
    shadowY: 5
    shadowBlur: 6

The shadow gets animated to zero when you press down on the layer.

layer_A.onTapStart ->
    @animate
        x: @x + 2.5
        y: @y + 2.5
        shadowX: 0
        shadowY: 0
        shadowBlur: 0

(While also slightly changing the position of the layer.)

… and then after a 🛠 Delay, the shadow is set to "inner" and animated back in.

    Utils.delay .3, =>
        @shadowType = "inner"
        layer_A_label.text = ""inner""
        @animate
            shadowX: 5
            shadowY: 5
            shadowBlur: 6

The blue layer doesn’t have any x or y shadow offset, only an "inner" shadow with some shadow spread:

# Blue layer
layer_B.props =
    shadowType: "inner"
    shadowSpread: 6
    shadowBlur: 6

… which also first gets animated to 0, and then animated back up once it became an "outer" shadow.

layer_B.onTapStart ->
    @animate
        shadowSpread: 0
        shadowBlur: 0
    Utils.delay .3, =>
        @shadowType = "outer"
        layer_B_label.text = ""outer""
        @animate
            shadowSpread: 6
            shadowBlur: 6
Open in Framer

The shadows in this project were added in Code because adding them in Design would create one of the nine Multiple shadows.

Layers with and without images

An "outer" shadow will follow the transparency of the layer content, so when the layer’s image is, e.g., 50% opaque in a specific spot, the shadow underneath it will be lighter.

But, this is only true when the layer has an image. On layers with only a background color, the shadow will just follow the shape of the layer, even when that color has transparency.

Layers with and without an image (all with transparent background colors)
Open in Framer

(This is unrelated to a layer’s opacity. When that is less than 1 everything becomes more transparent: the layer itself, its child layers, and its shadow(s).)

Shadow color

The shadowColor property wants a string in CSS color format, just like Background color, and the default color is also the same transparent gray.

Shadow offset

You define the shadow’s offset separately for the x- and y-axes.

shadowX : The distance of the shadow on the x-axis. A positive value will place it on the right side of a layer, a negative value on the left.

shadowY : Same for the y-axis. A positive value will put it at the bottom of the layer, while a negative value will produce a shadow from the top edge.

Both values are in points, but halves (e.g., 0.5) can be used to change the value with just a pixel on a @2x device.

Shadow blur

The default value of shadowBlur is 0, which will create a sharp ‘high noon’ shadow. Setting a higher value softens it with a Gaussian blur.

Shadow spread

The shadowSpread property will grow a shadow in all directions, or at least positive values do; a negative value will cause it to shrink.

As an example: if shadowX, shadowY and shadowBlur are all 0, you will see no shadow, because the layer will cover it.

If you then set shadowSpread to 2, you’ll see a 2-point border appear around the layer.

The value is in points, but halves (e.g., 0.5) can be used to change the spread with just a pixel on a @2x device.

(A layer’s border properties create a border on the inside of the layer… so you now also know how to create a border on the outside.)

Multiple shadows

Next to the global shadow, explained in the preceding pages, you can add nine more shadows to a layer.

You can set these shadows one by one and give each of them their type, color, x and y offset, blur and spread.

You can set a shadow on layer.shadow1, a second one on shadow2, and so on until shadow9.

layerA = new Layer
    size: 200
    shadow1:
        type: "outer"
        color: "#7DDD11"
        x: -15
        y: -15
    shadow2: { type: "outer", color: "#F8B000", x: 15, y: -30 }
    shadow3: { type: "outer", color: "#28AFFA", x: 15, y: 15 }
    shadow4: { type: "inner", color: "#877DD7", blur: 5, x: 10, y: 10 }
Open in Framer
Two layers with the same four multiple shadows

Shadows added in Design will by default be these multiple shadows. (Shadows added in Design will never set global properties like, e.g., layer.shadowX.)

Shadows with higher numbers will be drawn first, so shadow1 (the green one in above’s example) will always be on top.

The first shadow you add in Design will be shadow1, and then it counts up when you go down the list.

You can change any shadow’s properties directly, like this:

layer_A.shadow1.blur = 10

Animating multiple shadows

When animating these shadows be sure to ‘reach into’ the shadow object’s properties with an extra indented line, like this:

layerA.onTap ->
    @animate
        shadow1:
            x: -30
        shadow2:
            x: 30
        shadow3:
            y: 30
Open in Framer

… or you give it a complete shadow object to animate to:

layerA.onTap ->
    @animate
        shadow1: { type: "outer", color: "gray", x: -10, y: -10 }

Because this, for instance, will not work:

layerA.onTap ->
    @animate
        shadow1.x: 30
Animating the first three shadows

All shadows

In addition to the numbered shadows (shadow1, shadow2…), there’s also a shadows property; it contains an array of all nine shadows.

With a print of it, you can inspect a layer’s shadows.

print layerA.shadows

» [{type:"outer", color:<Color "#7DDD11">, x:-15, y:-15, blur:0, spread:0}, {type:"outer", color:<Color "#F8B000">, x:15, y:-30, blur:0, spread:0}, {type:"outer", color:<Color "#28AFFA">, x:15, y:15, blur:0, spread:0}, {type:"inner", color:<Color "#877DD7">, blur:5, x:10, y:10, spread:0}]

You can also use shadows to copy all shadows without having to reference them one-by-one. Like I did with the second (green) layer above:

layerB = new Layer
    size: 200
    backgroundColor: "#2DD7AA"
    shadows: layerA.shadows

Animating a set of multiple shadows

What’s cool is that you can animate shadows: you can animate to a different set of shadows. In the resulting animation, the first shadow (shadow1) will animate to the first one in the new set, shadow2 to the second one, and so on, all at the same time.

The easiest way to do this is by creating another layer in Design, give it the shadows you want to animate to, and then animate to that layer’s shadows.

firstLayer.animate
    shadows: secondLayer.shadows

But you can also create shadow descriptions. Take this function:

# Function that makes a new set of shadows
makeNewShadows = (layer) ->
    newShadows = []
    # For every shadow on the layer …
    for shadow in layer.shadows
        # … a new shadow with the same color
        # but random x, y, and blur
        newShadow =
            x: Utils.randomNumber -40, 40
            y: Utils.randomNumber -40, 40
            blur: Utils.randomNumber 0, 20
            color: shadow.color

        newShadows.push newShadow

    return newShadows

The above function…

  • Takes a layer as input
  • Loops through that layer’s array of shadows
  • Makes a newShadow for every existing shadow, with the same color but a randomized x, y, and blur
  • And returns all of them as a new array of shadows

I use it to animate a layer’s shadows to what gets returned by makeNewShadows(). (this refers to the layer that’s tapped.)

layer_A.onTap ->
    # Save existing shadows
    originalShadows = @shadows
    # Animate to new shadows
    @animate
        shadows: makeNewShadows this
    # Animate back to the original ones
    Utils.delay 1, =>
        @animate
            shadows: originalShadows
Open in Framer

And then animate back to the original set of shadows after a one second 🛠 Delay.

Using shadows to animate a set of multiple shadows

Result of changing global shadow properties

What happens to the multiple shadows when you change one of the global shadow properties (shadowColor etc.) might be unexpected.

Whenever you change shadowColor, shadowX, shadowY, shadowBlur, or shadowSpread you’ll be changing it for all the multiple shadows.

So when you have nine shadows on layerA, with this lime:

layerA.shadowColor = "lime"

… all nine of them will suddenly be lime green.

(The exception is shadowType, changing this property will not affect existing multiple shadows.)

In this example, I blur all eight of the layer’s shadows and then remove the blur after a 🛠 Delay of one second.

layer_B.onTap ->
    # Blur all shadows
    @animate
        shadowBlur: 25
    # Remove the blur
    Utils.delay 1, =>
        @animate
            shadowBlur: 0
Open in Framer
Using shadowBlur to change the blur of all multiple shadows

Leave a Reply