Windows 10 button hover effect using HTML, CSS, and vanilla JS
Tags: html, css, javascript, webdev
Published: 2021-04-23 09:44:47

##Table of Contents
1. [Introduction](#introduction)
2. [Observations](#observations)
3. [Getting Started](#getting-started)
4. [The Crux](#the-crux)
    1. [Calculating the cursor position](#calculating-the-cursor-position)
    2. [Creating the spotlight](#creating-the-spotlight)
    3. [Applying spotlight to borders](#applying-spotlight-to-borders)
5. [Additional Resources](#additional-resources)


##Introduction
If you are one of those who are fascinated by the windows 10 hover effect and would like to re-create it then you have come to the right place! In this quick tutorial, I will explain how you can get the same effect using CSS and a little bit of vanilla js.

Before starting with the explanation, let us first have a look at the final result.


![Win Button codepen output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h2c7ft6mspgvoc5e1w2u.gif)

 

{% codepen https://codepen.io/jashgopani/pen/QWdqMLZ %}

##Observations

1. A spotlight that follows the cursor inside the element.
2. The highlighting of the border according to the cursor position
![Button Hover](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2d94ktvkqwwkp26jxra.gif)

##Getting Started

Let us create some items on our page.

### HTML
```html
<html>

<head>
  <title>Windows hover effect</title>
</head>

<body>
  <h1>Windows 10 Button Hover Effect</h1>

  <div class="win-grid">
    <div class="win-btn" id="1">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="2">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="3">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="4">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="5">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="6">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="7">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="8">This is a windows 10 hoverable item</div>
    <div class="win-btn" id="9">This is a windows 10 hoverable item</div>
  </div>

</body>

</html>
```

Without CSS, our page looks something like this

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9q86oynxouh1erfgf6fb.png) 

### CSS
```css
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100&display=swap");

* {
  box-sizing: border-box;
  color: white;
  font-family: "Noto Sans JP", sans-serif;
  letter-spacing: 2px;
}

body {
  background-color: black;
  display: flex;
  flex-flow: column wrap;
  justofy-content: center;
  align-items: center;
}

.win-grid {
  border: 1px solid white;
  letter-spacing: 2px;
  color: white;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: stretch;
  text-align: center;
  grid-gap: 1rem;
  padding: 5rem;
}

.win-btn {
  padding: 2rem;
  text-align: center;
  border: none;
  border-radius: 0px;
  background: black;
  color: white;
  border: 1px solid transparent;
}

button:focus {
  outline: none;
}

```

After adding the above CSS styles, we get the following look
![Button Hover with CSS only](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9qr0oqh2pf6rvxm5rki.gif)

 
At this point, we are halfway through the code. We have our target elements set up on DOM, now the only part remaining is applying the highlight effect based on cursor movement.

One thing to note here is that we keep the border of the elements transparent by default and change it based on the cursor position ahead. 

## The Crux

`For each` target element, we need to `add event listeners` which listen for `mouse movements`. We *apply CSS* styles when the *cursor moves over* an element and *remove* those effects when the *cursor leaves* an element. 

See below how the lines above convert to JS Code

```javascript
document.querySelectorAll(".win-btn").forEach((b) => {
  
  b.onmouseleave = (e) => {
    //remove effects
  };

  b.addEventListener("mousemove", (e) => {
    //add effects
  });
});
```

> Notice, I am using the new *property based event listener* syntax wherever applicable because it is concise and it **overrides any other event listeners** for the same event on the same object as compared to `addEventListener` which allows you to add multiple event listeners for the same event and same object.

Next, we need to calculate the position of the cursor inside the target element and draw a spotlight circle of a specific radius considering that point as the center of the circle.

##Calculating the cursor position 
Simple logic to calculate position relative to the element: find the difference of cursor position coordinates and starting coordinates of the target element. Refer to the illustration and code below for a better understanding.


![Cursor coordinates illustration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1k800snodniuxu7adtg.png)

 

```javascript
const rect = e.target.getBoundingClientRect();
const x = e.clientX - rect.left; //x position within the element.
const y = e.clientY - rect.top; //y position within the element.
``` 

##Creating the spotlight

Now simply add a circular radial gradient to our target element with the current cursor position as the center and the colors of the gradient go from white (with low opacity; 0.2) to transparent (opacity 0 basically).

So our radial gradient becomes
```javascript
radial-gradient(circle at ${x}px ${y}px , rgba(255,255,255,0.2),rgba(255,255,255,0) )
```
##Applying spotlight to borders
The border magic happens when we apply a similar gradient to the border of the image! For such special types of borders, we use the `border-image` CSS property as gradient functions in CSS return images! We use the same gradient with slightly more intensity (opacity 0.4).

The syntax for `border-image` is as follows

```javascript
radial-gradient(20% 75% at ${x}px ${y}px ,rgba(255,255,255,0.7),rgba(255,255,255,0.1) ) 9 / 1px / 0px stretch 
```
Now you might be wondering what are these extra values...So let me explain those also...

The syntax for `border-image` is
> source | slice | border-width | border-outset | slice-repeat

Now you might be wondering what are those extra values with the radial gradient.

1. **20% 75%:** The horizontal and vertical radius of the gradient ellipse shape. % indicates that much % of parent’s width and height respectively.
2. **slice (9):** the `radial-gradient` is our *source* image for the border and the `slice` property divides that image into 9 regions which it then applies to edges and corners of the element specified.
3. **width (2px):** the thickness of the `border-image`
4. **outset (2px):** the space between the border and the element
5. **repeat (stretch):** this value specifies how the 9 regions, are applied to the image and edges. How the regions 5,6,7,8 specified here are repeated in the border

> ℹ: I have attached an amazing tool for playing around with `border-image` (developed my MDN) so you can get a better understanding of this.

At last, we must not forget to remove these styles when the cursor moves out of our element.
Our complete JS code looks like this

```javascript
document.querySelectorAll(".win-btn").forEach((b) => {
  console.log(b);
  b.onmouseleave = (e) => {
    e.target.style.background = "black";
    e.target.style.borderImage = null;
  };

  b.addEventListener("mousemove", (e) => {
    const rect = e.target.getBoundingClientRect();
    const x = e.clientX - rect.left; //x position within the element.
    const y = e.clientY - rect.top; //y position within the element.
    e.target.style.background = `radial-gradient(circle at ${x}px ${y}px , rgba(255,255,255,0.2),rgba(255,255,255,0) )`;
    e.target.style.borderImage = `radial-gradient(20% 75% at ${x}px ${y}px ,rgba(255,255,255,0.7),rgba(255,255,255,0.1) ) 1 / 1px / 0px stretch `;
  });
});

```

That's all folks :)

Hope this article has helped you understand, how to breakdown logically an effect into CSS and JS code.
Feel free to comment if you have any questions or issues and I'll try to help you! 😁

* As promised, I have published an article on [Windows 10 grid hover effect using HTML, CSS, and vanilla JS](https://dev.to/jashgopani/windows-10-grid-hover-effect-using-html-css-and-vanilla-js-42d9). Do check that out also!

##Additional Resources
You can refer to the additional resources mentioned below for a better understanding of CSS and JS.

1. [MDN Docs - CSS](https://developer.mozilla.org/en-US/docs/Web/CSS)
2. [MDN Docs - JavaScript](https://developer.mozilla.org/en-US/docs/Web/JS)
3. [CSS Tricks](https://css-tricks.com/snippets/css/complete-guide-grid/)
4. [Border-Image generator tool](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Background_and_Borders/Border-image_generator)