Depth of Field
Three planes at different "distances" — background at the top left, subject at the center, foreground at the bottom right — with only one in focus: hovering, tapping or tabbing to a plane moves the focus there (CSS blur from 0 to 4 px and a slight change in scale), and a click keeps it there. A lens's depth of field, made with three buttons and a CSS blur.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →
3 usage examples



How it works
The root .fx-0027-root (#0a0a0f background, at least 300 px tall) holds the .dof-scene (full width × 250 px) and three .dof-layer buttons: "Background" placed 20 px from the top left corner (40% indigo), "Focus" at the center (#6366f1 → #8b5cf6 gradient, shadow, above the others) and "Foreground" 20 px from the bottom right corner (50% pink). The scene's data-focus attribute says which plane is sharp, and the CSS does the rest. At rest (mid): subject sharp, the other two at blur(3px), background shrunk to 90% and foreground enlarged to 105%. On bg: background sharp at 100%, subject at 2 px, foreground at 4 px. On fg: foreground sharp at 100%, subject at 2 px, background at 4 px and shrunk to 85%. Every change glides in 0.6 s (transition on filter and transform).
The script touches no style at all: it only changes data-focus. Hovering a plane (pointerenter, which also covers fingers and pens) or giving it keyboard focus shows a preview of the focus on that plane; leaving it (pointerleave, blur) goes back to the kept plane. A click, a tap, Enter or Space makes the plane the kept one and updates aria-pressed on the three buttons. Because the states live in the CSS rather than in inline styles, hover, click and keyboard combine without overwriting each other. Measured in Chromium 151, Firefox 153 and WebKit 26: after a click on "Background", moving the mouse out leaves the background sharp (blurs 0 / 2 / 4 px), hovering "Foreground" switches to 4 / 2 / 0 px, and leaving returns to 0 / 2 / 4 px.
One instance starts per [data-dof] scene found under a .fx-0027-root root: two copies on a page each keep their own plane (measured: a click on the second one changes nothing in the first). With a finger, measured with real touch events in Chromium: tapping "Background" brings it into focus and keeps it there. The blur is only an image of depth: nothing is 3D, there is no perspective; the gap in sharpness (0, 2, 3, 4 px) and the gap in scale (85 to 105%) are what make three distances readable.
Accessibility
- Keyboard: the three planes are real
<button>elements. Tab moves focus to the next plane and shifts the focus of the image there (measured in Chromium and Firefox), Enter or Space keeps it, and a 2 px white outline marks focus.aria-pressed="true"announces the kept plane to screen readers. In Safari, Tab only reaches buttons with Option + Tab or the "Press Tab to highlight each item" setting (behavior measured in WebKit). - Reduced motion: under
prefers-reduced-motion: reduce, a block scoped to.fx-0027-rootremoves the transitions: sharpness and scale change at once, with no glide. Every interaction remains (measured: same blurs after hover, click and keyboard, transition duration 0 s). - Blurred text: a blurred plane cannot be read by eye, that is the point. Screen readers read all three labels normally. Only put in a blurred plane what can wait, and keep the main text on the plane that is sharp at rest.
- Contrast: white text on the sharp plane's gradient, calculated at 4.5:1 on
#6366f1and 4.2:1 on#8b5cf6, just under the 4.5:1 threshold for 16 px text: darken the gradient slightly if the label is long. The other two planes, once sharp, exceed 6:1.
Browser compatibility
CSS (filter: blur(), transform: scale(), transitions, attribute selectors) + 22 lines of JavaScript (pointer, focus and click events), no dependencies. Measured in Chromium 151, Firefox 153 and WebKit 26: same blurs in every state, plane kept after a click, hover still working after the click, two independent copies, transitions removed under reduced motion. Touch measured in Chromium with real touch events.
Without JavaScript, the scene stays frozen in its starting state (subject sharp, two blurred planes): the buttons do nothing but all the text stays in the page. Without filter (very old browsers), the three planes stay sharp and only the change in scale marks the chosen plane.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0027-root">
<div class="dof-scene" data-dof="" data-focus="mid">
<button type="button" class="dof-layer dof-bg" data-plane="bg" aria-pressed="false">Background</button>
<button type="button" class="dof-layer dof-mid" data-plane="mid" aria-pressed="true">Focus</button>
<button type="button" class="dof-layer dof-fg" data-plane="fg" aria-pressed="false">Foreground</button>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Blur strength (CSS — blur(3px) at rest, blur(2px) and blur(4px) in the [data-focus] rules) |
3 px at rest; 2 and 4 px when the focus moves | Keep a gap between the neighboring plane and the distant one (2 then 4 px): that gap is what suggests distance. Above 6 px, 13 px text turns into a smudge; below 1.5 px, the difference no longer shows. |
Switch speed (CSS — transition on .dof-layer) |
0.6 s | 0.3 s makes the hover preview snappier (the scenes' setting); 1 s gives a slow, cinematic focus pull. Under reduced motion, the transition is removed anyway. |
Plane in focus at start (HTML — data-focus and aria-pressed; JS — var kept = 'mid') |
mid (the subject) | To open on the background, set data-focus="bg" on the scene, aria-pressed="true" on "Background" (and false on the others) and 'bg' in the script. |
Position and size of the planes (CSS — .dof-bg, .dof-mid, .dof-fg) |
top left corner, center, bottom right corner | Place them anywhere with position: absolute. The larger a plane, the easier it is to hover; the middle plane keeps z-index: 2 to pass in front of the others if they overlap. |
Plane scale (CSS — scale(.9), scale(1.05), scale(.85)) |
90% at the back, 105% in front, 85% for a very blurred background | Scale reinforces distance: a distant plane slightly smaller, a near plane slightly larger. Stay between 80 and 110% so the labels do not move too much. |
Plane content (HTML — text of the three <button> elements) |
Background, Focus, Foreground | Text, a small image, a line in <small>: anything a button can contain. No link or other button inside (invalid HTML, confusing keyboard focus). |
FAQ
<button> takes focus, responds to Enter and Space, and aria-pressed announces which one is chosen. The button's default styles are neutralized in the CSS (border: 0, inherited font): visually, they are three cards.