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)