Showing a spinner over content - fade out some elements and disable clicking on some elements I am displaying a loading spinner inside of various elements. There are four potential states an element could be in:


Reduced opacity; unresponsive to pointer events.
Reduced opacity; responsive to pointer events.
Maintain opacity; unresponsive to pointer events.
Maintain opacity; responsive to pointer events.


I'm trying to write some CSS which is elegant, but also allows for enough flexibility to achieve the above goals.

I've attached a code-snippet to this post showing my implementation. Please note that it is intended only for modern browsers.

My concerns are:


I feel like this is the sort of thing which should be done using an overlay element and clever usage of z-index, but I also feel like my scenarios are too dynamic to support this sort of approach.
I am using the * selector with some filters applied to it in order to properly select elements. It is generally frowned upon to use the * selector. However, I don't believe that inverting my logic and applying .is-belowFadeout and .is-unclickableWhenSpinning classes is more appropriate. 


How should I be approaching this problem?



.content {
    width: 180px;
    height: 180px;
    position: relative;
    background-color: lightGray;
    padding: 10px;
}

.content-subContent {
    width: 40px;
    height: 40px;
    background-color: red;
    cursor: pointer;
    display: inline-block;
}

@-webkit-keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(359deg);
  }
}

.spinner {
    border: 1px solid #4ea6ea;
    border-left-color: transparent;
    border-top-color: transparent;
    border-radius: 50%;
    -webkit-animation: spin 600ms infinite linear;
    display: none;
    vertical-align: middle;
}

.spinner--large {
    width: 32px;
    height: 32px;
    border-width: 4px;
}

/* TODO: This seems like a poor way of doing this. What would be more robust? */
.is-showingSpinner &gt; *:not(.is-aboveFadeout):not(.spinner) {
    opacity: .2;
}

.is-showingSpinner &gt; *:not(.is-alwaysClickable) {
    pointer-events: none;
}

.is-showingSpinner &gt; .spinner {
    display: inline-block;
}

.u-overlay {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    top: 0;
}

.u-marginAuto {
    margin: auto;
}

.is-alwaysClickable:hover {
    background-color: #8b0000;
}
&lt;div class='content is-showingSpinner'&gt;
    &lt;div class="spinner spinner--large u-overlay u-marginAuto"&gt;&lt;/div&gt;
    &lt;div class='content-subContent'&gt;&lt;/div&gt;
    &lt;div class='content-subContent is-aboveFadeout'&gt;&lt;/div&gt;
    &lt;div class='content-subContent is-alwaysClickable'&gt;&lt;/div&gt;
    &lt;div class='content-subContent is-aboveFadeout is-alwaysClickable'&gt;&lt;/div&gt;
&lt;/div&gt;
First, For the universal selector, the performance diference will be negligible exept if you load 100s or 1000s of those element with into one web page.

This said, I reviewed you code and made several changes :

Used pseudo elements to make the spinner and the overlay for 2 reasons :


one unsemantic html tag removed
this alows to play with z-index so the red elements can be behind or in front of the overlay.


Used z-index instead of opacity to fade red elements out and moved the pointer-events property to the overlay pseudo element so that the .subContent can still be clicked.



.content {
    width: 180px; height: 180px;
    position: relative;
    padding: 10px;
}
.is-showingSpinner:before, .is-showingSpinner:after{
    content:'';
    position:absolute;
    bottom: 0; left: 0; right: 0; top: 0;
    z-index:2;
    pointer-events:none;
}
.is-showingSpinner:before {
    width:100%; height:100%;
    background-color: rgba(211, 211, 211, .8);
}
.is-showingSpinner:after { 
    margin:auto;
    width: 32px; height: 32px;
    border: 4px solid #4ea6ea;
    border-left-color: transparent;
    border-top-color: transparent;
    border-radius: 50%;
    -webkit-animation: spin 600ms infinite linear;
    animation: spin 600ms infinite linear;
}
.content-subContent {
    width: 40px; height: 40px;
    background-color: red;
    display: inline-block;
}
@-webkit-keyframes spin {
    0%   { transform: rotate(0deg); }
    100% { transform: rotate(359deg); }
}
/* TODO: This seems like a poor way of doing this. What would be more robust? */
 .is-showingSpinner &gt; .is-aboveFadeout {
    position:relative;
    z-index:2;
}
.is-alwaysClickable:hover {
    cursor: pointer;
    background-color: #8b0000;
}
&lt;div class='content is-showingSpinner'&gt;
    &lt;div class='content-subContent'&gt;&lt;/div&gt;
    &lt;div class='content-subContent is-aboveFadeout'&gt;&lt;/div&gt;
    &lt;div class='content-subContent is-alwaysClickable'&gt;&lt;/div&gt;
    &lt;div class='content-subContent is-aboveFadeout is-alwaysClickable'&gt;&lt;/div&gt;
&lt;/div&gt;




I also removed the classes you added to the spinner element. If you still need them, you can add them to the .content div to style the spinner ( :after pseudo element) as needed.