Demo - Code Snippets
Creates a progress bar indicating the scroll percentage of the page.
- Use
position: fixed
and a largez-index
value to place the element at the top of the page and above any content. - Use
EventTarget.addEventListener()
along withElement.scrollTop
to determine the scroll percentage of the document and apply it to the width of the element.
💠 Core
<div id="scroll_progress_bar"></div>
#scroll_progress_bar {
position: fixed;
top: 0;
width: 0%;
height: 4px;
background: #7983ff;
z-index: 10000;
}
const scrollProgress = document.getElementById('scroll_progress_bar');
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
window.addEventListener('scroll', () => {
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
scrollProgress.style.width = `${(scrollTop / height) * 100}%`;
});
✍️ Implement - Vue3
<!-- ScrollProgress.vue -->
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
root: {
type: String,
default: '#app',
required: false,
},
height: {
type: String,
default: '4px',
required: false,
},
theme: {
type: String,
default: '#3eaf7c',
required: false,
validator: (v: string) => {
document.head.style.color = v
const q = document.head.style.color
document.head.style.color = ''
return !!q
},
},
placement: {
type: String,
default: 'top',
required: false,
validator: (v: string) => {
if (!['top', 'bottom'].includes(v)) {
console.error(`[ScrollProgress(placement)] The value must match one of these strings: 'top' | 'bottom'`)
return false
}
return true
},
},
zIndex: {
type: [Number, String],
default: 10000,
required: false,
validator: (v: string) => /^-?[\d]+$/.test(v),
},
})
const el = ref(null)
const appHeight = ref(0)
onMounted(() => {
const targetNode = document.querySelector(props.root)
if (!targetNode) return console.error(`[ScrollProgress(root)] '${props.root}' is invalid`)
const config = { attributes: true, childList: false, subtree: true }
const observer = new MutationObserver((mutationsList: MutationRecord[]) => {
// Use traditional 'for loops' for IE 11
for(let mutation of mutationsList) {
if (mutation.type === 'attributes') {
appHeight.value = document.documentElement.scrollHeight
}
}
})
observer.observe(targetNode, config)
})
const listener = () => {
const scrollProgress = el.value
const height = appHeight.value - document.documentElement.clientHeight
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop
scrollProgress.style.width = `${(scrollTop / height) * 100}%`
}
onMounted(() => window.addEventListener('scroll', listener))
onUnmounted(() => window.removeEventListener('scroll', listener))
const style: any = {
background: props.theme,
zIndex: props.zIndex,
height: props.height,
}
if (props.placement === 'top') style.top = 0
if (props.placement === 'bottom') style.bottom = 0
defineExpose({ style })
</script>
<template>
<div id="scroll_progress" ref="el" :style="style" />
</template>
<style scoped>
#scroll_progress {
position: fixed;
width: 0%;
transition: width 300ms ease-out;
}
</style>
🎥 Demo
🔗 Reference
- [MDN] Document: scroll event - The scroll event fires when the document view has been scrolled.
-
[MDN] MutationObserver - The
MutationObserver
interface provides the ability to watch for changes being made to theDOM tree
. - Vue3 API
Top comments (0)