Quiero crear una animación de carga css (o JS) representada en esta imagen:
Debería haber un rectángulo contenedor que tenga una clase. Luego, se debe aplicar algo de css a ese rectángulo para que haya algo de superposición. Primero es todo negro con un 50% de transparencia. Luego, con el tiempo, el negro se reduce a medida que gira en el sentido de las agujas del reloj, hasta que ya no hay más negro. Si le doy un valor de 100, debería ser todo negro, si le doy 0, no debería tener negro y solo mostrar la imagen subyacente por completo.
¿Alguien sabe algún tutorial o cómo crear esto?
Sin duda difícil, pero posible. Después de aproximadamente una hora de molienda, se me ocurrieron muchos divs y un código de trabajo:
const inner = document.getElementById('inner'); const black = document.getElementById('black'); const cover = document.getElementById('cover'); const overlay = document.getElementById('overlay'); const block = document.getElementById('block'); inner.addEventListener('animationend', e => { inner.style.display = 'none'; block.style.display = 'block'; }); cover.addEventListener('animationend', e => { alert('done!'); }); #wrapper { height: 100px; width: 100px; border: 5px solid black; position: relative; overflow: hidden; } #wrapper > div { position: absolute; height: 300%; width: 300%; top: 50%; left: 50%; transform: translate(-50%, -50%); } #cover { background-color: white; animation: spin 5s linear 5s forwards; } #overlay { background-color: black; width: 50%; height: 100%; position: absolute; left: 0; top: 0; } #inner { animation: spin 5s linear forwards; } #black { background-color: black; width: 50%; height: 100%; position: absolute; right: 0; top: 0; } @keyframes spin { from { transform: translate(-50%, -50%) rotate(0); } to { transform: translate(-50%, -50%) rotate(180deg); } } #block { display: none; background-color: white; height: 100%!important; width: 50%!important; transform: translate(0, 0)!important; position: absolute; top: 0!important; right: 0!important; z-index: 10 } /*Just for the demo*/ body, html { display: flex; justify-content: center; align-items: center; height: 100%; } <div id="wrapper"> <div id="cover"> <div id="overlay"></div> </div> <div id="inner"> <div id="black"></div> </div> <div id="block"></div> </div> ¿Cómo en el mundo funciona esto? Considere esta imagen (perdón por el terrible gráfico): 
El pequeño cuadrado en el medio representa #wrapper . El cuadrado más grande que lo rodea es su hijo #inner . En el lado derecho de #inner (con las rayas) está #black , que ocupa la mitad de su padre. #inner gira 180 grados, desaparece, luego #cover esencialmente hace lo mismo en el lado opuesto. #block evita que la parte negra de la #cover muestre en el otro lado. *¡Uf*, eso fue divertido!
Lo descubrí usando lienzo.
var canvas = document.getElementById('loading_animation'); var ctx = canvas.getContext('2d'); ctx.fillStyle = '#00000088'; var final = []; var list1 = [ [Math.floor(canvas.width / 2), 0], [Math.floor(canvas.width / 2), Math.floor(canvas.height / 2)] ]; var list2 = [ [canvas.width - 1, 0], [canvas.width - 1, canvas.height - 1], [0, canvas.height - 1], [0, 0] ]; var last = [Math.floor(canvas.width / 2), 0]; for (var x = Math.floor(canvas.width / 2); x < canvas.width; x += 1) { var path = list1.concat([[x, 0]]).concat(list2).concat([last]); final.push(path); } list2.shift(); for (var y = 1; y < canvas.height; y += 1) { var path = list1.concat([[canvas.width - 1, y]]).concat(list2).concat([last]); final.push(path); } list2.shift(); for (var x = canvas.width - 2; x >= 0; x -= 1) { var path = list1.concat([[x, canvas.height - 1]]).concat(list2).concat([last]); final.push(path); } list2.shift(); for (var y = canvas.height - 2; y >= 0; y -= 1) { var path = list1.concat([[0, y]]).concat(list2).concat([last]); final.push(path); } list2.shift(); for (var x = 1; x < Math.floor(canvas.width / 2); x += 1) { var path = list1.concat([[x, 0]]).concat(list2).concat([last]); final.push(path); } function RenderAnimation() { var path = final.shift(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.moveTo(path[0][0], path[0][1]); for (let i = 1; i < path.length; i++) { ctx.lineTo(path[i][0], path[i][1]); } ctx.closePath(); ctx.fill(); if (final.length > 0) { window.requestAnimationFrame(RenderAnimation); } else { ctx.clearRect(0, 0, canvas.width, canvas.height); } } RenderAnimation(); <!DOCTYPE html> <html> <head> <title>Title of the document</title> <style> canvas { background-image: url('https://media.wired.com/photos/5d09594a62bcb0c9752779d9/125:94/w_1994,h_1500,c_limit/Transpo_G70_TA-518126.jpg'); background-size: 100% 100%; background-repeat: no-repeat; } </style> </head> <body> <canvas id="loading_animation" width="300px" height="200px"></canvas> </body> </html>