0

I am trying to make a box with a nice looking animated gradient. I can not use the animate function to change the gradient so I try to do it with JavaScript. I would use the jQuery.css() function, but I can not address the :before and :after selectors with jQuery.

So what I am trying to do is to change the CSS code in #js-style every 100ms in an infinite loop. But what happens is that it does update the CSS code, but it only applies it when the loop breaks.

Is there a way to tell the browser to check and apply the code every time it changes during the JavaScript loop?

  $(document).ready(function() {
      // Settings
      var steps_per_color = 100;
      var timeout = 100;
      var colors = [
        [255, 0, 158],
        [0, 205, 255],
        [42, 0, 255],
        [168, 0, 253]
      ];
      var cur_base_colors = [
        0,
        1,
        2,
        3
      ];
      var cur_goal_colors = [
        1,
        2,
        3,
        0
      ];
      var cur_colors = [
        colors[0],
        colors[1],
        colors[2],
        colors[3]
      ];

      var def_colors = [
        [255, 0, 158],
        [0, 205, 255],
        [42, 0, 255],
        [168, 0, 253]
      ];
      var step = 0;
      var step_size, goal, base, text, cur_color;

      while (true) {
        cur_base_colors.unshift(cur_base_colors[3]);
        cur_base_colors.pop();
        cur_goal_colors.unshift(cur_goal_colors[3]);
        cur_goal_colors.pop();

        cur_colors.forEach(function(color, color_index) {
          cur_colors[color_index] = colors[cur_base_colors[color_index]];
        });
        while (step < steps_per_color) {
          cur_colors.forEach(function(color, color_index) {
            color.forEach(function(item, index) {
              base = colors[cur_base_colors[color_index]][index];
              goal = colors[cur_goal_colors[color_index]][index];
              step_size = (goal - base) / steps_per_color;
              cur_color = item + step_size
              cur_colors[color_index][index] = cur_color;
              def_colors[color_index][index] = Math.round(cur_color);
            });
          });
          text = ".shadow:before, .shadow:after{background: linear-gradient(135deg";
          def_colors.forEach(function(item, index) {
            text += ", rgb(" + item[0] + ", " + item[1] + ", " + item[2] + ")";
          });
          text += ");}";

          console.log(text);
          $('#js-style').html(text);

          sleep(timeout);
          step += 1;
        }
        break;
        step = 0;
      }
    });

    function sleep(milliseconds) {
      const date = Date.now();
      let currentDate = null;
      do {
        currentDate = Date.now();
      } while (currentDate - date < milliseconds);
    }
  * {
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      background: #555;
      margin: 0;
      height: 100vh;
      width: 100vw;
      padding: 20px;
    }
    
    .block {
      position: relative;
      width: 100%;
      height: 100%;
      color: #f2f2f2;
      display: flex;
      flex-direction: column;
      justify-content: center;
      border-radius: 5px;
    }
    
    .shadow:before,
    .shadow:after {
      content: '';
      position: absolute;
      top: -2px;
      left: -2px;
      width: calc(100% + 4px);
      height: calc(100% + 4px);
      background-size: 100%;
      z-index: -1;
      border-radius: 5px;
    }
    
    .shadow:after {
      top: -4px;
      left: -4px;
      width: calc(100% + 10px);
      height: calc(100% + 10px);
      filter: blur(4px);
      opacity: 1;
    }
  <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

<div class="block shadow"></div>
Yosef Tukachinsky
  • 5,570
  • 1
  • 13
  • 29
Robin
  • 164
  • 14
  • 3
    Use [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) instead of blocking the thread like your `sleep` function does. – Heretic Monkey May 19 '20 at 15:38
  • Not too sure, but manipulating CSS in async function might help – LordBertson May 19 '20 at 15:41
  • 1
    Does this answer your question? [JS hangs on a do while loop](https://stackoverflow.com/questions/10809868/js-hangs-on-a-do-while-loop) – Heretic Monkey May 19 '20 at 15:41
  • Seems to do the trick! @HereticMonkey I moved all the code to a function called by requestAnimationFrame and now it updates in real time. The numbers dont get changed properly anymore though, is there a proper way i can set a timeout (100ms wait) every run? Thanks! – Robin May 19 '20 at 15:59
  • If you need control over the timeout, use `setTimeout` or `setInterval`, as noted in the linked question's answers. – Heretic Monkey May 19 '20 at 16:04

0 Answers0