繁体   English   中英

如何用 CSS 制作这种照明效果

[英]How to make this illumination effect with CSS

我想模拟一个“扫描”灯,它将显示框中的单词,这是我现在的代码:

 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>

这个想法是根据扫描灯位置显示.description div 中的单词。 如果可能的话,我只想使用 CSS 来实现这种效果,并且只使用 JavaScript 来移动扫描(这将进一步成为 CSS 动画)。 我尝试使用一些伪元素,但效果不佳。 这是此动画应该如何工作的示例。

您可以使用带有渐变背景的透明文本。 我使用background-attachment: fixed和一个 CSS 变量来控制背景位置。

您可以增加背景大小(在本例中为 500 像素)以增加过渡平滑度。

 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>

这是另一个具有很长段落和多个隐藏文本的示例。 我们在这里控制 X 轴和 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.

这是一个使用转换以获得更好性能的想法

 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>

要仅将其应用于几个单词,您可以使用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>


如果您想要透明度,可以使其适用于任何背景的另一个想法:

 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>

炫酷的荧光棒!

我假设这是用于徽标,并且当荧光棒通过文本时应继续显示文本。


我会在 description 元素上使用一个伪元素,将它放在顶部并使用从透明到深蓝色背景颜色的渐变背景。 通过使用渐变,您可以实现文本的漂亮淡入。

然后,我将使用我通过您的 onmousemove 方法更新的 CSS 变量设置深色背景颜色的起点。

代码没有考虑不同的屏幕尺寸,因此如果您希望动画具有响应性,您可能需要将像素转换为百分比。

我还将您的课程更改为 id。 我认为通过使用 id 显示元素以某种方式被 javascript 使用更合适。 将元素绑定到变量也更容易。

 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>

我刚试过clipPath。 从技术上讲,它可以满足您的需求,但是当与发光效果结合时,动画 clipPath 的性能非常差(但没有效果会更好!)。 可能从图像之类的东西而不是框阴影构建发光会改善这一点。 (可以减少最外面的盒子阴影的大小)

 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>

像这样尝试:

 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>

此解决方案使用与横幅背景颜色相同的扫描右侧的封面。 封面随着扫描移动,因此当扫描向右移动时,它会显示左侧的文本。 它的工作原理是在本演示中单击它,但您可以在 JavaScript 中启动它,但最适合您。

似乎有点棘手。 想到的第一个解决方案可能是在灯条位置使用带有动态“停止点”的线性渐变。 渐变从暗 -> 透明(光条位置)-> 暗。 代码可能类似于:

.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);
}

不确定这是否可行,并且可能需要在某处放置一个框阴影,但也许它会给你一些想法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM