HTML5鼠标滚动树生长过程特效

版权:原创 更新时间:1年以上
[该文章底部包含文件资源,可根据自己情况,决定是否下载资源使用,时间>金钱,如有需要,立即查看资源]

以下是 HTML5鼠标滚动树生长过程特效 的示例演示效果:

当前平台(PC电脑)
  • 平台:

部分效果截图:

HTML5鼠标滚动树生长过程特效

HTML代码(index.html):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="skrollr.js"></script>
<style>
#info {
  position: fixed;
  top: 20px;
  left: 20px;
  background-color: rgba(0,0,0,0.5);
  color: #fff;
  padding: 20px;
  z-index: 9999;
}
section {
  height: 5000px;
}
#slide-1 .bcg {
  height: 100%;
  width: 100%;
  background-image: url('img/bcg_paper.png');
  background-repeat: repeat;
  background-position: center top;
  background-attachment: fixed;
}
#scrollBaby {
  width: 184px;
  height: 286px;
  background: url('img/img_get-scrolling.png') no-repeat top left;
  position: fixed;
  bottom: 0;
  left: 50%;
  margin-left: -92px;
}
#slide-1 #tree {
  width: 380px; height: 550px;
  position: fixed;
  top: 50%;
  left: 50%;
  margin: -275px 0 0 -190px;
}
#slide-1 .item {position: absolute; top: 0; left: 0;}
#slide-1 .tree1 {bottom: 426px; left: 100px; top: auto;}
#slide-1 .tree2 {bottom: 309px; left: 73px; top: auto;}
#slide-1 .tree3 {bottom: 205px; left: 30px; top: auto;}
#slide-1 .tree4 {bottom: 101px; left: 14px; top: auto;}
#slide-1 .trunk {bottom: 87px; left: 167px; top: auto;}
#slide-1 .pot {bottom: 20px; left: 130px; top: auto;}
#slide-1 .shadow {bottom: 0; left: 24px; top: auto;}
</style>
<title>HTML5鼠标滚动树生长过程特效</title>
</head>

<body>
<div id="info">0</div>

<section id="slide-1">
  <div class="bcg"></div>
  <div id="scrollBaby"
    data-top="transform:translateY(0px)"
    data--875-top="transform:translateY(300px)"
    data-anchor-target="#slide-1"
  ></div>
  <div id="tree">

    <div class="item tree1"
      data-top="opacity: 0;" 
	    data--1600-top="opacity: 0; transform: scale(0.5); bottom: 71px;" 
	    data--2000-top="opacity: 1; transform: scale(0.5); bottom: 90px;" 
	    data--4000-top="opacity: 1; transform: scale(1); bottom: 426px;" 
	    data-anchor-target="#slide-1"     
    ><img src="img/img_tree-p1.png"></div>

    <div class="item tree2"
      data-top="opacity: 0; transform: scale(0.3); bottom: 71px;" 
	    data--2000-top="opacity: 0; transform: scale(0.3); bottom: 71px;" 
	    data--2212-top="opacity: 1; transform: scale(0.45); bottom: 81px;" 
	    data--4000-top="opacity: 1; transform: scale(1); bottom: 309px;" 
	    data-anchor-target="#slide-1"
    ><img src="img/img_tree-p2.png"></div>    

   <div class="item tree3"
      data-top="opacity: 0; transform: scale(0.3);" 
      data--2212-top="opacity: 0; transform: scale(0.3); bottom: 71px;" 
      data--2700-top="opacity: 1; transform: scale(0.55); bottom: 81px;" 
      data--4000-top="opacity: 1; transform: scale(1); bottom: 205px;" 
      data-anchor-target="#slide-1"
    ><img src="img/img_tree-p3.png"></div>
    
    <div class="item tree4"
      data-top="opacity: 0; transform: scale(0.3);" 
      data--3000-top="opacity: 0; transform: scale(0.52);" 
      data--3300-top="opacity: 1; transform: scale(0.60);" 
      data--4000-top="opacity: 1; transform: scale(1);" 
      data-anchor-target="#slide-1"
    ><img src="img/img_tree-p4.png"></div>
    
    <div class="item trunk"
      data-top="opacity: 0;" 
      data--1600-top="opacity: 0; transform: scale(0.3, 0.6);" 
      data--2000-top="opacity: 1; transform: scale(0.3, 0.6);" 
      data--4000-top="transform: scale(1,1);" 
      data-anchor-target="#slide-1"
    ><img src="img/img_trunk.png"></div>
    
     <div class="item pot" data-top="opacity: 0; transform:translateY(-800px)"  data--875-top="opacity: 1; transform[bounce]:translateY(-200px)" data--1500-top="opacity: 1; transform[bounce]:translateY(0)"  data-anchor-target="#slide-1"><img src="img/img_pot.png"></div>

    <div class="item shadow"
      data-top="opacity: 0; transform: scale(0.6);" 
      data--3000-top="opacity: 0.2; transform: scale(0.6);" 
      data--4000-top="opacity: 1; transform: scale(1);" 
      data-anchor-target="#slide-1"
    ><img src="img/img_shadow.png"></div>
    
  </div>
</section>
<script>
var s = skrollr.init({
	render: function(data) {
	  //Log the current scroll position.
	  $('#info').text(data.curTop);
	}
});
</script>
</body>
</html>

JS代码(skrollr.js):

(function(window,document,undefined){
	'use strict';
	/* * Global api. */
var skrollr = window.skrollr ={
	get:function(){
	return _instance;
}
,//Main entry point.init:function(options){
	return _instance || new Skrollr(options);
}
,VERSION:'0.6.17'}
;
	//Minify optimization.var hasProp = Object.prototype.hasOwnProperty;
	var Math = window.Math;
	var getStyle = window.getComputedStyle;
	//They will be filled when skrollr gets initialized.var documentElement;
	var body;
	var EVENT_TOUCHSTART = 'touchstart';
	var EVENT_TOUCHMOVE = 'touchmove';
	var EVENT_TOUCHCANCEL = 'touchcancel';
	var EVENT_TOUCHEND = 'touchend';
	var SKROLLABLE_CLASS = 'skrollable';
	var SKROLLABLE_BEFORE_CLASS = SKROLLABLE_CLASS + '-before';
	var SKROLLABLE_BETWEEN_CLASS = SKROLLABLE_CLASS + '-between';
	var SKROLLABLE_AFTER_CLASS = SKROLLABLE_CLASS + '-after';
	var SKROLLR_CLASS = 'skrollr';
	var NO_SKROLLR_CLASS = 'no-' + SKROLLR_CLASS;
	var SKROLLR_DESKTOP_CLASS = SKROLLR_CLASS + '-desktop';
	var SKROLLR_MOBILE_CLASS = SKROLLR_CLASS + '-mobile';
	var DEFAULT_EASING = 'linear';
	var DEFAULT_DURATION = 1000;
	//msvar DEFAULT_MOBILE_DECELERATION = 0.004;
	//pixel/ms²var DEFAULT_SMOOTH_SCROLLING_DURATION = 200;
	//msvar ANCHOR_START = 'start';
	var ANCHOR_END = 'end';
	var ANCHOR_CENTER = 'center';
	var ANCHOR_BOTTOM = 'bottom';
	//The property which will be added to the DOM element to hold the ID of the skrollable.var SKROLLABLE_ID_DOM_PROPERTY = '___skrollable_id';
	var rxTouchIgnoreTags = /^(?:input|textarea|button|select)$/i;
	var rxTrim = /^\s+|\s+$/g;
	//Find all data-attributes. data-[_constant]-[offset]-[anchor]-[anchor].var rxKeyframeAttribute = /^data(?:-(_\w+))?(?:-?(-?\d*\.?\d+p?))?(?:-?(start|end|top|center|bottom))?(?:-?(top|center|bottom))?$/;
	var rxPropValue = /\s*([\w\-\[\]]+)\s*:\s*(.+?)\s*(?:;
	|$)/gi;
	//Easing function names follow the property in square brackets.var rxPropEasing = /^([a-z\-]+)\[(\w+)\]$/;
	var rxCamelCase = /-([a-z])/g;
	var rxCamelCaseFn = function(str,letter){
	return letter.toUpperCase();
}
;
	//Numeric values with optional sign.var rxNumericValue = /[\-+]?[\d]*\.?[\d]+/g;
	//Used to replace occurences of{
	?}
with a number.var rxInterpolateString = /\{
	\?\}
/g;
	//Finds rgb(a) colors,which don't use the percentage notation.var rxRGBAIntegerColor = /rgba?\(\s*-?\d+\s*,\s*-?\d+\s*,\s*-?\d+/g;
	//Finds all gradients.var rxGradient = /[a-z\-]+-gradient/g;
	//Vendor prefix. Will be set once skrollr gets initialized.var theCSSPrefix = '';
	var theDashedCSSPrefix = '';
	//Will be called once (when skrollr gets initialized).var detectCSSPrefix = function(){
	//Only relevant prefixes. May be extended.//Could be dangerous if there will ever be a CSS property which actually starts with "ms". Don't hope so.var rxPrefixes = /^(?:O|Moz|webkit|ms)|(?:-(?:o|moz|webkit|ms)-)/;
	//Detect prefix for current browser by finding the first property using a prefix.if(!getStyle){
	return;
}
var style = getStyle(body,null);
	for(var k in style){
	//We check the key and if the key is a number,we check the value as well,because safari's getComputedStyle returns some weird array-like thingy.theCSSPrefix = (k.match(rxPrefixes) || (+k == k && style[k].match(rxPrefixes)));
	if(theCSSPrefix){
	break;
}
}
//Did we even detect a prefix?if(!theCSSPrefix){
	theCSSPrefix = theDashedCSSPrefix = '';
	return;
}
theCSSPrefix = theCSSPrefix[0];
	//We could have detected either a dashed prefix or this camelCaseish-inconsistent stuff.if(theCSSPrefix.slice(0,1) === '-'){
	theDashedCSSPrefix = theCSSPrefix;
	//There's no logic behind these. Need a look up.theCSSPrefix = ({
	'-webkit-':'webkit','-moz-':'Moz','-ms-':'ms','-o-':'O'}
)[theCSSPrefix];
}
else{
	theDashedCSSPrefix = '-' + theCSSPrefix.toLowerCase() + '-';
}
}
;
	var polyfillRAF = function(){
	var requestAnimFrame = window.requestAnimationFrame || window[theCSSPrefix.toLowerCase() + 'RequestAnimationFrame'];
	var lastTime = _now();
	if(_isMobile || !requestAnimFrame){
	requestAnimFrame = function(callback){
	//How long did it take to render?var deltaTime = _now() - lastTime;
	var delay = Math.max(0,1000 / 60 - deltaTime);
	return window.setTimeout(function(){
	lastTime = _now();
	callback();
}
,delay);
}
;
}
return requestAnimFrame;
}
;
	var polyfillCAF = function(){
	var cancelAnimFrame = window.cancelAnimationFrame || window[theCSSPrefix.toLowerCase() + 'CancelAnimationFrame'];
	if(_isMobile || !cancelAnimFrame){
	cancelAnimFrame = function(timeout){
	return window.clearTimeout(timeout);
}
;
}
return cancelAnimFrame;
}
;
	//Built-in easing functions.var easings ={
	begin:function(){
	return 0;
}
,end:function(){
	return 1;
}
,linear:function(p){
	return p;
}
,quadratic:function(p){
	return p * p;
}
,cubic:function(p){
	return p * p * p;
}
,swing:function(p){
	return (-Math.cos(p * Math.PI) / 2) + 0.5;
}
,sqrt:function(p){
	return Math.sqrt(p);
}
,outCubic:function(p){
	return (Math.pow((p - 1),3) + 1);
}
,//see https://www.desmos.com/calculator/tbr20s8vd2 for how I did thisbounce:function(p){
	var a;
	if(p <= 0.5083){
	a = 3;
}
else if(p <= 0.8489){
	a = 9;
}
else if(p <= 0.96208){
	a = 27;
}
else if(p <= 0.99981){
	a = 91;
}
else{
	return 1;
}
return 1 - Math.abs(3 * Math.cos(p * a * 1.028) / a);
}
}
;
	/** * Constructor. */
function Skrollr(options){
	documentElement = document.documentElement;
	body = document.body;
	detectCSSPrefix();
	_instance = this;
	options = options ||{
}
;
	_constants = options.constants ||{
}
;
	//We allow defining custom easings or overwrite existing.if(options.easing){
	for(var e in options.easing){
	easings[e] = options.easing[e];
}
}
_edgeStrategy = options.edgeStrategy || 'set';
	_listeners ={
	//Function to be called right before rendering.beforerender:options.beforerender,//Function to be called right after finishing rendering.render:options.render}
;
	//forceHeight is true by default_forceHeight = options.forceHeight !== false;
	if(_forceHeight){
	_scale = options.scale || 1;
}
_mobileDeceleration = options.mobileDeceleration || DEFAULT_MOBILE_DECELERATION;
	_smoothScrollingEnabled = options.smoothScrolling !== false;
	_smoothScrollingDuration = options.smoothScrollingDuration || DEFAULT_SMOOTH_SCROLLING_DURATION;
	//Dummy object. Will be overwritten in the _render method when smooth scrolling is calculated._smoothScrolling ={
	targetTop:_instance.getScrollTop()}
;
	//A custom check function may be passed._isMobile = ((options.mobileCheck || function(){
	return (/Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i).test(navigator.userAgent || navigator.vendor || window.opera);
}
)());
	if(_isMobile){
	_skrollrBody = document.getElementById('skrollr-body');
	//Detect 3d transform if there's a skrollr-body (only needed for #skrollr-body).if(_skrollrBody){
	_detect3DTransforms();
}
_initMobile();
	_updateClass(documentElement,[SKROLLR_CLASS,SKROLLR_MOBILE_CLASS],[NO_SKROLLR_CLASS]);
}
else{
	_updateClass(documentElement,[SKROLLR_CLASS,SKROLLR_DESKTOP_CLASS],[NO_SKROLLR_CLASS]);
}
//Triggers parsing of elements and a first reflow._instance.refresh();
	_addEvent(window,'resize orientationchange',function(){
	var width = documentElement.clientWidth;
	var height = documentElement.clientHeight;
	//Only reflow if the size actually changed (#271).if(height !== _lastViewportHeight || width !== _lastViewportWidth){
	_lastViewportHeight = height;
	_lastViewportWidth = width;
	_requestReflow = true;
}
}
);
	var requestAnimFrame = polyfillRAF();
	//Let's go.(function animloop(){
	_render();
	_animFrame = requestAnimFrame(animloop);
}
());
	return _instance;
}
/** * (Re)parses some or all elements. */
Skrollr.prototype.refresh = function(elements){
	var elementIndex;
	var elementsLength;
	var ignoreID = false;
	//Completely reparse anything without argument.if(elements === undefined){
	//Ignore that some elements may already have a skrollable ID.ignoreID = true;
	_skrollables = [];
	_skrollableIdCounter = 0;
	elements = document.getElementsByTagName('*');
}
else{
	//We accept a single element or an array of elements.elements = [].concat(elements);
}
elementIndex = 0;
	elementsLength = elements.length;
	for(;
	elementIndex < elementsLength;
	elementIndex++){
	var el = elements[elementIndex];
	var anchorTarget = el;
	var keyFrames = [];
	//If this particular element should be smooth scrolled.var smoothScrollThis = _smoothScrollingEnabled;
	//The edge strategy for this particular element.var edgeStrategy = _edgeStrategy;
	if(!el.attributes){
	continue;
}
//Iterate over all attributes and search for key frame attributes.var attributeIndex = 0;
	var attributesLength = el.attributes.length;
	for (;
	attributeIndex < attributesLength;
	attributeIndex++){
	var attr = el.attributes[attributeIndex];
	if(attr.name === 'data-anchor-target'){
	anchorTarget = document.querySelector(attr.value);
	if(anchorTarget === null){
	throw 'Unable to find anchor target "' + attr.value + '"';
}
continue;
}
//Global smooth scrolling can be overridden by the element attribute.if(attr.name === 'data-smooth-scrolling'){
	smoothScrollThis = attr.value !== 'off';
	continue;
}
//Global edge strategy can be overridden by the element attribute.if(attr.name === 'data-edge-strategy'){
	edgeStrategy = attr.value;
	continue;
}
var match = attr.name.match(rxKeyframeAttribute);
	if(match === null){
	continue;
}
var kf ={
	props:attr.value,//Point back to the element as well.element:el}
;
	keyFrames.push(kf);
	var constant = match[1];
	//If there is a constant,get it's value or fall back to 0.constant = constant && _constants[constant.substr(1)] || 0;
	//Parse key frame offset. If undefined will be casted to 0.var offset = match[2];
	//Is it a percentage offset?if(/p$/.test(offset)){
	kf.isPercentage = true;
	kf.offset = ((offset.slice(0,-1) | 0) + constant) / 100;
}
else{
	kf.offset = (offset | 0) + constant;
}
var anchor1 = match[3];
	//If second anchor is not set,the first will be taken for both.var anchor2 = match[4] || anchor1;
	//"absolute" (or "classic") mode,where numbers mean absolute scroll offset.if(!anchor1 || anchor1 === ANCHOR_START || anchor1 === ANCHOR_END){
	kf.mode = 'absolute';
	//data-end needs to be calculated after all key frames are known.if(anchor1 === ANCHOR_END){
	kf.isEnd = true;
}
else if(!kf.isPercentage){
	//For data-start we can already set the key frame w/o calculations.//#59:"scale" options should only affect absolute mode.kf.frame = kf.offset * _scale;
	delete kf.offset;
}
}
//"relative" mode,where numbers are relative to anchors.else{
	kf.mode = 'relative';
	kf.anchors = [anchor1,anchor2];
}
}
//Does this element have key frames?if(!keyFrames.length){
	continue;
}
//Will hold the original style and class attributes before we controlled the element (see #80).var styleAttr,classAttr;
	var id;
	if(!ignoreID && SKROLLABLE_ID_DOM_PROPERTY in el){
	//We already have this element under control. Grab the corresponding skrollable id.id = el[SKROLLABLE_ID_DOM_PROPERTY];
	styleAttr = _skrollables[id].styleAttr;
	classAttr = _skrollables[id].classAttr;
}
else{
	//It's an unknown element. Asign it a new skrollable id.id = (el[SKROLLABLE_ID_DOM_PROPERTY] = _skrollableIdCounter++);
	styleAttr = el.style.cssText;
	classAttr = _getClass(el);
}
_skrollables[id] ={
	element:el,styleAttr:styleAttr,classAttr:classAttr,anchorTarget:anchorTarget,keyFrames:keyFrames,smoothScrolling:smoothScrollThis,edgeStrategy:edgeStrategy}
;
	_updateClass(el,[SKROLLABLE_CLASS],[]);
}
//Reflow for the first time._reflow();
	//Now that we got all key frame numbers right,actually parse the properties.elementIndex = 0;
	elementsLength = elements.length;
	for(;
	elementIndex < elementsLength;
	elementIndex++){
	var sk = _skrollables[elements[elementIndex][SKROLLABLE_ID_DOM_PROPERTY]];
	if(sk === undefined){
	continue;
}
//Parse the property string to objects_parseProps(sk);
	//Fill key frames with missing properties from left and right_fillProps(sk);
}
return _instance;
}
;
	/** * Transform "relative" mode to "absolute" mode. * That is,calculate anchor position and offset of element. */
Skrollr.prototype.relativeToAbsolute = function(element,viewportAnchor,elementAnchor){
	var viewportHeight = documentElement.clientHeight;
	var box = element.getBoundingClientRect();
	var absolute = box.top;
	//#100:IE doesn't supply "height" with getBoundingClientRect.var boxHeight = box.bottom - box.top;
	if(viewportAnchor === ANCHOR_BOTTOM){
	absolute -= viewportHeight;
}
else if(viewportAnchor === ANCHOR_CENTER){
	absolute -= viewportHeight / 2;
}
if(elementAnchor === ANCHOR_BOTTOM){
	absolute += boxHeight;
}
else if(elementAnchor === ANCHOR_CENTER){
	absolute += boxHeight / 2;
}
//Compensate scrolling since getBoundingClientRect is relative to viewport.absolute += _instance.getScrollTop();
	return (absolute + 0.5) | 0;
}
;
	/** * Animates scroll top to new position. */
Skrollr.prototype.animateTo = function(top,options){
	options = options ||{
}
;
	var now = _now();
	var scrollTop = _instance.getScrollTop();
	//Setting this to a new value will automatically cause the current animation to stop,if any._scrollAnimation ={
	startTop:scrollTop,topDiff:top - scrollTop,targetTop:top,duration:options.duration || DEFAULT_DURATION,startTime:now,endTime:now + (options.duration || DEFAULT_DURATION),easing:easings[options.easing || DEFAULT_EASING],done:options.done}
;
	//Don't queue the animation if there's nothing to animate.if(!_scrollAnimation.topDiff){
	if(_scrollAnimation.done){
	_scrollAnimation.done.call(_instance,false);
}
_scrollAnimation = undefined;
}
return _instance;
}
;
	/** * Stops animateTo animation. */
Skrollr.prototype.stopAnimateTo = function(){
	if(_scrollAnimation && _scrollAnimation.done){
	_scrollAnimation.done.call(_instance,true);
}
_scrollAnimation = undefined;
}
;
	/** * Returns if an animation caused by animateTo is currently running. */
Skrollr.prototype.isAnimatingTo = function(){
	return !!_scrollAnimation;
}
;
	Skrollr.prototype.setScrollTop = function(top,force){
	_forceRender = (force === true);
	if(_isMobile){
	_mobileOffset = Math.min(Math.max(top,0),_maxKeyFrame);
}
else{
	window.scrollTo(0,top);
}
return _instance;
}
;
	Skrollr.prototype.getScrollTop = function(){
	if(_isMobile){
	return _mobileOffset;
}
else{
	return window.pageYOffset || documentElement.scrollTop || body.scrollTop || 0;
}
}
;
	Skrollr.prototype.getMaxScrollTop = function(){
	return _maxKeyFrame;
}
;
	Skrollr.prototype.on = function(name,fn){
	_listeners[name] = fn;
	return _instance;
}
;
	Skrollr.prototype.off = function(name){
	delete _listeners[name];
	return _instance;
}
;
	Skrollr.prototype.destroy = function(){
	var cancelAnimFrame = polyfillCAF();
	cancelAnimFrame(_animFrame);
	_removeAllEvents();
	_updateClass(documentElement,[NO_SKROLLR_CLASS],[SKROLLR_CLASS,SKROLLR_DESKTOP_CLASS,SKROLLR_MOBILE_CLASS]);
	var skrollableIndex = 0;
	var skrollablesLength = _skrollables.length;
	for(;
	skrollableIndex < skrollablesLength;
	skrollableIndex++){
	_reset(_skrollables[skrollableIndex].element);
}
documentElement.style.overflow = body.style.overflow = 'auto';
	documentElement.style.height = body.style.height = 'auto';
	if(_skrollrBody){
	skrollr.setStyle(_skrollrBody,'transform','none');
}
_instance = undefined;
	_skrollrBody = undefined;
	_listeners = undefined;
	_forceHeight = undefined;
	_maxKeyFrame = 0;
	_scale = 1;
	_constants = undefined;
	_mobileDeceleration = undefined;
	_direction = 'down';
	_lastTop = -1;
	_lastViewportWidth = 0;
	_lastViewportHeight = 0;
	_requestReflow = false;
	_scrollAnimation = undefined;
	_smoothScrollingEnabled = undefined;
	_smoothScrollingDuration = undefined;
	_smoothScrolling = undefined;
	_forceRender = undefined;
	_skrollableIdCounter = 0;
	_edgeStrategy = undefined;
	_isMobile = false;
	_mobileOffset = 0;
	_translateZ = undefined;
}
;
	/*Private methods.*/
var _initMobile = function(){
	var initialElement;
	var initialTouchY;
	var initialTouchX;
	var currentElement;
	var currentTouchY;
	var currentTouchX;
	var lastTouchY;
	var deltaY;
	var initialTouchTime;
	var currentTouchTime;
	var lastTouchTime;
	var deltaTime;
	_addEvent(documentElement,[EVENT_TOUCHSTART,EVENT_TOUCHMOVE,EVENT_TOUCHCANCEL,EVENT_TOUCHEND].join(' '),function(e){
	var touch = e.changedTouches[0];
	currentElement = e.target;
	//We don't want text nodes.while(currentElement.nodeType === 3){
	currentElement = currentElement.parentNode;
}
currentTouchY = touch.clientY;
	currentTouchX = touch.clientX;
	currentTouchTime = e.timeStamp;
	if(!rxTouchIgnoreTags.test(currentElement.tagName)){
	e.preventDefault();
}
switch(e.type){
	case EVENT_TOUCHSTART://The last element we tapped on.if(initialElement){
	initialElement.blur();
}
_instance.stopAnimateTo();
	initialElement = currentElement;
	initialTouchY = lastTouchY = currentTouchY;
	initialTouchX = currentTouchX;
	initialTouchTime = currentTouchTime;
	break;
	case EVENT_TOUCHMOVE:deltaY = currentTouchY - lastTouchY;
	deltaTime = currentTouchTime - lastTouchTime;
	_instance.setScrollTop(_mobileOffset - deltaY,true);
	lastTouchY = currentTouchY;
	lastTouchTime = currentTouchTime;
	break;
	default:case EVENT_TOUCHCANCEL:case EVENT_TOUCHEND:var distanceY = initialTouchY - currentTouchY;
	var distanceX = initialTouchX - currentTouchX;
	var distance2 = distanceX * distanceX + distanceY * distanceY;
	//Check if it was more like a tap (moved less than 7px).if(distance2 < 49){
	if(!rxTouchIgnoreTags.test(initialElement.tagName)){
	initialElement.focus();
	//It was a tap,click the element.var clickEvent = document.createEvent('MouseEvents');
	clickEvent.initMouseEvent('click',true,true,e.view,1,touch.screenX,touch.screenY,touch.clientX,touch.clientY,e.ctrlKey,e.altKey,e.shiftKey,e.metaKey,0,null);
	initialElement.dispatchEvent(clickEvent);
}
return;
}
initialElement = undefined;
	var speed = deltaY / deltaTime;
	//Cap speed at 3 pixel/ms.speed = Math.max(Math.min(speed,3),-3);
	var duration = Math.abs(speed / _mobileDeceleration);
	var targetOffset = speed * duration + 0.5 * _mobileDeceleration * duration * duration;
	var targetTop = _instance.getScrollTop() - targetOffset;
	//Relative duration change for when scrolling above bounds.var targetRatio = 0;
	//Change duration proportionally when scrolling would leave bounds.if(targetTop > _maxKeyFrame){
	targetRatio = (_maxKeyFrame - targetTop) / targetOffset;
	targetTop = _maxKeyFrame;
}
else if(targetTop < 0){
	targetRatio = -targetTop / targetOffset;
	targetTop = 0;
}
duration = duration * (1 - targetRatio);
	_instance.animateTo((targetTop + 0.5) | 0,{
	easing:'outCubic',duration:duration}
);
	break;
}
}
);
	//Just in case there has already been some native scrolling,reset it.window.scrollTo(0,0);
	documentElement.style.overflow = body.style.overflow = 'hidden';
}
;
	/** * Updates key frames which depend on others. * That is "end" in "absolute" mode and all key frames in "relative" mode. */
var _updateDependentKeyFrames = function(){
	var skrollable;
	var element;
	var anchorTarget;
	var keyFrames;
	var keyFrameIndex;
	var keyFramesLength;
	var kf;
	var skrollableIndex;
	var skrollablesLength;
	//First process all relative-mode elements and find the max key frame.skrollableIndex = 0;
	skrollablesLength = _skrollables.length;
	for(;
	skrollableIndex < skrollablesLength;
	skrollableIndex++){
	skrollable = _skrollables[skrollableIndex];
	element = skrollable.element;
	anchorTarget = skrollable.anchorTarget;
	keyFrames = skrollable.keyFrames;
	keyFrameIndex = 0;
	keyFramesLength = keyFrames.length;
	for(;
	keyFrameIndex < keyFramesLength;
	keyFrameIndex++){
	kf = keyFrames[keyFrameIndex];
	var offset = kf.offset;
	if(kf.isPercentage){
	//Convert the offset to percentage of the viewport height.offset = offset * documentElement.clientHeight;
	//Absolute + percentage mode.kf.frame = offset;
}
if(kf.mode === 'relative'){
	_reset(element);
	kf.frame = _instance.relativeToAbsolute(anchorTarget,kf.anchors[0],kf.anchors[1]) - offset;
	_reset(element,true);
}
//Only search for max key frame when forceHeight is enabled.if(_forceHeight){
	//Find the max key frame,but don't use one of the data-end ones for comparison.if(!kf.isEnd && kf.frame > _maxKeyFrame){
	_maxKeyFrame = kf.frame;
}
}
}
}
//#133:The document can be larger than the maxKeyFrame we found._maxKeyFrame = Math.max(_maxKeyFrame,_getDocumentHeight());
	//Now process all data-end keyframes.skrollableIndex = 0;
	skrollablesLength = _skrollables.length;
	for(;
	skrollableIndex < skrollablesLength;
	skrollableIndex++){
	skrollable = _skrollables[skrollableIndex];
	keyFrames = skrollable.keyFrames;
	keyFrameIndex = 0;
	keyFramesLength = keyFrames.length;
	for(;
	keyFrameIndex < keyFramesLength;
	keyFrameIndex++){
	kf = keyFrames[keyFrameIndex];
	if(kf.isEnd){
	kf.frame = _maxKeyFrame - kf.offset;
}
}
skrollable.keyFrames.sort(_keyFrameComparator);
}
}
;
	/** * Calculates and sets the style properties for the element at the given frame. * @param fakeFrame The frame to render at when smooth scrolling is enabled. * @param actualFrame The actual frame we are at. */
var _calcSteps = function(fakeFrame,actualFrame){
	//Iterate over all skrollables.var skrollableIndex = 0;
	var skrollablesLength = _skrollables.length;
	for(;
	skrollableIndex < skrollablesLength;
	skrollableIndex++){
	var skrollable = _skrollables[skrollableIndex];
	var element = skrollable.element;
	var frame = skrollable.smoothScrolling ? fakeFrame:actualFrame;
	var frames = skrollable.keyFrames;
	var firstFrame = frames[0].frame;
	var lastFrame = frames[frames.length - 1].frame;
	var beforeFirst = frame < firstFrame;
	var afterLast = frame > lastFrame;
	var firstOrLastFrame = frames[beforeFirst ? 0:frames.length - 1];
	var key;
	var value;
	//If we are before/after the first/last frame,set the styles according to the given edge strategy.if(beforeFirst || afterLast){
	//Check if we already handled this edge case last time.//Note:using setScrollTop it's possible that we jumped from one edge to the other.if(beforeFirst && skrollable.edge === -1 || afterLast && skrollable.edge === 1){
	continue;
}
//Add the skrollr-before or -after class._updateClass(element,[beforeFirst ? SKROLLABLE_BEFORE_CLASS:SKROLLABLE_AFTER_CLASS],[SKROLLABLE_BEFORE_CLASS,SKROLLABLE_BETWEEN_CLASS,SKROLLABLE_AFTER_CLASS]);
	//Remember that we handled the edge case (before/after the first/last keyframe).skrollable.edge = beforeFirst ? -1:1;
	switch(skrollable.edgeStrategy){
	case 'reset':_reset(element);
	continue;
	case 'ease'://Handle this case like it would be exactly at first/last keyframe and just pass it on.frame = firstOrLastFrame.frame;
	break;
	default:case 'set':var props = firstOrLastFrame.props;
	for(key in props){
	if(hasProp.call(props,key)){
	value = _interpolateString(props[key].value);
	skrollr.setStyle(element,key,value);
}
}
continue;
}
}
else{
	//Did we handle an edge last time?if(skrollable.edge !== 0){
	_updateClass(element,[SKROLLABLE_CLASS,SKROLLABLE_BETWEEN_CLASS],[SKROLLABLE_BEFORE_CLASS,SKROLLABLE_AFTER_CLASS]);
	skrollable.edge = 0;
}
}
//Find out between which two key frames we are right now.var keyFrameIndex = 0;
	var framesLength = frames.length - 1;
	for(;
	keyFrameIndex < framesLength;
	keyFrameIndex++){
	if(frame >= frames[keyFrameIndex].frame && frame <= frames[keyFrameIndex + 1].frame){
	var left = frames[keyFrameIndex];
	var right = frames[keyFrameIndex + 1];
	for(key in left.props){
	if(hasProp.call(left.props,key)){
	var progress = (frame - left.frame) / (right.frame - left.frame);
	//Transform the current progress using the given easing function.progress = left.props[key].easing(progress);
	//Interpolate between the two valuesvalue = _calcInterpolation(left.props[key].value,right.props[key].value,progress);
	value = _interpolateString(value);
	skrollr.setStyle(element,key,value);
}
}
break;
}
}
}
}
;
	/** * Renders all elements. */
var _render = function(){
	if(_requestReflow){
	_requestReflow = false;
	_reflow();
}
//We may render something else than the actual scrollbar position.var renderTop = _instance.getScrollTop();
	//If there's an animation,which ends in current render call,call the callback after rendering.var afterAnimationCallback;
	var now = _now();
	var progress;
	//Before actually rendering handle the scroll animation,if any.if(_scrollAnimation){
	//It's overif(now >= _scrollAnimation.endTime){
	renderTop = _scrollAnimation.targetTop;
	afterAnimationCallback = _scrollAnimation.done;
	_scrollAnimation = undefined;
}
else{
	//Map the current progress to the new progress using given easing function.progress = _scrollAnimation.easing((now - _scrollAnimation.startTime) / _scrollAnimation.duration);
	renderTop = (_scrollAnimation.startTop + progress * _scrollAnimation.topDiff) | 0;
}
_instance.setScrollTop(renderTop,true);
}
//Smooth scrolling only if there's no animation running and if we're not forcing the rendering.else if(!_forceRender){
	var smoothScrollingDiff = _smoothScrolling.targetTop - renderTop;
	//The user scrolled,start new smooth scrolling.if(smoothScrollingDiff){
	_smoothScrolling ={
	startTop:_lastTop,topDiff:renderTop - _lastTop,targetTop:renderTop,startTime:_lastRenderCall,endTime:_lastRenderCall + _smoothScrollingDuration}
;
}
//Interpolate the internal scroll position (not the actual scrollbar).if(now <= _smoothScrolling.endTime){
	//Map the current progress to the new progress using easing function.progress = easings.sqrt((now - _smoothScrolling.startTime) / _smoothScrollingDuration);
	renderTop = (_smoothScrolling.startTop + progress * _smoothScrolling.topDiff) | 0;
}
}
//That's were we actually "scroll" on mobile.if(_isMobile && _skrollrBody){
	//Set the transform ("scroll it").skrollr.setStyle(_skrollrBody,'transform','translate(0,' + -(_mobileOffset) + 'px) ' + _translateZ);
}
//Did the scroll position even change?if(_forceRender || _lastTop !== renderTop){
	//Remember in which direction are we scrolling?_direction = (renderTop > _lastTop) ? 'down':(renderTop < _lastTop ? 'up':_direction);
	_forceRender = false;
	var listenerParams ={
	curTop:renderTop,lastTop:_lastTop,maxTop:_maxKeyFrame,direction:_direction}
;
	//Tell the listener we are about to render.var continueRendering = _listeners.beforerender && _listeners.beforerender.call(_instance,listenerParams);
	//The beforerender listener function is able the cancel rendering.if(continueRendering !== false){
	//Now actually interpolate all the styles._calcSteps(renderTop,_instance.getScrollTop());
	//Remember when we last rendered._lastTop = renderTop;
	if(_listeners.render){
	_listeners.render.call(_instance,listenerParams);
}
}
if(afterAnimationCallback){
	afterAnimationCallback.call(_instance,false);
}
}
_lastRenderCall = now;
}
;
	/** * Parses the properties for each key frame of the given skrollable. */
var _parseProps = function(skrollable){
	//Iterate over all key framesvar keyFrameIndex = 0;
	var keyFramesLength = skrollable.keyFrames.length;
	for(;
	keyFrameIndex < keyFramesLength;
	keyFrameIndex++){
	var frame = skrollable.keyFrames[keyFrameIndex];
	var easing;
	var value;
	var prop;
	var props ={
}
;
	var match;
	while((match = rxPropValue.exec(frame.props)) !== null){
	prop = match[1];
	value = match[2];
	easing = prop.match(rxPropEasing);
	//Is there an easing specified for this prop?if(easing !== null){
	prop = easing[1];
	easing = easing[2];
}
else{
	easing = DEFAULT_EASING;
}
//Exclamation point at first position forces the value to be taken literal.value = value.indexOf('!') ? _parseProp(value):[value.slice(1)];
	//Save the prop for this key frame with his value and easing functionprops[prop] ={
	value:value,easing:easings[easing]}
;
}
frame.props = props;
}
}
;
	/** * Parses a value extracting numeric values and generating a format string * for later interpolation of the new values in old string. * * @param val The CSS value to be parsed. * @return Something like ["rgba(?%,?%,?%,?)",100,50,0,.7] * where the first element is the format string later used * and all following elements are the numeric value. */
var _parseProp = function(val){
	var numbers = [];
	//One special case,where floats don't work.//We replace all occurences of rgba colors//which don't use percentage notation with the percentage notation.rxRGBAIntegerColor.lastIndex = 0;
	val = val.replace(rxRGBAIntegerColor,function(rgba){
	return rgba.replace(rxNumericValue,function(n){
	return n / 255 * 100 + '%';
}
);
}
);
	//Handle prefixing of "gradient" values.//For now only the prefixed value will be set. Unprefixed isn't supported anyway.if(theDashedCSSPrefix){
	rxGradient.lastIndex = 0;
	val = val.replace(rxGradient,function(s){
	return theDashedCSSPrefix + s;
}
);
}
//Now parse ANY number inside this string and create a format string.val = val.replace(rxNumericValue,function(n){
	numbers.push(+n);
	return '{
	?}
';
}
);
	//Add the formatstring as first value.numbers.unshift(val);
	return numbers;
}
;
	/** * Fills the key frames with missing left and right hand properties. * If key frame 1 has property X and key frame 2 is missing X,* but key frame 3 has X again,then we need to assign X to key frame 2 too. * * @param sk A skrollable. */
var _fillProps = function(sk){
	//Will collect the properties key frame by key framevar propList ={
}
;
	var keyFrameIndex;
	var keyFramesLength;
	//Iterate over all key frames from left to rightkeyFrameIndex = 0;
	keyFramesLength = sk.keyFrames.length;
	for(;
	keyFrameIndex < keyFramesLength;
	keyFrameIndex++){
	_fillPropForFrame(sk.keyFrames[keyFrameIndex],propList);
}
//Now do the same from right to fill the last gapspropList ={
}
;
	//Iterate over all key frames from right to leftkeyFrameIndex = sk.keyFrames.length - 1;
	for(;
	keyFrameIndex >= 0;
	keyFrameIndex--){
	_fillPropForFrame(sk.keyFrames[keyFrameIndex],propList);
}
}
;
	var _fillPropForFrame = function(frame,propList){
	var key;
	//For each key frame iterate over all right hand properties and assign them,//but only if the current key frame doesn't have the property by itselffor(key in propList){
	//The current frame misses this property,so assign it.if(!hasProp.call(frame.props,key)){
	frame.props[key] = propList[key];
}
}
//Iterate over all props of the current frame and collect themfor(key in frame.props){
	propList[key] = frame.props[key];
}
}
;
	/** * Calculates the new values for two given values array. */
var _calcInterpolation = function(val1,val2,progress){
	var valueIndex;
	var val1Length = val1.length;
	//They both need to have the same lengthif(val1Length !== val2.length){
	throw 'Can\'t interpolate between "' + val1[0] + '" and "' + val2[0] + '"';
}
//Add the format string as first element.var interpolated = [val1[0]];
	valueIndex = 1;
	for(;
	valueIndex < val1Length;
	valueIndex++){
	//That's the line where the two numbers are actually interpolated.interpolated[valueIndex] = val1[valueIndex] + ((val2[valueIndex] - val1[valueIndex]) * progress);
}
return interpolated;
}
;
	/** * Interpolates the numeric values into the format string. */
var _interpolateString = function(val){
	var valueIndex = 1;
	rxInterpolateString.lastIndex = 0;
	return val[0].replace(rxInterpolateString,function(){
	return val[valueIndex++];
}
);
}
;
	/** * Resets the class and style attribute to what it was before skrollr manipulated the element. * Also remembers the values it had before reseting,in order to undo the reset. */
var _reset = function(elements,undo){
	//We accept a single element or an array of elements.elements = [].concat(elements);
	var skrollable;
	var element;
	var elementsIndex = 0;
	var elementsLength = elements.length;
	for(;
	elementsIndex < elementsLength;
	elementsIndex++){
	element = elements[elementsIndex];
	skrollable = _skrollables[element[SKROLLABLE_ID_DOM_PROPERTY]];
	//Couldn't find the skrollable for this DOM element.if(!skrollable){
	continue;
}
if(undo){
	//Reset class and style to the "dirty" (set by skrollr) values.element.style.cssText = skrollable.dirtyStyleAttr;
	_updateClass(element,skrollable.dirtyClassAttr);
}
else{
	//Remember the "dirty" (set by skrollr) class and style.skrollable.dirtyStyleAttr = element.style.cssText;
	skrollable.dirtyClassAttr = _getClass(element);
	//Reset class and style to what it originally was.element.style.cssText = skrollable.styleAttr;
	_updateClass(element,skrollable.classAttr);
}
}
}
;
	/** * Detects support for 3d transforms by applying it to the skrollr-body. */
var _detect3DTransforms = function(){
	_translateZ = 'translateZ(0)';
	skrollr.setStyle(_skrollrBody,'transform',_translateZ);
	var computedStyle = getStyle(_skrollrBody);
	var computedTransform = computedStyle.getPropertyValue('transform');
	var computedTransformWithPrefix = computedStyle.getPropertyValue(theDashedCSSPrefix + 'transform');
	var has3D = (computedTransform && computedTransform !== 'none') || (computedTransformWithPrefix && computedTransformWithPrefix !== 'none');
	if(!has3D){
	_translateZ = '';
}
}
;
	/** * Set the CSS property on the given element. Sets prefixed properties as well. */
skrollr.setStyle = function(el,prop,val){
	var style = el.style;
	//Camel case.prop = prop.replace(rxCamelCase,rxCamelCaseFn).replace('-','');
	//Make sure z-index gets a <integer>.//This is the only <integer> case we need to handle.if(prop === 'zIndex'){
	if(isNaN(val)){
	//If it's not a number,don't touch it.//It could for example be "auto" (#351).style[prop] = val;
}
else{
	//Floor the number.style[prop] = '' + (val | 0);
}
}
//#64:"float" can't be set across browsers. Needs to use "cssFloat" for all except IE.else if(prop === 'float'){
	style.styleFloat = style.cssFloat = val;
}
else{
	//Need try-catch for old IE.try{
	//Set prefixed property if there's a prefix.if(theCSSPrefix){
	style[theCSSPrefix + prop.slice(0,1).toUpperCase() + prop.slice(1)] = val;
}
//Set unprefixed.style[prop] = val;
}
catch(ignore){
}
}
}
;
	/** * Cross browser event handling. */
var _addEvent = skrollr.addEvent = function(element,names,callback){
	var intermediate = function(e){
	//Normalize IE event stuff.e = e || window.event;
	if(!e.target){
	e.target = e.srcElement;
}
if(!e.preventDefault){
	e.preventDefault = function(){
	e.returnValue = false;
}
;
}
return callback.call(this,e);
}
;
	names = names.split(' ');
	var name;
	var nameCounter = 0;
	var namesLength = names.length;
	for(;
	nameCounter < namesLength;
	nameCounter++){
	name = names[nameCounter];
	if(element.addEventListener){
	element.addEventListener(name,callback,false);
}
else{
	element.attachEvent('on' + name,intermediate);
}
//Remember the events to be able to flush them later._registeredEvents.push({
	element:element,name:name,listener:callback}
);
}
}
;
	var _removeEvent = skrollr.removeEvent = function(element,names,callback){
	names = names.split(' ');
	var nameCounter = 0;
	var namesLength = names.length;
	for(;
	nameCounter < namesLength;
	nameCounter++){
	if(element.removeEventListener){
	element.removeEventListener(names[nameCounter],callback,false);
}
else{
	element.detachEvent('on' + names[nameCounter],callback);
}
}
}
;
	var _removeAllEvents = function(){
	var eventData;
	var eventCounter = 0;
	var eventsLength = _registeredEvents.length;
	for(;
	eventCounter < eventsLength;
	eventCounter++){
	eventData = _registeredEvents[eventCounter];
	_removeEvent(eventData.element,eventData.name,eventData.listener);
}
_registeredEvents = [];
}
;
	var _reflow = function(){
	var pos = _instance.getScrollTop();
	//Will be recalculated by _updateDependentKeyFrames._maxKeyFrame = 0;
	if(_forceHeight && !_isMobile){
	//un-"force" the height to not mess with the calculations in _updateDependentKeyFrames (#216).body.style.height = 'auto';
}
_updateDependentKeyFrames();
	if(_forceHeight && !_isMobile){
	//"force" the height.body.style.height = (_maxKeyFrame + documentElement.clientHeight) + 'px';
}
//The scroll offset may now be larger than needed (on desktop the browser/os prevents scrolling farther than the bottom).if(_isMobile){
	_instance.setScrollTop(Math.min(_instance.getScrollTop(),_maxKeyFrame));
}
else{
	//Remember and reset the scroll pos (#217)._instance.setScrollTop(pos,true);
}
_forceRender = true;
}
;
	/* * Returns the height of the document. */
var _getDocumentHeight = function(){
	var skrollrBodyHeight = (_skrollrBody && _skrollrBody.offsetHeight || 0);
	var bodyHeight = Math.max(skrollrBodyHeight,body.scrollHeight,body.offsetHeight,documentElement.scrollHeight,documentElement.offsetHeight,documentElement.clientHeight);
	return bodyHeight - documentElement.clientHeight;
}
;
	/** * Returns a string of space separated classnames for the current element. * Works with SVG as well. */
var _getClass = function(element){
	var prop = 'className';
	//SVG support by using className.baseVal instead of just className.if(window.SVGElement && element instanceof window.SVGElement){
	element = element[prop];
	prop = 'baseVal';
}
return element[prop];
}
;
	/** * Adds and removes a CSS classes. * Works with SVG as well. * add and remove are arrays of strings,* or if remove is ommited add is a string and overwrites all classes. */
var _updateClass = function(element,add,remove){
	var prop = 'className';
	//SVG support by using className.baseVal instead of just className.if(window.SVGElement && element instanceof window.SVGElement){
	element = element[prop];
	prop = 'baseVal';
}
//When remove is ommited,we want to overwrite/set the classes.if(remove === undefined){
	element[prop] = add;
	return;
}
//Cache current classes. We will work on a string before passing back to DOM.var val = element[prop];
	//All classes to be removed.var classRemoveIndex = 0;
	var removeLength = remove.length;
	for(;
	classRemoveIndex < removeLength;
	classRemoveIndex++){
	val = _untrim(val).replace(_untrim(remove[classRemoveIndex]),' ');
}
val = _trim(val);
	//All classes to be added.var classAddIndex = 0;
	var addLength = add.length;
	for(;
	classAddIndex < addLength;
	classAddIndex++){
	//Only add if el not already has class.if(_untrim(val).indexOf(_untrim(add[classAddIndex])) === -1){
	val += ' ' + add[classAddIndex];
}
}
element[prop] = _trim(val);
}
;
	var _trim = function(a){
	return a.replace(rxTrim,'');
}
;
	/** * Adds a space before and after the string. */
var _untrim = function(a){
	return ' ' + a + ' ';
}
;
	var _now = Date.now || function(){
	return +new Date();
}
;
	var _keyFrameComparator = function(a,b){
	return a.frame - b.frame;
}
;
	/* * Private variables. */
//Singletonvar _instance;
	/*A list of all elements which should be animated associated with their the metadata.Exmaple skrollable with two key frames animating from 100px width to 20px:skrollable ={
	element:<the DOM element>,styleAttr:<style attribute of the element before skrollr>,classAttr:<class attribute of the element before skrollr>,keyFrames:[{
	frame:100,props:{
	width:{
	value:['{
	?}
px',100],easing:<reference to easing function>}
}
,mode:"absolute"}
,{
	frame:200,props:{
	width:{
	value:['{
	?}
px',20],easing:<reference to easing function>}
}
,mode:"absolute"}
]}
;
	*/
var _skrollables;
	var _skrollrBody;
	var _listeners;
	var _forceHeight;
	var _maxKeyFrame = 0;
	var _scale = 1;
	var _constants;
	var _mobileDeceleration;
	//Current direction (up/down).var _direction = 'down';
	//The last top offset value. Needed to determine direction.var _lastTop = -1;
	//The last time we called the render method (doesn't mean we rendered!).var _lastRenderCall = _now();
	//For detecting if it actually resized (#271).var _lastViewportWidth = 0;
	var _lastViewportHeight = 0;
	var _requestReflow = false;
	//Will contain data about a running scrollbar animation,if any.var _scrollAnimation;
	var _smoothScrollingEnabled;
	var _smoothScrollingDuration;
	//Will contain settins for smooth scrolling if enabled.var _smoothScrolling;
	//Can be set by any operation/event to force rendering even if the scrollbar didn't move.var _forceRender;
	//Each skrollable gets an unique ID incremented for each skrollable.//The ID is the index in the _skrollables array.var _skrollableIdCounter = 0;
	var _edgeStrategy;
	//Mobile specific vars. Will be stripped by UglifyJS when not in use.var _isMobile = false;
	//The virtual scroll offset when using mobile scrolling.var _mobileOffset = 0;
	//If the browser supports 3d transforms,this will be filled with 'translateZ(0)' (empty string otherwise).var _translateZ;
	//Will contain data about registered events by skrollr.var _registeredEvents = [];
	//Animation frame id returned by RequestAnimationFrame (or timeout when RAF is not supported).var _animFrame;
}
(window,document));
	
附件:下载该文件资源,减少时间成本(增值服务)
留言
该资源可下载
File Source
.rar
82.94 KB
html5特效
最新结算
jquery虚拟键盘中文打字效果js代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
jquery虚拟键盘中文打字效果js代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
HTML5实现CSS滤镜图片切换特效代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
jQuery头像裁剪插件cropbox js代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery头像裁剪插件cropbox js代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
CSS3制作3D图片立方体旋转特效
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery+css3实现信封效果
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
我们力求给您提供有用的文章,再此基础上,会附加营收资源,不做任何广告,让平台可以更好发展 若您发现您的权利被侵害,或使用了您的版权,请发邮件联系 sunlifel@foxmail.com ggbig觉得 : 不提供源码的文章不是好文章
合作伙伴
联系我们
  • QQ:21499807
  • 邮箱:sunlifel@foxmail.com
  • QQ扫一扫加QQ
    QQ扫一扫
Copyright 2023-2024 ggbig.com·皖ICP备2023004211号-1
打赏文章