Wie man diesen Beleuchtungseffekt mit CSS macht

Lesezeit: 11 Minuten

Benutzer-Avatar
Leo Letto

Ich möchte ein “Scan” -Licht simulieren, das Wörter in einem Feld anzeigt. Dies ist jetzt mein Code:

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>

Die Idee ist, die Wörter in der Show zu zeigen .description div entsprechend der Scanlichtposition. Wenn möglich, möchte ich nur CSS verwenden, um diesen Effekt zu erzielen, und JavaScript nur verwenden, um den Scan zu verschieben (der später zu einer CSS-Animation wird). Ich habe versucht, einige Pseudoelemente zu verwenden, aber es hat nicht gut funktioniert. Hier ist ein Beispiel dafür, wie diese Animation funktionieren sollte.

Benutzer-Avatar
doğukan

Sie können transparenten Text mit Hintergrund mit Farbverlauf verwenden. ich benutzte background-attachment: fixed und eine CSS-Variable zur Steuerung der Hintergrundposition.

Sie können die Hintergrundgröße (in diesem Beispiel 500 Pixel) erhöhen, um die Übergangsglättung zu verbessern.

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>

Hier ist ein weiteres Beispiel mit sehr langem Absatz und mehreren versteckten Texten. Wir steuern hier sowohl die X- als auch die Y-Achse.

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.

Benutzer-Avatar
Temani Afif

Hier ist eine Idee, die Transformation verwendet, um eine bessere Leistung zu erzielen

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>

Um es auf nur wenige Wörter anzuwenden, spielen Sie mit 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>

Eine weitere Idee, damit es mit jedem Hintergrund funktioniert, falls Sie Transparenz wünschen:

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>

Benutzer-Avatar
Rickard Elimä

Cooler Leuchtstab!

Ich gehe davon aus, dass dies für ein Logo ist und dass der Text weiterhin angezeigt werden soll, wenn der Leuchtstab den Text passiert hat.


Ich würde ein Pseudo-Element auf dem Beschreibungselement verwenden, es darauf platzieren und einen Verlaufshintergrund verwenden, der von transparent zu der dunkelblauen Hintergrundfarbe geht. Durch die Verwendung eines Farbverlaufs können Sie eine schöne Einblendung des Textes erzielen.

Ich würde dann den Startpunkt der dunklen Hintergrundfarbe mit einer CSS-Variablen festlegen, die ich über Ihre onmousemove-Methode aktualisiere.

Der Code berücksichtigt keine unterschiedlichen Bildschirmgrößen, daher müssen Sie wahrscheinlich Pixel in Prozent umwandeln, wenn Ihre Animation reaktionsschnell sein soll.

Ich habe auch Ihre Klassen auf id geändert. Ich denke, es ist angemessener, durch die Verwendung von IDs zu zeigen, dass das Element irgendwie von Javascript verwendet wird. Es ist auch einfacher, die Elemente an Variablen zu binden.

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>

Benutzer-Avatar
Ilmarinen123

Ich habe gerade ClipPath ausprobiert. Technisch tut es, was Sie brauchen, aber die Leistung des animierten clipPath ist ziemlich schlecht, wenn es mit dem Glow-Effekt kombiniert wird (aber viel besser ohne!). Möglicherweise würde es dies verbessern, das Leuchten aus so etwas wie einem Bild anstelle eines Kastenschattens aufzubauen. (ebenso wie die Reduzierung der Größe des äußersten Kastenschattens)

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>

Versuchen Sie es so:

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>

Diese Lösung verwendet rechts neben dem Scan ein Cover mit der gleichen Hintergrundfarbe wie das Banner. Das Cover bewegt sich mit dem Scan, wenn sich der Scan also nach rechts bewegt, wird der Text auf der linken Seite angezeigt. Es funktioniert, indem Sie in dieser Demo darauf klicken, aber Sie können es in JavaScript starten, wie es für Sie am besten ist.

  • Vollständiges Ein-/Ausblenden beim Mausklick scheint nicht der gewünschten Ausgabe von OP zum Verschieben der Leiste/Ausblenden des Textes basierend auf der Cursorposition zu entsprechen.

    – TylerH

    12. November 2020 um 19:52 Uhr

  • Einverstanden. Das ist genau das, was ich mit “Scannen” und “Verwenden Sie JavaScript nur zum Verschieben des Scans” gemeint habe.

    – sbgib

    13. November 2020 um 8:00 Uhr

Scheint ein wenig knifflig zu sein. Die erste Lösung, die mir in den Sinn kommt, ist vielleicht die Verwendung eines linearen Farbverlaufs mit einem dynamischen „Haltepunkt“ an der Position des Lichtbalkens. Der Farbverlauf geht von dunkel -> transparent (Position heller Balken) -> dunkel. Der Code sieht vielleicht so aus:

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

Ich bin mir nicht sicher, ob dies funktionieren wird, und es müsste wahrscheinlich irgendwo ein Box-Schatten eingefügt werden, aber vielleicht gibt es Ihnen einige Ideen.

  • Vollständiges Ein-/Ausblenden beim Mausklick scheint nicht der gewünschten Ausgabe von OP zum Verschieben der Leiste/Ausblenden des Textes basierend auf der Cursorposition zu entsprechen.

    – TylerH

    12. November 2020 um 19:52 Uhr

  • Einverstanden. Das ist genau das, was ich mit “Scannen” und “Verwenden Sie JavaScript nur zum Verschieben des Scans” gemeint habe.

    – sbgib

    13. November 2020 um 8:00 Uhr

1329770cookie-checkWie man diesen Beleuchtungseffekt mit CSS macht

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy