I like to invent various interface elements, and once I wanted to make a preloader.
To implement it, I needed the following markup:
<div class="preloader"></div>
According to my idea, the preloader consists of two squares: a large one with a size of 60x60px and a small one - 15x15px.
Since the big square is the outline for a small square, for its implementation I used the div element .prealoder itself. But for the nested square I needed the pseudo-element before.
.preloader { width: 60px; height: 60px; border: 2px solid #fff; position: relative; } .preloader::before { content: ""; width: 15px; height: 15px; background-color: #fff; position: absolute; top: calc(50% - 7.5px); left: calc(50% - 7.5px); }
For the animation, I wrote the following script:
.preloader::before { animation: preloader 2.25s ease-out both infinite; } @keyframes preloader { 0%, 10%, 90%, 100% { transform: translate3d(0, 0, 0) scale(0); } 20%, 70% { transform: translate3d(0, 0, 0) scale(1); } 30% { transform: translate3d(-15px, -15px, 0) scale(1); } 40% { transform: translate3d(15px, -15px, 0) scale(1); } 50% { transform: translate3d(15px, 15px, 0) scale(1); } 60% { transform: translate3d(-15px, 15px, 0) scale(1); } }
In addition to the main display, I wanted to add a preloader with the dimensions of the contour 120x120px and the internal square 30x30px.
.preloader_l { width: 120px; height: 120px; } .preloader_l::before { width: 30px; height: 30px; top: calc(50% - 15px); left: calc(50% - 15px); animation-name: preloader-l; } @keyframes preloader-l { 0%, 10%, 90%, 100% { transform: translate3d(0, 0, 0) scale(0); } 20%, 70% { transform: translate3d(0, 0, 0) scale(1); } 30% { transform: translate3d(-30px, -30px, 0) scale(1); } 40% { transform: translate3d(30px, -30px, 0) scale(1); } 50% { transform: translate3d(30px, 30px, 0) scale(1); } 60% { transform: translate3d(-30px, 30px, 0) scale(1); } }
Everything turned out as intended. I went to drink tea, and the thought came to me that if I needed to add another size, I would have to specify dimensions (width and height), position (top and left) and animation script again.
In order to fix this, I will use the unit of measure em. With it, I can bind all property values to a single font-size value, with which I will switch the preloader sizes.
As a result, the code will change as follows:
/* Xem Xpx em px. */ .preloader { width: Xem; height: Xem; font-size: Xpx; } .preloader::before { width: Xem; height: Xem; animation: preloader 2.25s ease-out both infinite; } @keyframes preloader { 0%, 10%, 90%, 100% { transform: translate3d(0, 0, 0) scale(0); } 20%, 70% { transform: translate3d(0, 0, 0) scale(1); } 30% { transform: translate3d(-Xem, -Xem, 0) scale(1); } 40% { transform: translate3d(Xem, -Xem, 0) scale(1); } 50% { transform: translate3d(Xem, Xem, 0) scale(1); } 60% { transform: translate3d(-Xem, Xem, 0) scale(1); } } .preloader_l { font-size: Xpx; }
To solve the problem, the em calculation formula is useful to me:
Vem = Vpx / Fs
Vpx is the value in px that was previously set. The value of Fs is the chosen number, which is convenient to divide the value of Vpx.
Now you can start calculating the following properties:
.preloader { width: 60px; height: 60px; } .preloader::before { width: 15px; height: 15px; top: calc(50% - 7.5px); left: calc(50% - 7.5px); }
To do this, select the font-size value. In my opinion, this property will set the dimensions of the contour, so it is logical to use the same value that is now set for width and height.
Width(em) = 60px / 60px = 1em Height(em) = 60px / 60px = 1em
.preloader { width: 1em; height: 1em; font-size: 60px; }
Next, I’ll calculate the width, height, top, and left values for the .preloader :: before element. To do this, it is no longer necessary to select the font-size value, because it will be inherited from the font-size of the .preloader element.
Width(em) = 15px / 60px = 0.25em Height(em) = 15px / 60px = 0.25em Top(em) = 7.5px / 60px = 0.125em; Left(em) = 7.5px / 60px = 0.125em;
.preloader::before { width: 0.25em; height: 0.25em; top: calc(50% - 0.125em); left: calc(50% - 0.125em); }
It remains to change the values in the animation script.
@keyframes preloader { 0%, 10%, 90%, 100% { transform: translate3d(0, 0, 0) scale(0); } 20%, 70% { transform: translate3d(0, 0, 0) scale(1); } 30% { transform: translate3d(-15px, -15px, 0) scale(1); } 40% { transform: translate3d(15px, -15px, 0) scale(1); } 50% { transform: translate3d(15px, 15px, 0) scale(1); } 60% { transform: translate3d(-15px, 15px, 0) scale(1); } }
If you look at the values without the sign, you only need to translate 15px. I have already done this before, and they correspond to 0.25em.
@keyframes preloader { 0%, 10%, 90%, 100% { transform: translate3d(0, 0, 0) scale(0); } 20%, 70% { transform: translate3d(0, 0, 0) scale(1); } 30% { transform: translate3d(-0.25em, -0.25em, 0) scale(1); } 40% { transform: translate3d(0.25em, -0.25em, 0) scale(1); } 50% { transform: translate3d(0.25em, 0.25em, 0) scale(1); } 60% { transform: translate3d(-0.25em, 0.25em, 0) scale(1); } }
Now you can set the size of 120px for the element .preloader_l.
.preloader_l { font-size: 120px; }
It's worth noting that I deleted the .preloader_l :: before CSS rule and the preloader-l animation script because they are no longer needed.
In order to consolidate this trick, I have prepared a task. It is necessary to convert the values from px to em, which are used in the animation script. All previously calculated property values are preserved.
@keyframes preloader { 0%, 70%, 100% { transform: translate3d(0, 0, 0) scale(0); } 10%, 60% { transform: translate3d(0, 0, 0) scale(1); } 20% { transform: translate3d(9px, -21px, 0) scale(1); } 30% { transform: translate3d(3px, 21px, 0) scale(1); } 40% { transform: translate3d(-9px, -21px, 0) scale(1); } 50% { transform: translate3d(-9px, 21px, 0) scale(1); } }
Source: https://habr.com/ru/post/443292/