3

I must display a loader and blur the complete background on button click and after a response from fetch this loader should not be displayed and the background should return to normal. Below is the code that I have tried but it does not work correctly. It blurs even the loader and the page remains blur even after the response.

.no_spinner_display {
  display: none !important;
}

.body_blur {
  filter: blur(3px);
}

.loader_parent {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  margin: auto;
}

.loader {
  border: 16px solid #f3f3f3;
  border-radius: 50%;
  border-top: 16px solid #3498db;
  width: 120px;
  height: 120px;
  -webkit-animation: spin 2s linear infinite; /* Safari */
  animation: spin 2s linear infinite;
}

/* Safari */
@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
<body>
  <header></header>
  <table class="my_table">
    <thead>
      <tr>
        <th>NAME</th>
        <th>AGE</th>
        <th>Marks</th>
      </tr>
    </thead>
    <tbody>
      <div class="loader_parent no_spinner_display" id="loader_parent">
        <div class="loader" id="loader"></div>
      </div>
      <tr>
        <td>Jack</td>
        <td>20</td>
        <td>15</td>
        <td>Jill</td>
        <td>19</td>
        <td>10</td>
        <td>John</td>
        <td>21</td>
        <td>30</td>
      </tr>
    </tbody>
  </table>
  <button>Submit</button>
  <footer></footer>
</body>

I have added the loader element at that position because I want it to be displayed in the middle of the screen.

let myClass = document.querySelectorAll('.myClass');
  myClass.forEach((ele) => {
    ele.addEventListener('change', () => {
      var body = document.getElementsByTagName("BODY")[0]; 
      var loader = document.getElementById('loader_parent');
      body.classList.add('body_blur');
      loader.classList.remove('no_spinner_display', 'body_blur');
      fetchData(ele.value);
    });
  });

fetchData = async (ele) => {
    if (response.success) {
        var body = document.getElementsByTagName("BODY")[0]; 
        var loader = document.getElementById('loader_parent');
        body.classList.remove('body_blur');
        loader.classList.add('no_spinner_display');
    }
}
body > *:not(#loader) {
  filter: blur(3px);
}
// This code when added in css blurs all except loader but I want to add this code in a class if I want the desired functionality.

What should I change in order for the code to work as per my requirement?

Can I add css like this?

.body_blur {
  body > *:not(#loader) {
    filter: blur(3px);
  }
}
Lax_Sam
  • 1,099
  • 2
  • 14
  • 32
  • Changing body with desired class is not working? – Piyush Jan 07 '20 at 05:11
  • No. It blurs even the loader. – Lax_Sam Jan 07 '20 at 05:23
  • In that case, please put the html code as well where you are using that class or if possible create an working example – Piyush Jan 07 '20 at 05:24
  • Does this answer your question? [Background blur with CSS](https://stackoverflow.com/questions/14565520/background-blur-with-css) – Awais Jan 07 '20 at 05:31
  • @Awais In the answer provided in that link, the background not exactly behind the front image is not being blurred. I want the whole background to be blurred. Even that which is not directly behind the loader div. Can it be done? – Lax_Sam Jan 07 '20 at 05:49
  • Yes i'll provide a solution with pure CSS you can just call that div on click, Is that ok to you? – Awais Jan 07 '20 at 05:58
  • Sure. I want in pure CSS only. Thanks. – Lax_Sam Jan 07 '20 at 06:00

3 Answers3

1

I would go for this instead..

Don't forget to remove pointer-events: none; from .loader_parent in production. This make all behind spinner clickable, which you don't want in production.

function blurMe() {
  let spinner = document.querySelector("#loader_parent")
  if (spinner.classList.contains("blurred")) {
   spinner.classList.remove("blurred");
  } else {
  spinner.classList.add("blurred")
  }
};
.loader_parent {
    display: none;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    height: 100vh;
    width: 100%;
    z-index: 1111111;
    pointer-events: none;
}

.loader {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 37px;
    font-weight: bold;
}

.loader_parent.blurred {
  display: block;
}

.blurred ~ * {
  filter: blur(3px);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.3/css/uikit.min.css" rel="stylesheet" />
<body>
  <header></header>
  <div class="loader_parent" id="loader_parent">
    <div class="loader" id="loader"><div uk-spinner="ratio: 2"></div></div>
  </div>
  <table class="my_table">
    <thead>
      <tr>
        <th>NAME</th>
        <th>AGE</th>
        <th>Marks</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Jack</td>
        <td>20</td>
        <td>15</td>
      </tr>
    </tbody>
  </table>
  <button onclick="blurMe()">Submit</button>
  <footer></footer>
</body>
<script src="https://cdn.jsdelivr.net/npm/uikit@3.2.6/dist/js/uikit.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/uikit@3.2.6/dist/js/uikit-icons.min.js"></script>
Lumi
  • 439
  • 2
  • 8
0

First we create a div with text(what ever you want) after body tag in your HTML

<div class="loader-bg">
    <div class="loader-content">Loading</div>
</div>

Then we use backdrop-filter on its parent div loader-bg

.loader-bg {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    height: 100vh;
    width: 100%;
    z-index: 1111111;
    backdrop-filter: blur(3px);
}

In last center the content of loader like img text whatever you put inside .loader-content

.loader-content {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 37px;
    font-weight: bold;
}

A working snippet for more explanation

.loader_parent {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    height: 100vh;
    width: 100%;
    z-index: 1111111;
    backdrop-filter: blur(3px);
}

.loader {
    position: fixed;
    border: 16px solid #f3f3f3;
    border-radius: 50%;
    border-top: 16px solid #3498db;
    width: 120px;
    height: 120px;
    -webkit-animation: spin 2s linear infinite; /* Safari */
    animation: spin 2s linear infinite;
    
}
<body>
<div class="loader_parent no_spinner_display" id="loader_parent">
        <div class="loader" id="loader"></div>
      </div>
  <header></header>
  <table class="my_table">
    <thead>
      <tr>
        <th>NAME</th>
        <th>AGE</th>
        <th>Marks</th>
      </tr>
    </thead>
    <tbody>
      
      <tr>
        <td>Jack</td>
        <td>20</td>
        <td>15</td>
        <td>Jill</td>
        <td>19</td>
        <td>10</td>
        <td>John</td>
        <td>21</td>
        <td>30</td>
      </tr>
    </tbody>
  </table>
  <button>Submit</button>
  <footer></footer>
</body>
Awais
  • 4,752
  • 4
  • 17
  • 40
  • If I add the above code, the `loader-bg` is being displayed above the table in my page. It is not displaying it on top of the table. – Lax_Sam Jan 07 '20 at 06:42
  • OK change position `fixed` to `absolute` of `.loader-bg` – Awais Jan 07 '20 at 06:43
  • Now background is not blurred. – Lax_Sam Jan 07 '20 at 06:48
  • `body > *:not(#loader) { filter: blur(3px); }`. This works exactly like I want. But can I put it in a class and use in JS? – Lax_Sam Jan 07 '20 at 06:49
  • Yes you can like that ` #loader{filter: blur(0px);}` set filter to 0 for that specific div. and you can use this in js as well, and second can you make a snippet of you latest code just like mine snippet or you can edit mine too with you latest code – Awais Jan 07 '20 at 06:54
  • I have added another query to the question. – Lax_Sam Jan 07 '20 at 07:02
  • @Lax_Sam Updated the answer please check snippet, i `backdrop-filter` only removed `filter`. – Awais Jan 07 '20 at 09:08
0

I think you should blur the the div instead of whole body and need to change loader's css. For your understanding I changed code little bit and used setTimeout function instead of actual ajax/http request. It will alert fake "Got data" message and restore the div.

      let mybutton = document.getElementById('fetch');
        mybutton.addEventListener('click', () => {
          document.getElementById("anydiv").style["filter"]="blur(3px)";
          document.getElementById('loader_parent').style.display="block"; 
          fetchData();
        });

        fetchData = async () => {
          setTimeout(function(){
            alert("Got data")
            document.getElementById("anydiv").style["filter"]="blur(0px)";
            document.getElementById('loader_parent').style.display="none";
          }, 3000);          
        }
 .loader_parent {
              position: absolute;
              left: 44%;
              top: 34%;
              width: 100%;
              height: 100%;
              z-index: 999;
              display: none;
          }

        .loader {
          border: 16px solid #f3f3f3;
          border-radius: 50%;
          border-top: 16px solid #3498db;
          width: 120px;
          height: 120px;
          -webkit-animation: spin 2s linear infinite; /* Safari */
          animation: spin 2s linear infinite;
        }

        /* Safari */
        @-webkit-keyframes spin {
          0% { -webkit-transform: rotate(0deg); }
          100% { -webkit-transform: rotate(360deg); }
        }

        @keyframes spin {
          0% { transform: rotate(0deg); }
          100% { transform: rotate(360deg); }
        }
        #anydiv{
          width: 500px;
          height: 500px;
          margin-left: auto;
          margin-right: auto;
          background-color: bisque;
          position: relative;
        }
        #fetch{
          width: 100%;
        }
<button id="fetch">
    fetchData
  </button>
  <div class="loader_parent no_spinner_display" id="loader_parent">
    <div class="loader" id="loader"></div>
  </div>
  <div id="anydiv">
    
  </div>
Sunny Rajdeep
  • 151
  • 1
  • 3