Me gustaría simular una luz de "escaneo" que revelará palabras en un cuadro, este es mi código por ahora:
const e = document.getElementsByClassName('scan')[0]; document.onmousemove = function(event){ e.style.left = `${event.clientX}px`; }; *{ margin: 0; padding: 0; } html, body{ width: 100%; min-height: 100vh; overflow-x: hidden; display: flex; } .banner{ width: 100vw; height: 100vh; display: flex; flex-grow: 1; flex-direction: row; align-items: center; background-color: #031321; } .banner .scan{ width: 7px; height: 80%; position: absolute; left: 30px; z-index: 3; transition: left 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner .description{ width: 100%; color: white; font-size: 3em; text-align: center; -webkit-user-select: none; -ms-user-select: none; user-select: none; } <div class="banner"> <div class="scan"></div> <div class="description"> Just trying something </div> </div> La idea es mostrar las palabras en el div .description según la posición de la luz de escaneo. Si es posible, me gustaría usar CSS solo para hacer este efecto, y usar JavaScript solo para mover el escaneo (que luego se convertirá en una animación CSS). Traté de usar algunos pseudo elementos, pero no funcionó bien. Aquí hay un ejemplo de cómo debería funcionar esta animación.
Parece un poco complicado. La primera solución que viene a la mente es tal vez usar un degradado lineal con un "punto de parada" dinámico en la posición de la barra de luz. El degradado va de oscuro -> transparente (posición de la barra clara) -> oscuro. El código tal vez se verá algo como:
.description-overlay { /* Replace 50% with the position of the light bar. Get brighter and more transparent as you approach the position of the light bar. */ background: linear-gradient(to right, #000, 50% hsla(0, 0%, 100%, 0.2), #000); }No estoy seguro de si esto funcionará y probablemente necesitaría una sombra de cuadro en algún lugar, pero tal vez le dé algunas ideas.
Acabo de probar clipPath. Técnicamente hace lo que necesita, pero el rendimiento del clipPath animado es bastante pobre cuando se combina con el efecto de brillo (¡pero mucho mejor sin él!). Posiblemente, construir el brillo a partir de algo como una imagen en lugar de una sombra de caja mejoraría esto. (al igual que reducir el tamaño de la sombra del cuadro más externo)
const e = document.getElementsByClassName('scan')[0]; const description = document.getElementsByClassName('description')[0]; document.onmousemove = function(event){ // comment out to compare performance e.style.left = `${event.clientX}px`; description.style.clipPath = `polygon(0 0, ${event.clientX}px 0, ${event.clientX}px 100%, 0 100%)`; }; *{ margin: 0; padding: 0; } html, body{ width: 100%; min-height: 100vh; overflow-x: hidden; display: flex; } .banner{ width: 100vw; height: 100vh; display: flex; flex-grow: 1; flex-direction: row; align-items: center; background-color: #031321; } .banner .scan{ width: 7px; height: 80%; position: absolute; left: 30px; z-index: 3; transition: left 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner .description{ width: 100%; color: white; font-size: 3em; text-align: center; -webkit-user-select: none; -ms-user-select: none; user-select: none; } <div class="banner"> <div class="scan"></div> <div class="description"> Just trying something </div> </div>Prueba así:
const e = document.getElementsByClassName('cover')[0]; e.addEventListener('click', animate); function animate() { e.classList.add('scanning'); } *{ margin: 0; padding: 0; } html, body{ width: 100%; min-height: 100vh; overflow-x: hidden; display: flex; } .banner{ width: 100vw; height: 100vh; display: flex; flex-grow: 1; flex-direction: row; align-items: center; background-color: #031321; } .banner .cover{ position: absolute; left: 30px; z-index: 3; height: 80%; width:100vw; background-color: #031321; transition: left 700ms ease-out 0s; } .banner .cover.scanning { left: calc(100% - 30px); } .banner .scan{ width: 7px; height:100%; transition: left 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner .description{ width: 100%; color: white; font-size: 3em; text-align: center; -webkit-user-select: none; -ms-user-select: none; user-select: none; } <div class="banner"> <div class="cover"> <div class="scan"> </div> </div> <div class="description"> Just trying something </div> </div>Esta solución utiliza una cubierta a la derecha del escaneo con el mismo color de fondo que el banner. La cubierta se mueve con el escaneo, por lo que cuando el escaneo se mueve hacia la derecha, revela el texto de la izquierda. Funciona haciendo clic en él en esta demostración, pero puede iniciarlo en JavaScript como sea mejor para usted.
¡Palito luminoso genial!
Supongo que esto es para un logotipo, y que el texto debe continuar mostrándose cuando la barra luminosa haya pasado el texto.
Usaría un pseudo-elemento en el elemento de descripción, lo colocaría en la parte superior y usaría un fondo degradado que pasaría de transparente a azul oscuro. Al usar un degradado, puede lograr un buen fundido de entrada del texto.
Luego establecería el punto de inicio del color de fondo oscuro con una variable CSS que actualizo a través de su método onmousemove.
El código no tiene en cuenta los diferentes tamaños de pantalla, por lo que probablemente necesite convertir píxeles a porcentaje, si desea que su animación responda.
También cambié tus clases a id. Creo que es más apropiado mostrar, mediante el uso de identificadores, que javascript usa el elemento de alguna manera. También es más fácil vincular los elementos a las variables.
const scanEl = document.getElementById('scan'); const descEl = document.getElementById("description") document.onmousemove = function(event){ let descriptionDisplacement = 100; scanEl.style.left = `${event.clientX}px`; descEl.style.setProperty("--background-shift", `${event.clientX + descriptionDisplacement}px`); }; *{ margin: 0; padding: 0; } html, body{ width: 100%; min-height: 100vh; overflow-x: hidden; display: flex; } .banner{ width: 100vw; height: 100vh; display: flex; flex-grow: 1; flex-direction: row; align-items: center; background-color: #031321; } .banner > #scan{ width: 7px; height: 80%; position: absolute; left: 30px; z-index: 3; transition: left 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner > #description{ width: 100%; color: white; font-size: 3em; text-align: center; -webkit-user-select: none; -ms-user-select: none; user-select: none; /* ADDED */ --background-shift: 0px; --background-shift-transparent: calc(var(--background-shift) - 150px); position: relative; } .banner > #description::before { content: ''; background: linear-gradient(to right, transparent var(--background-shift-transparent), #031321 var(--background-shift)); position: absolute; top: 0; bottom: 0; left: 0; right: 0; } <div class="banner"> <div id="scan"></div> <div id="description"> Just trying something </div> </div>Puede utilizar texto transparente con fondo degradado. Usé background-attachment: fixed y una variable CSS para controlar la posición del fondo.
Puede aumentar el tamaño del fondo (500 px en este ejemplo) para aumentar el suavizado de la transición.
const e = document.getElementsByClassName('scan')[0]; const hidden = document.getElementsByClassName('hidden')[0]; document.onmousemove = function(event) { e.style.left = `${event.clientX}px`; // ↓ background width (500px) / 2 hidden.style.setProperty("--pos", `${event.clientX - 250}px`); }; * { margin: 0; padding: 0; } html, body { width: 100%; min-height: 100vh; overflow-x: hidden; display: flex; } .banner { width: 100vw; height: 100vh; display: flex; flex-grow: 1; flex-direction: row; align-items: center; background-color: #031321; } .banner .scan { width: 7px; height: 80%; position: absolute; left: 30px; z-index: 3; transition: left 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner .description { width: 100%; color: white; font-size: 3em; text-align: center; -webkit-user-select: none; -ms-user-select: none; user-select: none; } .hidden { background: radial-gradient(dodgerblue 10%, #031321 50%) var(--pos) 50% / 500px 500px no-repeat fixed; -webkit-background-clip: text; -webkit-text-fill-color: transparent; } <div class="banner"> <div class="scan"></div> <div class="description"> Just <span class="hidden">hidden</span> something </div> </div>Aquí hay otro ejemplo con un párrafo muy largo y múltiples textos ocultos. Aquí controlamos los ejes X e Y.
const hiddens = document.querySelectorAll('.hidden'); document.addEventListener("mousemove", e => { hiddens.forEach(p => { // ↓ background width (400px) / 2 p.style.setProperty("--posX", `${e.clientX - 200}px`); p.style.setProperty("--posY", `${e.clientY - 200}px`); }); }); html, body { width: 100%; overflow-x: hidden; } body { background: #031321; color: #fff; font-size: 3rem; line-height: 1.5; padding: 20px; box-sizing: border-box; } .hidden { background: radial-gradient(dodgerblue 10%, #031321 50%) var(--posX) var(--posY) / 400px 400px no-repeat fixed; -webkit-background-clip: text; -webkit-text-fill-color: transparent; } Lorem ipsum dolor sit amet, <span class="hidden">consectetur</span> adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. <span class="hidden">Excepteur sint</span> occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea <span class="hidden">commodo</span> consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Aquí hay una idea que usa la transformación para tener un mejor rendimiento.
document.onmousemove = function(event){ document.body.style.setProperty("--p", `${event.clientX}px`); }; body{ margin: 0; overflow:hidden; } .banner{ height: 100vh; display: flex; align-items: center; background-color: #031321; } .banner::before{ content:""; width: 7px; height: 80%; position: absolute; left: 0; transform:translateX(var(--p,30px)); z-index: 3; transition: transform 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner .description{ color: white; font-size: 3em; text-align: center; width:100%; -webkit-user-select: none; -ms-user-select: none; user-select: none; overflow:hidden; position:relative; } .banner .description::before { content:""; position:absolute; top:0; right:0; bottom:0; width:200%; background:linear-gradient(to right,#031321 40%,transparent,#031321 60%); transform:translateX(var(--p,0px)); } <div class="banner"> <div class="description"> Just trying something </div> </div> Para aplicarlo solo a unas pocas palabras, juegas con z-index
document.onmousemove = function(event){ document.body.style.setProperty("--p", `${event.clientX}px`); }; body{ margin: 0; overflow:hidden; } .banner{ height: 100vh; display: flex; align-items: center; background-color: #031321; } .banner::before{ content:""; width: 7px; height: 80%; position: absolute; left: 0; transform:translateX(var(--p,30px)); z-index: 3; transition: transform 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner .description{ color: white; font-size: 3em; text-align: center; width:100%; -webkit-user-select: none; -ms-user-select: none; user-select: none; overflow:hidden; position:relative; z-index:0; } .banner .description::before { content:""; position:absolute; z-index:-1; top:0; right:0; bottom:0; width:200%; background:linear-gradient(to right,#031321 40%,transparent,#031321 60%); transform:translateX(var(--p,0px)); } .banner .description > span { position:relative; z-index:-2; color:lightblue; font-weight:bold; } <div class="banner"> <div class="description"> Just <span>trying</span> something <span>cool</span> </div> </div>Otra idea para que funcione con cualquier fondo en caso de que quieras transparencia:
document.onmousemove = function(event){ document.body.style.setProperty("--p", `${event.clientX}px`); }; body{ margin: 0; overflow:hidden; } .banner{ height: 100vh; display: flex; align-items: center; justify-content:center; color: white; font-size: 3em; background: url(https://picsum.photos/id/1018/800/800) center/cover; position:relative; z-index:0; -webkit-user-select: none; -ms-user-select: none; user-select: none; } .banner::before{ content:""; width: 7px; height: 80%; position: absolute; left: 0; transform:translateX(var(--p,30px)); z-index: 3; transition: transform 50ms ease-out 0s; border-radius: 15px; background-color: #fff; box-shadow: 0 0 15px 5px #fff, /* inner white */ 0 0 35px 15px #008cff, /* inner blue */ 0 0 350px 20px #0ff; /* outer cyan */ } .banner::after { content:""; position:absolute; z-index:-1; top:0; right:0; bottom:0; left:0; background:inherit; -webkit-mask: linear-gradient(to right,#fff 45%,transparent,#fff 55%) right calc(-1*var(--p,0px)) top 0/200% 100% no-repeat; } .banner > span { position:relative; z-index:-2; color:red; font-weight:bold; } <div class="banner"> Just <span>trying</span> something <span>cool</span> </div>