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.
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:
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Magni harum vitae, ex ad aut corrupti corporis molestias velit exercitationem numquam cupiditate fuga, esse maxime officiis beatae molestiae odio in dolore!
🌭
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.