Why shadows in browser look like from 2007?


Why shadows in browser look like from 2007?


Aleksandr Korotaev

My own context

Experience with non-standard shadows for WebGL and React Native.

My own context

Customers reaching out to me when standard APIs didn't work as well.



Why 2007?

part 1 / 4

Web (CSS)

In 2007, work on box-shadow in CSS started (released in 2010)

CSS Backgrounds and Borders Module Level 3
# box-shadow

Web (CSS)

            box-shadow:
                inset 0 -3em 3em rgba(0, 0, 0, 0.1),
                0 0 0 2px rgb(255, 255, 255),
                0.3em 0.3em 1em rgba(0, 0, 0, 0.3);
        

iOS

iOS (Swift UI)

            Element
              .shadow(
                color: .primary,
                radius: CGFloat(radius),
                x: CGFloat(offset),
                y: CGFloat(offset),
              )
        

Android

Android (< 9)

            <View
              android:elevation="2dp"
            >
        

Android (Jetpack Compose)

            <View
              android:elevation="2dp"
              android:shape="CircleShape | RectangleShape | RoundedCornerShape"
              android:clip="true | false"
              android:ambientColor="@android:color/primary"
              android:spotColor="@android:color/secondary"
            >
        



Issues

Issue

Making the same UI-kit
for 3 platforms
is hard.

Issue

Shadows in 2025 still
look Β«flatΒ» and restricted,
especially on Android and iOS.

Issue

Shadows as a filter are supported
in browsers ONLY.


Shadows for every platform β€” it's a compromise between design and performance from 15 years ago.



Why?

part 2 / 4



What is UI made from?

What is a block made from?

  1. Content area
  2. Border

What is a block made from?

  1. Content area
  2. Blur
  3. Border
  4. Blur
  5. Shadow (blurred)


How is a block drawn?

Let's look at the GPU pipeline



How is a block drawn?

Let's take a look at the Tech Assignment


Solution 1:

Assembly from triangles

Triangle cons

  1. Grid assembling
  2. Grid rebuilding
  3. Blurring

Solution 2:

Nine slices

Who uses Nine slices?

  1. Android
  2. Old iOS
  3. CSS border-image

Nine slices cons

  1. Texture for each new shape
  2. No dynamics

Solution 3:

SDF



SDF β€” this is a function that returns the distance to the closest object edge.



-1 β€” inside
0 β€” on edge
1 β€” outside

Who uses SDF?

  1. Browsers
  2. iOS

SDF cons

  1. Hard algorithms

SDF pros

  1. Memory
  2. Speed
  3. Sharpness

Why SDF?

  1. Shaders assembled at runtime
  2. Can generate custom ones

            float sdRoundedBox( in vec2 p, in vec2 b, in vec4 r )
            {
                r.xy = (p.x>0.0)?r.xy : r.zw;
                r.x  = (p.y>0.0)?r.x  : r.y;
                vec2 q = abs(p)-b+r.x;
                return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
            }
        

CSS Border Module 4

corner-shape: round;
corner-shape: bevel;
corner-shape: scoop;
corner-shape: notch;


There is some hope

part 3 / 4

Solution 4:

Vector Feathering



Vector Feathering β€” like SDF but with vectors instead of distance.

Rive

  1. Browsers
  2. iOS
  3. Android


Key takeaways

part 4 / 4


In 2007, the easiest solutions were chosen


Browsers and OS are stuck in compromise between ease and functionality.


Shadows are not just "black blurred rects". They're an important part of design