In today's article, I'm going to describe how to add dynamic colored borders to an element in your webpage, similar to the one you see on this page. After that, I'll talk about some details specific to the implementation in this page, which is statically generated with constexpr.js.

Let's say this is the element you want to add a dynamic border to:

.main_content { background: lightgrey; width: 10em; height: 10em; display: flex; align-items: center; justify-content: center; }

1. First thing your should do is wrap this element inside another div, and add a tiny amount of padding to the outer div. That padding will act as the border you see on this page.

.wstage1 { display: inline-block; padding: 5px; background: white; }

2. After that add some colors to the wrapper div. A linear-gradient should do the job:

.wstage2 { background: linear-gradient( 45deg, red, blue, green, red, blue, green, red, blue, green, red, blue, green, red, blue, green ); background-size: 300% 300%; }

3. Now we animate the background:

@keyframes animatedgradient { 0% { background-position: 0 50%; } 50% { background-position: 50% 50%; } 100% { background-position: 100% 50%; } } .wstage3 { animation: animatedgradient 8s linear alternate infinite; }

To be honest, this looks more like diwali material than holi material, but whatever.


Another method of doing this is adding an ::after element to the content, making it slightly bigger than the content element (width: calc(100% + 4px);), and animating the background on that pseudo element. This is a css only solution (doesn't require changing the markup, or writing javascript that changes the markup), but it has some cons:

  1. It doesn't play well with overflow: hidden;
  2. The ::after pseudo-element extends outside of the content bounds, so it might interfere with the surrounding elements. So you can not use this method if your target element is right next to some other element.

The method described in this article doesn't have these disadvantages. And, with constexpr.js, you can use this method without changing the markup or runtime javascript.

The implementation in this website

You can find the source of this page here.

Every page on this site contains these two constexpr script tags:

<script constexpr> async function render_page() { // ... const base_page_render = site_global_rendering() // ... await base_page_render // ... } </script> <script constexpr> render_page() .then(() => window._ConstexprJS_.compile()) </script>

site_global_rendering() generates all the markup that is common among all the pages on this site (nav, header, footer, syntax highlighting etc). Individual pages can add code that depends on the markup generated by this method after the await call.

The rendering code on this page waits for the site global rendering to finish, which generates the following markup: <div id="body_wrapper"> <header></header> <article></article> <footer></footer> </div>

And adds another wrapper around it that does the holi decoration: <script constexpr> async function render_page() { const base_page_render = site_global_rendering() await base_page_render const hw = make_element(`<div id="holi_wrapper"></div>`) hw.appendChild(body_wrapper) document.body.appendChild(hw) } </script>

Since all this code is constexpr, this wrapping is done at compile time.