Spotlight on hidden background
Tags: css, javascript, tutorial
Published: 2024-07-07 16:15:17

---
title: Spotlight on hidden background
published: true
date: 2024-07-07 16:05:12 UTC
tags: css,js,tutorial
canonical_url: https://blog.nicm42.co.uk/spotlight-on-hidden-background
---

The logical way of thinking about this is to have a background (colour, gradient or image) with an overlay that hides it. The spotlight then makes that part of the overlay transparent. But that's all we actually want to make it look like we're doing. Instead, we can have the background on top and hide most of it. Here's how to do it.

```html
<div class="spotlight"></div>
```

```css
html,
body {
  height: 100%;
  margin: 0;
}

body {
  position: relative;
  width: 100%;
  height: 100%;
  background-color: black;
}
```

This gives us a black background that fills the screen. The `.spotlight` div will be a circle that reveals the background.

## The spotlight

```css
.spotlight {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to bottom right, 
    red, orange, yellow, green, blue, indigo, violet,
    red, orange, yellow, green, blue, indigo, violet);
  clip-path: circle(5% at 50% 50%);
}
```

I've positioned the spotlight absolutely so we can move it with the mouse. It fills the screen and I've added a rainbow background gradient, since I created it in June which was Pride month. It's not one where every colour perfectly blends into another, and there's some pink between the violet and red. But since we'll only get to see a little of it at a time, it doesn't matter.

The `clip-path` creates a small circle in the middle of the screen. Anything outside of it is hidden, so we only see the background inside that small circle.

## Moving the spotlight

To move the spotlight, all we need to do is to update the clip-path circle position. The easiest way to do that is to use custom properties:

```css
.spotlight {
  --left-circle: 50%;
  --top-circle: 50%;
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to bottom right, 
    red, orange, yellow, green, blue, indigo, violet,
    red, orange, yellow, green, blue, indigo, violet);
  clip-path: circle(5% at var(--left-circle) var(--top-circle));
}
```

Then we can use the mousemove event listener to detect where the mouse is:

```js
const spotlight = document.querySelector('.spotlight');

spotlight.addEventListener('mousemove', e => {
  spotlight.style.setProperty('--left-circle', e.clientX + 'px');
  spotlight.style.setProperty('--top-circle', e.clientY + 'px');
});
```

clientX and clientY will get us the horizontal and vertical mouse position, where (0, 0) is the top left. This means that if you move the mouse to the very top left of the screen the clip-path becomes `clip-path: circle(5% at 0 0);`

All you have to do is to move your mouse around you can see different parts of the background in the circle.

## Adding some blur

The edge of the circle being less sharp would make it look better. A little more like a spotlight, which has a lot of light in the centre and less at the edges. However, adding blur to the edge is a little complicated when you have a clip-path.

If you didn't have a `clip-path`, then a `box-shadow` would do it. However, our .spotlight fills the screen, so we won't be able to see a shadow. A `drop-shadow` doesn't help because it has the same problem.

The solution is to add a `drop-shadow` to the element, but then have another inside it with the `clip-path` and background:

```css
.spotlight {
  --left-circle: 50%;
  --top-circle: 50%;
  position: absolute;
  inset: 0;
  filter: drop-shadow(0 0 20px rgba(255, 255, 255, .75));
  
  &::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image: linear-gradient(to bottom right, red, orange, yellow, green, blue, indigo, violet, red, orange, yellow, green, blue, indigo, violet);
    clip-path: circle(5% at var(--left-circle) var(--top-circle));
  }
}
```

And there you have a white blur around the circle.

## Final code

Here is the final code:

{% codepen https://codepen.io/nicm42/pen/vYwdapX %}