skip to Main Content

I want to ensure my loading spinner is always centered when used, in a table, a button, …

.th-loader {
  .progress {
    top: calc(50% - (var(--loading-indicator-border)/2));
    left: calc(50% - (var(--loading-indicator-border)/2));
    width: var(--loading-indicator-border);
    aspect-ratio: 1;
    background: #006edb;
    border-radius: 50%;
    transform: rotate(0deg) translateY(calc((var(--loading-indicator-size) * -0.5) + (var(--loading-indicator-border) * 0.5)));
    animation: spin 1s infinite linear;

    &.mini{
      --loading-indicator-size: 24px;
      --loading-indicator-border: 4px;
    }
  }
  @keyframes spin {
    to{transform: rotate(360deg) translateY(calc((var(--loading-indicator-size) * -0.5) + (var(--loading-indicator-border) * 0.5)))}
  }

  .progress:after {
    position: absolute;
    content: '';
    width: var(--loading-indicator-size);
    aspect-ratio: 1;
    top: 0%;
    left: 50%;
    translate: -50% 0;
    background: conic-gradient(transparent 10%, #006edb);
    border-radius: 50%;
    mask: radial-gradient(transparent calc(((var(--loading-indicator-size) * 0.5) - var(--loading-indicator-border)) - 1px), #006edb calc((var(--loading-indicator-size) * 0.5) - var(--loading-indicator-border)));
  }
}
<div> 
<button>Click Me</button>

<div class="th-loader">
  <div class="progress mini"></div>
</div>
</div>

but the spinner doesn’t stay in the middle relative to other siblings. Any idea if it’s possible to ensure that an element is always centered?

2

Answers


  1. This is the tried-and-tried method for keeping an element in the centre of its parent:

    .parent {
      position: relative;
    }
    .centered-child {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    p {
      position: relative;
    }
    
    span {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      
      background: red;
      color: white;
      padding: 0.5em;
      font-weight: bold;
    }
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tempor nunc mauris, sit amet placerat tortor lobortis dapibus. Nam lectus eros, maximus ac magna vel, congue consequat eros. Fusce id pretium diam. Cras sit amet pharetra ante. Sed quis commodo quam, vel facilisis ipsum. Vestibulum sodales iaculis arcu, et fringilla nisi ullamcorper sed. Donec interdum sit amet est non accumsan. Donec non augue feugiat, fermentum nunc non, convallis est. Cras vel ligula nec odio faucibus ultricies. Sed vulputate tortor eget pretium convallis. Cras interdum elit eget mi porta suscipit. Morbi ut velit diam. Etiam finibus eros et efficitur rutrum. Quisque viverra metus ac eleifend imperdiet. Quisque pretium ut purus vitae tempus. Duis varius risus congue velit faucibus, sed interdum purus consectetur.
      <span>centered</span>
    </p>
    Login or Signup to reply.
  2. There are many ways to add loader but this works best for me. Its also responsive for all screen sizes.

    .th-loader {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100vh;
            background-color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 100;
        }
    

    I have used position: absolute with width: 100% and height: 100vh which covers entire screen then used flexbox to center the spinner vertically and horizontally both. Finally used z-index: 100 so that it is above any other UI element.

    Below is working example.

    body {
      margin: 0;
      padding: 0;
    }
    
    .mainDiv {
      color: white;
      width: 100%;
      height: 100vh;
      background-color: #1e1e1e;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .th-loader {
      .progress {
        top: calc(50% - (var(--loading-indicator-border)/2));
        left: calc(50% - (var(--loading-indicator-border)/2));
        width: var(--loading-indicator-border);
        aspect-ratio: 1;
        background: #006edb;
        border-radius: 50%;
        transform: rotate(0deg) translateY(calc((var(--loading-indicator-size) * -0.5) + (var(--loading-indicator-border) * 0.5)));
        animation: spin 1s infinite linear;
        &.mini {
          --loading-indicator-size: 24px;
          --loading-indicator-border: 4px;
        }
      }
      @keyframes spin {
        to {
          transform: rotate(360deg) translateY(calc((var(--loading-indicator-size) * -0.5) + (var(--loading-indicator-border) * 0.5)))
        }
      }
      .progress:after {
        position: absolute;
        content: '';
        width: var(--loading-indicator-size);
        aspect-ratio: 1;
        top: 0%;
        left: 50%;
        translate: -50% 0;
        background: conic-gradient(transparent 10%, #006edb);
        border-radius: 50%;
        mask: radial-gradient(transparent calc(((var(--loading-indicator-size) * 0.5) - var(--loading-indicator-border)) - 1px), #006edb calc((var(--loading-indicator-size) * 0.5) - var(--loading-indicator-border)));
      }
    }
    
    .th-loader {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100vh;
      background-color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 100;
    }
    <div>
      <button>Click Me</button>
    
      <div class="th-loader">
        <div class="progress mini"></div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search