Search code examples
htmlcsscss-animationscss-transforms

How to resize rotation radius using css


How to resize balls rotation radius so that they should touch the orange contaner border

.bg {
    background-color: blue;

    display: flex;
    align-items: center;
    justify-content: center;
}

.ball-container {
    position: relative;
    display:flex;
    justify-content:center;
    align-items:center;
    background-color: orange;
    width: 250px;
    height: 250px;
}

.ball {
    position: absolute;
    width: 24px;
    height: 24px;
    background-color: white;
    border-radius: 50%;

    top: 125px - 12px;
    left: 125px - 12px;

    animation-name: ball_moves;
    animation-duration: 1.5s;
    animation-timing-function: ease-in-out;
    animation-iteration-count: infinite;
    animation-direction: initial;
}

.ball:nth-child(1) {
    transform-origin: top left;
}
.ball:nth-child(2) {
    transform-origin: top right;
}
.ball:nth-child(3) {
    transform-origin: bottom left;
}
.ball:nth-child(4) {
    transform-origin: bottom right;
}

@keyframes ball_moves {
    0% {
        transform: rotateZ(0);
    }
    100% {
        transform: rotateZ(360deg);
    }
}
<div class="bg">

    <div class="ball-container">
        <div class="ball"></div>
        <div class="ball"></div>
        <div class="ball"></div>
        <div class="ball"></div>
    </div>

</div>


Solution

  • Use CSS variables to define a unique offset that can control all your circles using transform-origin:

    .bg {
        background-color: blue;
    
        display: flex;
        align-items: center;
        justify-content: center;
        margin:10px;
    }
    
    .ball-container {
        --d:35px; /* adjust this like you want (you can even use % value)*/
        /* 
          1) we first find the middle of each small square
            the size is 250/2=125 so we translate by (125-24)/2 = 50.5px
            this will put the origin in the middle and give us a rotation 
            following the "circumscribe" circle so we the circle will go outside
          2) we need to decrease it to keep the rotation inside
             the calculate is a bit complex but we decrease by around 15px to have 35px
        */
        
        position: relative;
        display:flex;
        justify-content:center;
        align-items:center;
        background: 
          linear-gradient(red,red) center/100% 1px,
          linear-gradient(red,red) center/1px 100%,
          orange;
        background-repeat:no-repeat;
        width: 250px;
        height: 250px;
    }
    
    .ball {
        position: absolute;
        width: 24px;
        height: 24px;
        background-color: white;
        border-radius: 50%;
    
        animation-name: ball_moves;
        animation-duration: 1.5s;
        animation-timing-function: ease-in-out;
        animation-iteration-count: infinite;
        animation-direction: initial;
    }
    
    .ball:nth-child(1) {
        transform-origin: calc(-1*var(--d)) calc(-1*var(--d));
    }
    .ball:nth-child(2) {
        transform-origin: calc(-1*var(--d)) calc(100% + var(--d));
    }
    .ball:nth-child(3) {
        transform-origin: calc(100% + var(--d)) calc(-1*var(--d));
    }
    .ball:nth-child(4) {
        transform-origin: calc(100% + var(--d)) calc(100% + var(--d));
    }
    
    @keyframes ball_moves {
        0% {
            transform: rotateZ(0);
        }
        100% {
            transform: rotateZ(360deg);
        }
    }
    <div class="bg">
    
        <div class="ball-container">
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
        </div>
    
    </div>
    
    <div class="bg">
    
        <div class="ball-container" style="--d:100%;"> <!-- 100% = 24px (size of circle) -->
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
        </div>
    
    </div>

    Using another syntax:

    .bg {
        background-color: blue;
    
        display: flex;
        align-items: center;
        justify-content: center;
        margin:10px;
    }
    
    .ball-container {
        --d:47px; /* adjust this like you want (you can even use % value)*/
        /* 
          1) we first find the middle of each small square
            the size is 250/2=125 so we translate by (125)/2 = 66.5px
            this will put the origin in the middle and give us a rotation 
            following the "circumscribe" circle so we the circle will go outside
          2) we need to decrease it to keep the rotation inside
             the calculate is a bit complex but we decrease by around 15px to have 47px
        */
        
        position: relative;
        display:flex;
        justify-content:center;
        align-items:center;
        background: 
          linear-gradient(red,red) center/100% 1px,
          linear-gradient(red,red) center/1px 100%,
          orange;
        background-repeat:no-repeat;
        width: 250px;
        height: 250px;
    }
    
    .ball {
        position: absolute;
        width: 24px;
        height: 24px;
        background-color: white;
        border-radius: 50%;
    
        animation-name: ball_moves;
        animation-duration: 1.5s;
        animation-timing-function: ease-in-out;
        animation-iteration-count: infinite;
        animation-direction: initial;
    }
    
    .ball:nth-child(1) {
        transform-origin: calc(50% - var(--d)) calc(50% - var(--d));
    }
    .ball:nth-child(2) {
        transform-origin: calc(50% - var(--d)) calc(50% + var(--d));
    }
    .ball:nth-child(3) {
        transform-origin: calc(50% + var(--d)) calc(50% - var(--d));
    }
    .ball:nth-child(4) {
        transform-origin: calc(50% + var(--d)) calc(50% + var(--d));
    }
    
    @keyframes ball_moves {
        0% {
            transform: rotateZ(0);
        }
        100% {
            transform: rotateZ(360deg);
        }
    }
    <div class="bg">
    
        <div class="ball-container">
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
        </div>
    
    </div>
    
    <div class="bg">
    
        <div class="ball-container" style="--d:200%;"> <!-- 100% = 48px (size of circle) -->
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
            <div class="ball"></div>
        </div>
    
    </div>