Brew UI: Panel Anatomy


One of the first designs I came up with while working on my own UI framework were these panels, initially ported over from another side project. They’re wrapped in a gray-ish frame and accented with a hard neon color with a soft glow. I think they turned out pretty neat.

The gray “rim” is comprised of 3 strokes: a (relatively) lighter gray border sandwiched between two darker lines.

The accented edges were created using a similar trick from the tutorial lure: they’re actually just boxes with a linear gradient background, with a clip-path: polygon(...) rule to cut out the middle and make it appear as a 1px border. The gradient has 3 color stops: the provided primary color, to a dimmer tone, then finally a longer stretch to transparent - this curves the gradient and adds weight to the accented side.

Primary
Dim
Transparent

A copy of that box is laid on top with a filter: blur(4px) rule to achieve the glow effect. It isn’t applied to the whole frame - blurring the gray rim would look weird.

The “shimmer” effect is new - this is an animated mask image that sweeps across the panel, with mix-blend-mode: screen to get the shine over the edges. It exposes the accent color along all the edges, this was intentional but I haven’t decided if that’s a good idea.

Here’s a rough recreation of it with minimal CSS:


Another component with a more complicated outline:

This one isn’t much different than the previous panel. The round icon element introduces more complexity, so I used clip-path: path('...') instead of clip-path: polygon(...). The former is much more flexible and allows for curved lines, while the latter can only move in straight lines.

There’s a considerable trade-off in that path('...') doesn’t support percentage values (yet?); the dimensions of the box need to be known before we can create the clip path. This component uses JavaScript to determine the element’s size up front, in conjunction with a ResizeObserver to recompute the clip path whenever its dimensions change.

Here’s another rough recreation, with fixed dimensions included in the CSS:

I also put together another demo on CodePen here that demonstrates how to hook it up to a ResizeObserver so that it updates as its size changes. I’ve already embedded way too many iframes on this page though.