Skip to content

Commit

Permalink
Merge pull request #29 from jazzominy/post/gradient-progress-bar
Browse files Browse the repository at this point in the history
post on gradient progress bar
  • Loading branch information
jazzominy authored Nov 1, 2024
2 parents f7c0c9d + cde9e09 commit aafc30a
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 0 deletions.
162 changes: 162 additions & 0 deletions _posts/2024/11/2024-11-01-gradient-loader-part-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
author: "Jasmine Hirpara"
title: "Gradient progress bar - Part 1"
excerpt: "How to create a progress bar with single color gradient using CSS and use it to indicate scroll progress."
tags: [css, progress bar, css gradient]
permalink: /posts/gradient-loader
---

We all think of 2 or more colors when we hear the word gradient. Well...at least I do. That made me wonder what happens when we use a single color for a css gradient. So, to scratch that itch, i decided to check it out.

## CSS gradient

Lets start with a simple gradient. As per the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/CSS/gradient), a gradient is a smooth transition between two or more colors. The gradient can be linear or radial.

i will create a simple linear gradient with 2 colors.

```css
.gradient {
background: linear-gradient(to right, #dc6c6c, #4d4d9c);
}
```

which looks like this:
<style>
.gradient {
background: linear-gradient(to right, #dc6c6c, #4d4d9c);
height: 4rem;
}
</style>
<div class="gradient"></div>

i wont discuss about how to create a gradient here as there are many resources available online. Now there is a way to specify which color will occupy how much space in the gradient. This can be done using the `color-stop` value. It can be a percentage or a length value.

```css
.gradient-space {
background: linear-gradient(to right, #dc6c6c 30%, #4d4d9c 70%);
}
```

which looks like this:
<style>
.gradient-space {
background: linear-gradient(to right, #dc6c6c 30%, #4d4d9c 70%);
height: 4rem;
}
</style>
<div class="gradient-space"></div>

As you can see, the first color remains solid for the first 30% of the container's width and then from 30% to 70% the first color transitions to the second color. Then the second color remains solid for the rest of the container's width. What happens if the color-stop value is same? Lets find out.

```css
.gradient-same {
background: linear-gradient(to right, #dc6c6c 50%, #4d4d9c 50%);
}
```

which looks like this:
<style>
.gradient-same {
background: linear-gradient(to right, #dc6c6c 50%, #4d4d9c 50%);
height: 4rem;
}
</style>
<div class="gradient-same"></div>

As you can see, with the same value of color-stop for both colors, we didnt offer any space for the first color to transition to the second color. So there is a hard stop at 50% of the container's width and the transition switches to the second color with no color blending or interpolation. i have covered the same behavior in my [svg gradient animation](posts/svg-gradient-animation) post but for svg gradients.

## Single color gradient or is it?

Now let me try and see what happens when we use a single color for a gradient.

```css
.gradient-single {
background: linear-gradient(to right, #dc6c6c);
}
```

which looks like this:
<style>
.gradient-single {
background: linear-gradient(to right, #dc6c6c);
height: 4rem;
border: 1px solid #ccc;
text-align: center;
line-height: 3.5rem;
}
</style>
<div class="gradient-single">
oops! no gradient here
</div>

Well...the css complains and it does not render the gradient. So how do we create a gradient with a single color? Lets see what happens when we use the same color for both the colors in the gradient.

```css
.gradient-single-color {
background: linear-gradient(to right, #dc6c6c, #dc6c6c);
}
```

which looks like this:
<style>
.gradient-single-color {
background: linear-gradient(to right, #dc6c6c, #dc6c6c);
height: 4rem;
}
</style>
<div class="gradient-single-color"></div>

Phew!! we have something. Not much but a solid color background. Let me add a twist to this. What if the second color is transparent?

```css
.gradient-single-transparent {
background: linear-gradient(to right, #dc6c6c, transparent);
}
```

which looks like this:
<style>
.gradient-single-transparent {
background: linear-gradient(to right, #dc6c6c, transparent);
height: 4rem;
}
</style>
<div class="gradient-single-transparent"></div>

Well...we have a gradient now. The color gradually transitions to transparency. If we do not specify the color-stop value, it is assumed to be 0% for the first color and 100% for the second color. Now lets see what happens when we specify the color-stop value for the second color which is transparent.

```css
.gradient-single-transparent-space {
background: linear-gradient(to right, #dc6c6c, transparent 50%);
}
```

which looks like this:
<style>
.gradient-single-transparent-space {
background: linear-gradient(to right, #dc6c6c, transparent 50%);
height: 4rem;
}
</style>
<div class="gradient-single-transparent-space"></div>

The color transitions to transparency at 50% of the container's width. If you understood this, then you would have guessed what happens when we specify the same color-stop value for both colors.

```css
.gradient-single-transparent-same {
background: linear-gradient(to right, #dc6c6c 50%, transparent 50%);
}
```

which looks like this:
<style>
.gradient-single-transparent-same {
background: linear-gradient(to right, #dc6c6c 50%, transparent 50%);
height: 4rem;
}
</style>
<div class="gradient-single-transparent-same"></div>

Oh my!! we have a progress bar here with 50% of the container's width filled with the color and the rest with transparency 😎

So far so good. We now have a static gradient progress bar. Making it dynamic is discussed in the [next part](/posts/gradient-loader-part-2) of this post.
129 changes: 129 additions & 0 deletions _posts/2024/11/2024-11-01-gradient-loader-part-2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
author: "Jasmine Hirpara"
title: "Gradient progress bar - Part 2"
excerpt: "How to use css variable to create a dynamic gradient progress bar to indicate scroll progress."
tags: [css, progress bar, css gradient]
permalink: /posts/gradient-loader-part-2
---

In the [previous post](/posts/gradient-loader), i created a simple static gradient progress bar. In this post, i will show you how to make it dynamic to indicate scroll progress.

## Element scroll event

Whenever the content of an element overflows, the element gets a scrollbar either horizontally or vertically or both. We can use the `scroll` event to detect when the user scrolls the content of an element.

```js
const element = document.querySelector('.gradient-progress');
element.addEventListener('scroll', (event) => {
// code to update the progress bar
});
```

## Tracking the scroll progress

To track the scroll progress, we need to use the following properties of the element:
- [scrollTop](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop)
- [scrollHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight)
- [clientHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight)

Here is how we can calculate the scroll progress:

```js
element.addEventListener('scroll', () => {
const progress = Math.round((element.scrollTop / (element.scrollHeight - element.clientHeight)) * 100);
});
```
{: .snippet}

Here `element.scrollTop` is the number of pixels that the content of the element is scrolled vertically, `element.scrollHeight` is the total height of the content including the overflowed content and `element.clientHeight` is the height of the element including the padding.

## Updating the scroll progress

Now that we have the scroll progress, how can i link it to the progress bar? There may be different ways to do this. i will show you one way to do it. i will use a css variable to update the progress bar.

```js
element.addEventListener('scroll', () => {
const progress = Math.round((element.scrollTop / (element.scrollHeight - element.clientHeight)) * 100);
element.style.setProperty('--g-progress', `${progress}%`);
});
```
{: .snippet}

Here i am setting the `--g-progress` css variable on the element. This variable will be used to update the gradient of the progress bar.

## Styling a pseudo element to show the grdient progress bar

To create a gradient progress bar, i will use a pseudo element `::before` and apply a gradient to it. i will use the `--g-progress` variable to update the gradient.

```css
.gradient-progress {
position: relative;
overflow-y: auto;
max-height: 30vh;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
padding-top: 0;
}

.gradient-progress::before {
content: '';
display: block;
position: sticky;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 5px;
background: linear-gradient(to right, #dc6c6c var(--g-progress, 0%), transparent var(--g-progress, 0%));
}
```
{: .snippet}

```html
<div class="gradient-progress">
<!-- content goes here -->
</div>
```

Here in css, i have set the height of the pseudo element to `5px` and applied a gradient to it. The gradient color-stops are set using the `--g-progress` variable. The `var(--g-progress, 0%)` means that if the `--g-progress` variable is not set, then the default value will be `0%`. Now whenever we scroll the content, the value of the `--g-progress` variable will be updated using the scroll event listener. This will update the gradient color-stops of the pseudo element and show the progress accordingly.

i have created an inline demo below. Scroll the content to see the progress bar in action.

<style>
.gradient-progress {
position: relative;
overflow-y: auto;
max-height: 30vh;
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
padding-top: 0;
}

.gradient-progress::before {
content: '';
display: block;
position: sticky;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 5px;
background: linear-gradient(to right, #dc6c6c var(--g-progress, 0%), transparent var(--g-progress, 0%));
}
</style>

<div class="gradient-progress">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>

<script>
const element = document.querySelector('.gradient-progress');
element.addEventListener('scroll', () => {
const progress = Math.round((element.scrollTop / (element.scrollHeight - element.clientHeight)) * 100);
element.style.setProperty('--g-progress', `${progress}%`);
});
</script>

i have used the same concept for the blue progress bar that you see at the top of the page which indicates the scroll progress of the page. Now that you are here, it should indicate 100% 😀. Hope you learned something.
5 changes: 5 additions & 0 deletions tags/css-gradient/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
layout: tag
title: "Tag: css gradient"
tag: css gradient
---
5 changes: 5 additions & 0 deletions tags/css/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
layout: tag
title: "Tag: css"
tag: css
---
5 changes: 5 additions & 0 deletions tags/progress-bar/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
layout: tag
title: "Tag: progress bar"
tag: progress bar
---

0 comments on commit aafc30a

Please sign in to comment.