0

I've been trying to create a cool "bubble" effect on a website of my, but I cannot get the styling to change in a foreach loop.

There are no errors in the console, so I'm not sure what I should be doing to debug this.
Here is the code:

<script lang="ts">
    let bubbles:HTMLDivElement[]=[];
    let loaded:number=0;
    const ballAmount:number=15;
    function moveBubbles():void {
        bubbles.forEach((element)=>{
            element.style.top=Math.round((Math.random())*100)+"vh;";
            element.style.left=Math.round((Math.random())*100)+"vw;";
        });
        setTimeout(moveBubbles,15000);
    }
    moveBubbles();
</script>

<div class="bubbles">
    <div class="circles">
        {#each {length: ballAmount} as _, i}
            <div bind:this={bubbles[i]}
                class="bubble"
                style="
                    width: {Math.random()*25}vw;
                    opacity: {Math.random()*0.1};
                    top:{Math.random()*90}vh;
                    left:{Math.random()*100}vw;
                "></div>
        {/each}
    </div>
    <div class="main">
        <slot></slot>
    </div>
</div>

<style>
    .bubble {
        transition: top left 15s linear;
        aspect-ratio: 1;
        position: absolute;
        background-color: var(--primary);
        border-radius: 100%;
        opacity: 0.02;
        z-index: 0;
    }
    .bubbles {
        width: 100vw;
        height: 100vh;
    }
    .main * {
        z-index: 5;
    }
</style>

I've tried to use on:load, but I couldn't get it to run the function, same with use:moveBubbles.

1 Answer 1

2

The assigned values are just invalid and thus ignored due to a rogue ; after the unit:

Math.round((Math.random())*100)+"vh;";

Note that you are modifying the style which also has interpolated values in the template. If these values were dynamic, the changes from the script may be overridden.

Generally, direct DOM manipulation is not recommended. Instead I would store an array of { x, y } objects and interpolate those in the template. In the script you then just change the data.

<script lang="ts">
  const ballAmount = 15;
  let bubbles = randomLocations();
  setInterval(() => bubbles = randomLocations(), 1000);

  function randomLocations() {
    return Array.from({ length: ballAmount }, () => ({
      x: Math.round(Math.random() * 100) + "vw",
      y: Math.round(Math.random() * 100) + "vh",
    }));
  }
</script>

<div class="circles">
  {#each bubbles as { x, y }}
    <div class="bubble"
        style="
          width: {Math.random() * 25}vw;
          opacity: {Math.random() * 0.1};
          top: {y};
          left: {x};
        "></div>
  {/each}
</div>

(Timeouts and intervals should usually be cleaned up when the component is unmounted/destroyed to avoid leaks. Skipped that in the code sample for brevity.)

REPL

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.