Often pure CSS spinners need quite a lot of div's or other HTML elements to accomplish the figure. The snake-like CSS spinners I found have mostly a tail not exceeding the half of a circle. My challenge was to build a pure CSS spinner without images (or base64 image-data), with only one HTML element, with a tail to 3/4 of the circle, and with support by Internet Explorer 11.
The inspiration to make this spinner was generated by Ana Tudor (thebabydino) 's article "Creating Yin and Yang Loaders On the Web" at CSS-tricks.com. When the spinner was ready, I became curious how it would behave in a real web page. That was quite an other story.
Francky Kleyneman
7 dec. 2018
19 jan. 2019: updating in progress!
The snake is circling in an orbit of a constant width (in the image the light green orbit), so the imaginary backbone of the snake has to end just in the middle of the snake orbit at the bottom.
In the HTML we have a <div>, in which the spinner and the loading element are positioned
together. The loading element can be an image, or maybe some other element. In this story an image is used, so we set the surrounding box as
<div class="imgBox">
The spinner uses a box-sizing: border-box; in order to get everything in the right position.
Then the spinner has the background-color of the page (or background-color of the imgBox, if the imgBox has
a different background-color). - In the illustrations of the construction steps over here:
The temptation is great to start with filling the circle with the background-color of the page/imgBox, and then to put several snake elements
on top of it. My experience: that will result in an extra HTML element inside the spinner !
The trick is just the opposite: we start with filling the complete circle in the green snake color, as background-color. Afterwards we can put
the not-snake parts in the circle, in the background-color of the page/imgBox.
So we have this:
<div class="imgBox">
<div class="spinner"></div>
<img src="images/..." alt="...">
</div>
<script> /* none */ <script>
.imgBox {
/* ... custom properties ... */
background: #77B7B; /* tmp > #EFEFEF */
position: relative;
}
.spinner {
position: absolute;
box-sizing: border-box;
top: 20px;
left: 50%;
margin-left: -25px;
width: 50px;
height: 50px;
background: green;
border-radius: 50%;
}
Result step 1 as image for visitors with disabled css:
It happens that there is no need to consume a first :before selector for the "transparent" outer part of the snake. You can
arrange this by sculpturing the borders of the spinner itself.
Then in the center of the green ink stain, and in the bottom right quadrant we need to cut some holes (= an overlay with the page/imgBox
background-color). But that's for later.
<div class="imgBox">
<div class="spinner"></div>
<img src="images/..." alt="...">
</div>
<script> /* none */ <script>
.imgBox {
/* nothing changed */
}
.spinner {
/* ... styles from above ... */
border-style: solid;
border-color: #EFEFEF;
border-width: 2px 0 6px 4px;
}
Result step 2 as image for visitors with disabled css:
Surprise of Microsoft ! - It appears that Internet Explorer 11 and (at this moment) Edge are a bit messy in rendering a colored background with a round-shaped border. They show a kind of shadow image of the contour of the circle, with some 33% opacity of the given background color.
The workaround is to throw away the background-color, and use a radial-gradient circle background-image instead (see Step 4).
.spinner {
/* ... styles from above ... */
background: green;
background-image:
radial-gradient(circle at 25px 100px,
transparent 24px, green 25px);
}
The counterfeited center hole is taking place in the :before selector, with a different radius for each of the 4 borders to get the desired spiral shape. The bottom right corner can stay rectangular.
<div class="imgBox">
<div class="spinner"></div>
<img src="images/..." alt="...">
</div>
<script> /* none */ <script>
.spinner:before {
position: absolute;
content: "";
top: 10px;
left: 4px;
width: 30px;
height: 33px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 130px;
border-top-left-radius: 110px;
border-top-right-radius: 100px;
background: DeepSkyBlue; /* tmp > #EFEFEF */
}
Result step 3 as image for visitors with disabled css:
Painting the bottom right quadrant with a solid background-color of the page/imageBox and then paste a green circle on top for the head
of the snake should ask for two hooks in the code, and we have only one :after selector left ...
We need, again, the inverse.
The green is already there, so the head circle can be transparent, and the rest could be painted in the background color in order to hide
the unnecessary green. But a negative border radius doesn't exist.
The rescue is to use a radial gradient background-image to get a transparent circle part (see: Lea Verou 's
article Beveled corners & negative border-radius
with CSS3 gradients).
<div class="imgBox">
<div class="spinner"></div>
<img src="images/..." alt="...">
</div>
<script> /* none */ <script>
.spinner:after {
position: absolute;
content: "";
top: 24px;
right: 0;
width: 25px;
height: 18px;
border-bottom-right-radius: 100px;
background-image:
radial-gradient(circle at 19px 0,
transparent 6px, fuchsia 6px);
/* tmp > #EFEFEF */
}
Result step 4 as image for visitors with disabled css:
The eyes of the snake (or is it a fish or a tadpole?) are a bit over the bottom half of the image (see Topography above), so we can't use the
:after for it: that can not exceed the bottom half. Also the :before is not suitable.
But the surface of the spinner itself has space enough, so the spinner CSS can get two radial gradient background-images (white eyes, the rest
transparent). They can be combined with the existing radial-gradient for the general background green of the snake. Note: the stacking order is
opposite to normal; first in CSS is on top!
<div class="imgBox">
<div class="spinner"></div>
<img src="images/..." alt="...">
</div>
<script> /* none */ <script>
.spinner {
/* ... as above ... */
background-image:
radial-gradient(circle at 37px 24px,
white 1.5px, transparent 1.5px),
radial-gradient(circle at 43px 25px,
white 1.5px, transparent 1.5px);
radial-gradient(circle at 25px 100px,
transparent 24px, green 25px);
background-repeat: no-repeat;
}
Result step 5 as image for visitors with disabled css:
Removing the background-color of the imgBox and adding the rotation: ready!
<div class="imgBox">
<div class="spinner"></div>
<img src="images/..." alt="...">
</div>
<script> /* none */ <script>
.imgBox {
/* ... custom properties ... */
background: #EFEFEF;
position: relative;
}
.spinner {
/* ... as above ... */
animation: 1.5s spinning linear
infinite;
}
@keyframes spinning {
to {transform: rotate(360deg); }
}
Result step 6 (without rotation) as image for visitors with disabled css: