Как создать этот эффект иллюминации с помощью CSS?

Я хотел бы смоделировать "сканирующий" свет, который покажет слова в рамке.

Идея состоит в том, чтобы показать слова в div class:.description; в соответствии с положением источника света. Если возможно, я хотел бы использовать CSS только для создания этого эффекта и использовать JavaScript только для перемещения сканирования (которое в дальнейшем станет 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>

Свободный перевод вопроса How to make this illumination effect with CSS от участника @Leo Letto.


Ответы (3 шт):

Автор решения: Alexandr_TT

Вы можете использовать прозрачный текст с градиентным фоном. Я использовал 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>

Свободный перевод ответа от участника @dgknca.

→ Ссылка
Автор решения: Alexandr_TT

Вот идея использования преобразования для повышения производительности:

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>

Свободный перевод ответа от участника @Temani Afif.

→ Ссылка
Автор решения: Alexandr_TT

Я предполагаю, что это для логотипа, и что текст должен продолжать отображаться, когда светящаяся палочка передала текст, как это происходит в сканере


Я бы использовал псевдоэлемент для элемента описания, поместил его сверху и использовал gradient-background, переходящий от прозрачного к темно-синему цвету фона. Используя градиент, вы можете добиться плавного размытия текста.

Затем я бы установил начальную точку темного цвета фона с помощью переменной CSS, которую я обновляю с помощью вашего метода onmousemove.

Код не учитывает разные размеры экрана, поэтому вам, вероятно, потребуется преобразовать пиксели в проценты, если вы хотите, чтобы ваша анимация была отзывчивой.

Я также изменил ваши классы на 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>

Свободный перевод ответа от участника @Rickard Elimää.

→ Ссылка