In the development of mobile terminal, in order to prevent the click through behavior, we sometimes block the default behavior of the browser. At this time, we need to customize the required browser behavior. This article introduces the scroll bar of the customized browser.
Default behavior of mobile browser
The default behavior of browser m is as follows:
- Scroll bar up and down
- Long press to select text and picture
- Input box get focus
- User scaling
- Simulate click action (click through)
- Sliding blank area
- ...
Tween algorithm
Because it is difficult to realize the point and stop effect of scroll bar with conventional css transition and timing, we need to introduce tween algorithm To achieve the corresponding effect.
Parameter Description: t: current time: current time; b: beginning value: initial value, the initial position of the element; c: change in value: change amount, the distance between the end position and the initial position of the element d: duration: duration, the whole transition duration s: optional parameters for Elastic and Back. The larger the springback coefficient is, the farther the springback effect is. Return value: Where the element moves every time
/*tween class*/ var Tween = { Linear: function(t,b,c,d){ return c*t/d + b; }, Quad: { easeIn: function(t,b,c,d){ return c*(t/=d)*t + b; }, easeOut: function(t,b,c,d){ return -c *(t/=d)*(t-2) + b; }, easeInOut: function(t,b,c,d){ if ((t/=d/2) < 1) return c/2*t*t + b; return -c/2 * ((--t)*(t-2) - 1) + b; } }, Cubic: { easeIn: function(t,b,c,d){ return c*(t/=d)*t*t + b; }, easeOut: function(t,b,c,d){ return c*((t=t/d-1)*t*t + 1) + b; }, easeInOut: function(t,b,c,d){ if ((t/=d/2) < 1) return c/2*t*t*t + b; return c/2*((t-=2)*t*t + 2) + b; } }, Quart: { easeIn: function(t,b,c,d){ return c*(t/=d)*t*t*t + b; }, easeOut: function(t,b,c,d){ return -c * ((t=t/d-1)*t*t*t - 1) + b; }, easeInOut: function(t,b,c,d){ if ((t/=d/2) < 1) return c/2*t*t*t*t + b; return -c/2 * ((t-=2)*t*t*t - 2) + b; } }, Quint: { easeIn: function(t,b,c,d){ return c*(t/=d)*t*t*t*t + b; }, easeOut: function(t,b,c,d){ return c*((t=t/d-1)*t*t*t*t + 1) + b; }, easeInOut: function(t,b,c,d){ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; return c/2*((t-=2)*t*t*t*t + 2) + b; } }, Sine: { easeIn: function(t,b,c,d){ return -c * Math.cos(t/d * (Math.PI/2)) + c + b; }, easeOut: function(t,b,c,d){ return c * Math.sin(t/d * (Math.PI/2)) + b; }, easeInOut: function(t,b,c,d){ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; } }, Expo: { easeIn: function(t,b,c,d){ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; }, easeOut: function(t,b,c,d){ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; }, easeInOut: function(t,b,c,d){ if (t==0) return b; if (t==d) return b+c; if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; } }, Circ: { easeIn: function(t,b,c,d){ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; }, easeOut: function(t,b,c,d){ return c * Math.sqrt(1 - (t=t/d-1)*t) + b; }, easeInOut: function(t,b,c,d){ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; } }, Elastic: { easeIn: function(t,b,c,d,a,p){ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a || a < Math.abs(c)) { a=c; var s=p/4; } else var s = p/(2*Math.PI) * Math.asin (c/a); return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; }, easeOut: function(t,b,c,d,a,p){ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a || a < Math.abs(c)) { a=c; var s=p/4; } else var s = p/(2*Math.PI) * Math.asin (c/a); return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b); }, easeInOut: function(t,b,c,d,a,p){ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); if (!a || a < Math.abs(c)) { a=c; var s=p/4; } else var s = p/(2*Math.PI) * Math.asin (c/a); if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; } }, Back: { easeIn: function(t,b,c,d,s){ if (s == undefined) s = 1.70158; return c*(t/=d)*t*((s+1)*t - s) + b; }, easeOut: function(t,b,c,d,s){ if (s == undefined) s = 1.70158; return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; }, easeInOut: function(t,b,c,d,s){ if (s == undefined) s = 1.70158; if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; } }, Bounce: { easeIn: function(t,b,c,d){ return c - Tween.Bounce.easeOut(d-t, 0, c, d) + b; }, easeOut: function(t,b,c,d){ if ((t/=d) < (1/2.75)) { return c*(7.5625*t*t) + b; } else if (t < (2/2.75)) { return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; } else if (t < (2.5/2.75)) { return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; } else { return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; } }, easeInOut: function(t,b,c,d){ if (t < d/2) return Tween.Bounce.easeIn(t*2, 0, c, d) * .5 + b; else return Tween.Bounce.easeOut(t*2-d, 0, c, d) * .5 + c*.5 + b; } } }
Use cases
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #outer { margin: 50px; width: 600px; height: 40px; border: 5px solid green; } #inner { width: 0; height: 40px; background: #f90; } .btn{ margin-top: 20px; } </style> </head> <body> <div id="outer"> <div id="inner"></div> <div class="btn"> <button class="btn1">Uniform speed</button> <button class="btn2">Slow down</button> <button class="btn3">springback</button> </div> </div> <script> //Define the function of Tween algorithm var tween = { //Uniform speed linear: function(t,b,c,d){ return c*t/d + b; }, //Slow down cubicEaseOut: function(t,b,c,d){ return c*((t=t/d-1)*t*t + 1) + b; }, //springback backEaseOut: function(t,b,c,d,s){ if (s === undefined) s = 1.70158; return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; }, }; /* * Tween Parameters of function * t current time current time * b beginning value Initial value * c change in value Variable amount of value (target initial value) * d duration Duration * s Resilience coefficient * */ var inner = document.querySelector('#inner'); var btn1 = document.querySelector('.btn1'); var btn2 = document.querySelector('.btn2'); var btn3 = document.querySelector('.btn3'); btn1.onclick = function () { var t = 0; var b = 0; var c = 600; var d = 5000; var intervalId = setInterval(function(){ t += 10; var value = tween.linear(t, b, c, d); //Uniform speed inner.style.width = value + 'px'; // If the current time point has reached the total duration, listen if (t >= d) { clearInterval(intervalId); } }, 10); }; btn2.onclick = function () { var t = 0; var b = 0; var c = 600; var d = 5000; var intervalId = setInterval(function(){ t += 10; var value = tween.cubicEaseOut(t, b, c, d); //Slow down inner.style.width = value + 'px'; // If the current time point has reached the total duration, listen if (t >= d) { clearInterval(intervalId); } }, 10); }; btn3.onclick = function () { var t = 0; var b = 0; var c = 600; var d = 5000; var intervalId = setInterval(function(){ t += 10; var value = tween.backEaseOut(t, b, c, d); //springback inner.style.width = value + 'px'; // If the current time point has reached the total duration, listen if (t >= d) { clearInterval(intervalId); } }, 10); }; </script> </body> </html>
Customize screen scroll bar
//Custom screen scrolling plug-in touchScroll.js (function(w){ /** * Realize screen scrolling * @param wrapper Wrapped elements * @param content Content elements (responsible for location changes) * @param scrollBar Scroll bar element; optional; if not specified, no scroll bar */ function touchScroll(wrapper, content, scrollBar){ var intervalId = null; //Defining timer markers //Calculate the height of the scroll bar if (scrollBar) { var scale1 = wrapper.clientHeight / content.offsetHeight; //Proportion scrollBar.style.height = wrapper.clientHeight * scale1 + 'px'; } //Turn on 3d acceleration transformCss(content, 'translateZ', 0); //Touch start wrapper.addEventListener('touchstart', function(event){ //Get contact object var touch = event.targetTouches[0]; // Get the starting position of the contact this.startY = touch.clientY; // Get the starting position of content this.eleY = transformCss(content, 'translateY'); // Initial contact sliding distance this.dstY = 0; //Initial time this.startTime = Date.now(); //scroll bars displaying if (scrollBar) { scrollBar.style.opacity = 1; } //Cancel timer clearInterval(intervalId); }); //Touch Mobile wrapper.addEventListener('touchmove', function(event){ //Get contact object var touch = event.targetTouches[0]; //Get the end position of the contact var endY = touch.clientY; //Calculate the sliding distance of the contact this.dstY = endY - this.startY; // Calculate the position of content according to the sliding distance var translateY = this.eleY + this.dstY; //Judge the critical value and open the rubber band effect if (translateY >= 0) { //Upper boundary //Calculation proportion var scale = 1 - translateY / (wrapper.clientHeight * 1.9); //Recalculate translateY translateY *= scale; } else if (translateY <= (wrapper.clientHeight - content.offsetHeight)) { //Calculate the distance between content and the bottom of the viewport var bottomY = wrapper.clientHeight - (content.offsetHeight + translateY); // Calculation proportion var scale = 1 - bottomY / (wrapper.clientHeight * 1.9); // Recalculate bottom bottomY *= scale; // Recalculate translateY translateY = (wrapper.clientHeight - bottomY) - content.offsetHeight } // Set the location of content transformCss(content, 'translateY', translateY); // Adjust scroll bar position if (scrollBar) { setScrllBarOffset(translateY); } }); //End of touch wrapper.addEventListener('touchend', function(event){ //End time var dstTime = Date.now() - this.startTime; //Calculate acceleration distance var speed = this.dstY / dstTime * 200; // Calculate the position of the element at this time and add the acceleration distance var translateY = transformCss(content, 'translateY'); translateY += speed; //Set transition type var type = 'cubicEaseOut'; //It's slowing down all the time //Judge to reach critical point and start rebound if (translateY >= 0) { translateY = 0; type = 'backEaseOut'; } else if (translateY <= wrapper.clientHeight - content.offsetHeight) { translateY = wrapper.clientHeight - content.offsetHeight; type = 'backEaseOut'; } //Reset content location to call transition function moveTo(content, translateY, 500, type); }); /** * Transition function * @param node Elements to transform * @param target target value * @param duration Transition duration * @param type Transition types linear, cubicEaseOut, backEaseOut */ function moveTo(node, target, duration, type = 'linear') { //Define the function of Tween algorithm var tween = { //Uniform speed linear: function(t,b,c,d){ return c*t/d + b; }, //Slow down cubicEaseOut: function(t,b,c,d){ return c*((t=t/d-1)*t*t + 1) + b; }, //springback backEaseOut: function(t,b,c,d,s){ if (s === undefined) s = 1.70158; return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; }, }; // Define parameters of Tween function var t = 0; //current time var b = transformCss(node, 'translateY'); //Starting value var c = target - b; //Amount of change var d = duration; //Avoid multiple timings, and clear the previous timings (whether there is one or not) clearInterval(intervalId); //Opening timing intervalId = setInterval(function(){ //t transformation t += 10; //Using Tween function to get the current value var translateY = tween[type](t,b,c,d); // Set the location of content transformCss(node, 'translateY', translateY); //Adjust the position of the scroll bar if (scrollBar) { setScrllBarOffset(translateY); } //Judge transition completed if (t >= d) { //Timed end transition end clearInterval(intervalId); //Scroll bar hide if (scrollBar) { scrollBar.style.opacity = 0; } } }, 10); } /** * Set scroll bar position * @param contentTranslateY Where the content is now */ function setScrllBarOffset(contentTranslateY) { // Calculate proportion content current position / maximum position var scale2 = -contentTranslateY / (content.offsetHeight - wrapper.clientHeight); // Calculate scroll bar position transformCss(scrollBar, 'translateY', (wrapper.clientHeight - scrollBar.offsetHeight) * scale2); } } //Expose the method w.touchScroll = touchScroll; })(window);
Use case - vertical slide
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0,viewport-fit:cover"> <title>Custom vertical slide</title> <style> * { margin: 0; padding: 0; } html,body,#app { width:100%; height: 100%; overflow: hidden; } #content { font-size: 26px; } #scrollBar { position: absolute; top: 0; right: 0; width: 4px; height: 100px; border-radius: 2px; background-color: rgba(0,0,0,.8); opacity: 0; transition: opacity .2s; } </style> </head> <body> <div id="app"> <div id="content"></div> <div id="scrollBar"></div> </div> <script src="js/transformcss.js"></script> <script src="js/touchscroll.js"></script> <script> (function () { var app = document.querySelector('#app'); var content = document.querySelector('#content'); var scrollBar = document.querySelector('#scrollBar'); app.addEventListener('touchstart', function(event){ event.preventDefault(); }); for (var i = 0; i <= 200; i ++) { content.innerHTML += i + '<br>'; } touchScroll(app, content, scrollBar); })(); </script> </body> </html>
Note: in order to realize touch movement more conveniently and concisely, transformcss.js file is used when customizing the scroll bar (touchScroll.js). Therefore, transformcss.js should be introduced before using the custom scroll bar plug-in. Address: https://segmentfault.com/a/11... , or go directly to my last article: encapsulating the transfrom function.
Note: the author is just a novice who gropes silently on the front road. If there are any mistakes in this article, please correct them in time. If this article is helpful to you, click brother Ming's website http://learn.fuming.site/ Learn more!