Utilities✨ Premium

Lightning Border

Electric border: a violet ring twisted by an SVG turbulence filter changes shape every 350 ms and breathes gently; it flares up on hover, focus and finger press.

SVGFilterElectric

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Overvoltage alert in a solar plant's monitoring screen — Lightning Border example 1

① Overvoltage alert in a solar plant's monitoring screen

WhenOn the Vaudrelière plant's screen, four cards give today's readings. The one for inverter 2, at 846 V against an 800 V limit, is the only one framed by a crackling orange border; the log below says the technician has been notified.
WhyAn electrical alert that looks electric stands out at a glance among still cards, and the slow pace of the bolt draws attention without blinking like a beacon.
Settingsltb-box on the alert card (left-aligned content, 96 px tall), --ltb-color: #f97316, --ltb-color-active: #fdba74, --ltb-glow: rgba(249, 115, 22, .45). No driving: the border runs on its own.
Boss card in a card-game hand — Lightning Border example 2

② Boss card in a card-game hand

WhenIn Vexaldre, the player's hand holds five fanned cards. In the middle, taller and bigger, "The Storm Warden" is the only card edged with a lavender bolt, which flares up when the mouse passes over it.
WhyThe border says "rare card" without text, and its theme matches the card's. The hover state gives feedback while the player wonders whether to play it.
Settings128 × 184 px ltb-box on the boss card, --ltb-color: #a78bfa, --ltb-color-active: #e9d5ff, --ltb-glow: rgba(196, 181, 253, .55). Hover comes from the capture's mouse.
Band name on a concert poster — Lightning Border example 3

③ Band name on a concert poster

WhenRight in the middle of the page for Brumaskar's gig at L'Ébarbeuse, the band name in 54 px capitals is framed by the electric border, above the tour line, the Tickets button and the seats left.
WhyThe border turns the title into a buzzing neon sign that fits the gig, with no image or video to load.
Settings400 × 118 px ltb-box with a transparent background around the title, default colours (#7b2ff7, active #a855f7).

How it works

The .ltb-box has a crisp 2 px #7b2ff7 border. Right around it, the .ltb-ring (3 px, 6 px wider on each side, 16 px radius) goes through an SVG filter: feTurbulence builds noise (frequency 0.05, 3 octaves) and feDisplacementMap uses it to shift each pixel of the line by up to 2 px. The straight line turns ragged, like an electric arc.

Every 350 ms the script changes the turbulence seed: the bolt takes a new shape, fewer than three changes per second. Meanwhile the ring's opacity goes from 0.7 to 1 and back in 1.2 s (ltb-flicker). The script stops the shape changes when the box leaves the screen (IntersectionObserver) or when the system asks for less motion, and resumes them afterwards.

The script also gives each copy its own filter id (ltb-filter-1, ltb-filter-2…) and links the ring to it: several borders on one page never share a filter. On hover, focus (:focus-within) or finger press (ltb-on class), border and ring turn #a855f7 with a 15 to 40 px violet halo.

Accessibility

  • Flashes measured: frame by frame, no pixel of the border changes brightness more than 2 times per second (WCAG 2.3.1 threshold: 3), at rest and in the active state. The original version went up to 12.5 at rest and 21 on hover, reduced motion included.
  • Reduced motion: under prefers-reduced-motion: reduce the bolt shape is frozen and opacity stays at 0.8; nothing moves any more. The setting is followed live, without reloading the page.
  • Silent decoration: the filter SVG and the ring have aria-hidden="true"; only the box content is read.
  • Keyboard and touch: the demo box is a <div>, which Tab cannot reach. For a clickable card, give the ltb-box class to your <a href> or <button>, keeping the filter SVG and the ring as first children, or put your link inside the box: Tab then lights the active state. On a box turned into a link or button, that state replaces the focus outline; a link placed inside keeps its own. A finger press lights the active state too, WebKit included.
  • Limit: the bolt is a continuous animation with no pause button; it only stops off screen or with the system setting.

Browser compatibility

SVG filter (feTurbulence, feDisplacementMap) applied in CSS to an HTML element, :is() selector (Chrome 88, Firefox 78, Safari 14), IntersectionObserver (Chrome 51, Firefox 55, Safari 12.1) and 2 KB of JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two copies with two distinct filter ids, only the second one hovered, keyboard focus, finger press, 390 px without overflow, reduced motion with no animation and no seed change, 0 errors. Flashes measured in Chromium over 200 frames 20 ms apart.

Chrome 88+✓ Full (measured)
Firefox 78+✓ Full (measured)
Safari 14+✓ Full (measured in WebKit)
Edge 88+✓ Full (Chromium engine)
Mobile iOS 14+✓ WebKit engine, not checked on a device
Android Chrome 88+✓ Full (Chromium engine)

Without JavaScript, the ring keeps the first copy's filter (#ltb-filter) with a fixed shape and only the opacity breathes. Without :is(), the active state does not show but the border stays.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0770-root">
  <div class="ltb-box">
    <svg class="ltb-defs" aria-hidden="true" focusable="false">
      <filter id="ltb-filter" …>
        <feTurbulence … result="turb"></feTurbulence>
        <feDisplacementMap in="SourceGraphic" in2="turb" …></feDisplacementMap>
      </filter>
    </svg>
    <div class="ltb-ring" aria-hidden="true"></div>
    …
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Colour (CSS — --ltb-color) #7b2ff7 Crisp border and electric ring at rest.
Active colour and halo (CSS — --ltb-color-active, --ltb-glow) #a855f7 and rgba(123, 47, 247, .45) Colour and glow on hover, focus and touch.
Breathing (CSS — --ltb-flicker) 1.2s Length of one opacity round trip between 0.7 and 1. Do not go below 0.7 s.
Bolt pace (JS — STEP_MS) 350 ms Time between two shapes. Measured: at most 2 brightness changes per second at 350 ms, 2.5 at 250 ms, 3.5 at 170 ms (over the threshold). Stay at 250 ms or more.
Amplitude (HTML — scale of feDisplacementMap) 4 (2 px each way) Bigger twists the line more; at 0 it is straight again.
Grain (HTML — baseFrequency of feTurbulence) 0.05 Higher gives tighter ripples; lower, wider ones.
Forced active state (HTML — ltb-on class on .ltb-box) absent Keeps the border flared, for instance on the item in alert. The script only removes the one it added on touch.

FAQ

We measured it the way WCAG 2.3.1 does: 200 frames 20 ms apart, brightness computed pixel by pixel. No pixel goes beyond 2 clear changes per second, and the area involved (the 3 px line) stays far below the criterion's area limit. With reduced motion, nothing moves. If you speed the bolt up, keep at least 250 ms between two shapes.
For three things CSS cannot do alone: give each copy a unique filter id, change the turbulence seed at a chosen pace, and stop that change off screen or under reduced motion. Without the script the border still shows, with a fixed shape.
Yes. Each .fx-0770-root gets its own filter (a single .ltb-box per root: the script only handles the first one), and borders that are off screen stop changing shape. Each visible border still recomputes its filter for every new shape: beyond ten or so on screen at once, check smoothness on a low-end phone.