Chrome奇怪(scaleY)过渡行为

时间:2016-10-23 18:35:29

标签: jquery css google-chrome css-transitions inline-styles

所以我一直在研究基于CSS过渡的轻量级插件。它能够动态添加内联样式(转换)。

插件代码的某些部分(如前缀CSS属性)将被删除,以使事情更加清晰:

(function($, window, document) {
    'use strict';

    var plugin   = 'transition';

    // Constructors
    function Transition(element, animation, options) {
        this.element   = element;
        this.animation = animation;
        this.direction = null;
        this.settings  = $.extend({}, $.fn[plugin].defaults, options);
        this.init();
    }

    // Instance
    $.extend(Transition.prototype, {

        init: function() {
            var instance = this;
          
            instance.direction = $(instance.element).is(':visible') ? // toggle
                'outward':
                'inward' ;

            setTimeout(function() { // separate queue entry to make sure previous re-draw events are finished
                instance.settings.animations.hasOwnProperty(instance.animation) ?
                    instance.start():
                    console.error('Trying to call an undefined animation');
            }, 0);
        },

        /**
         * Start the transition.
         */
        start: function() {
            var instance  = this,
                $element  = $(instance.element);

            // Bind handlers
            $element
                .one('transitionstart', function() {
                    instance.settings.onStart.call($element);
                })
                .one('transitionend', function() {
                    instance.end();
                });

            // Add inline styles
            $element
                .css(instance.style('start'))
                .show() // ensure the element is visible
                .css(instance.style('end'));
        },


        /**
         * End the transition.
         */
        end: function() {
            var instance  = this,
                $element  = $(instance.element);

            instance.direction == 'inward' ?
                $element.show():
                $element.hide();

            instance.settings.onEnd.call($element);

            $element.css({
                opacity: '',
                transform: '',
                transformOrigin: '',
                transition: ''
            }).dequeue();
        },

        /**
         * Get the inline style for the transition.
         *
         * @param state
         */
        style: function(state) {
            var instance  = this,
                animation = instance.settings.animations[instance.animation],
                direction = instance.direction,
                css       = {};

            if (state === 'start') {
                css = (direction == 'inward') ?
                    animation.start:
                    animation.end; // reversed

                css['transition'] = 'all ' + 
                    instance.settings.duration + 'ms ' + 
                    instance.settings.curve + ' ' + 
                    instance.settings.delay + 'ms';
            } else {
                css = (direction == 'inward') ?
                    animation.end:
                    animation.start; // reversed
            }
            
            return css;
        }
    });

    // Plugin definition
    $.fn[plugin] = function(animation, options) {
        return this.each(function() {
            $(this).queue(function() {
                new Transition(this, animation, options);
            });
        });
    };

    // Default settings
    $.fn[plugin].defaults = {
        duration : 500,
        delay    : 0,
        curve    : 'ease',
        onStart  : function() {},
        onEnd    : function() {}
    };

    $.fn[plugin].defaults.animations = {
        fade: {
            start : { 'opacity': 0 },
            end   : { 'opacity': 1 }
        },
        scale: {
            start : { 'opacity': 0, 'transform': 'scale(0.8)' },
            end   : { 'opacity': 1, 'transform': 'scale(1.0)' }
        },
        slide: {
            start : { 'opacity': 0, 'transform': 'scaleY(0)', 'transform-origin': 'bottom'},
            end   : { 'opacity': 1, 'transform': 'scaleY(1)', 'transform-origin': 'bottom'}
        }
    };

})(jQuery, window, document);

$('#fading').transition('fade', {duration: 1000, delay: 1000});
$('#scaling').transition('scale', {duration: 1000, delay: 1000});
$('#sliding').transition('slide', {duration: 1000, delay: 1000});
div {
  display: inline-block;
  margin-bottom: 1em;
  padding: 3em 2em;
  background-color: #EEE;
  border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fading">Fading block</div>
<div id="scaling">Scaling block</div>
<div id="sliding">Sliding block</div>

由于某种原因,滑动动画在Chrome上不起作用,元素只会淡入/淡出。 FireFox和Edge没有这个问题。

应用于滑动动画的CSS:

slide: {
    start : { 'opacity': 0, 'transform': 'scaleY(0)', 'transform-origin': 'bottom'},
    end   : { 'opacity': 1, 'transform': 'scaleY(1)', 'transform-origin': 'bottom'}
}

希望任何魔术师能够弄清楚发生了什么。

1 个答案:

答案 0 :(得分:1)

这是转换比例(0)的已知错误。只需将其更改为比例(0.01)。

&#13;
&#13;
(function($, window, document) {
  'use strict';

  var plugin = 'transition';

  // Constructors
  function Transition(element, animation, options) {
    this.element = element;
    this.animation = animation;
    this.direction = null;
    this.settings = $.extend({}, $.fn[plugin].defaults, options);
    this.init();
  }

  // Instance
  $.extend(Transition.prototype, {

    init: function() {
      var instance = this;

      instance.direction = $(instance.element).is(':visible') ? // toggle
        'outward' :
        'inward';

      setTimeout(function() { // separate queue entry to make sure previous re-draw events are finished
        instance.settings.animations.hasOwnProperty(instance.animation) ?
          instance.start() :
          console.error('Trying to call an undefined animation');
      }, 0);
    },

    /**
     * Start the transition.
     */
    start: function() {
      var instance = this,
        $element = $(instance.element);

      // Bind handlers
      $element
        .one('transitionstart', function() {
          instance.settings.onStart.call($element);
        })
        .one('transitionend', function() {
          instance.end();
        });

      // Add inline styles
      $element
        .css(instance.style('start'))
        .show() // ensure the element is visible
        .css(instance.style('end'));
    },


    /**
     * End the transition.
     */
    end: function() {
      var instance = this,
        $element = $(instance.element);

      instance.direction == 'inward' ?
        $element.show() :
        $element.hide();

      instance.settings.onEnd.call($element);

      $element.css({
        opacity: '',
        transform: '',
        transformOrigin: '',
        transition: ''
      }).dequeue();
    },

    /**
     * Get the inline style for the transition.
     *
     * @param state
     */
    style: function(state) {
      var instance = this,
        animation = instance.settings.animations[instance.animation],
        direction = instance.direction,
        css = {};

      if (state === 'start') {
        css = (direction == 'inward') ?
          animation.start :
          animation.end; // reversed

        css['transition'] = 'all ' +
          instance.settings.duration + 'ms ' +
          instance.settings.curve + ' ' +
          instance.settings.delay + 'ms';
      } else {
        css = (direction == 'inward') ?
          animation.end :
          animation.start; // reversed
      }

      return css;
    }
  });

  // Plugin definition
  $.fn[plugin] = function(animation, options) {
    return this.each(function() {
      $(this).queue(function() {
        new Transition(this, animation, options);
      });
    });
  };

  // Default settings
  $.fn[plugin].defaults = {
    duration: 500,
    delay: 0,
    curve: 'ease',
    onStart: function() {},
    onEnd: function() {}
  };

  $.fn[plugin].defaults.animations = {
    fade: {
      start: {
        'opacity': 0
      },
      end: {
        'opacity': 1
      }
    },
    scale: {
      start: {
        'opacity': 0,
        'transform': 'scale(0.8)'
      },
      end: {
        'opacity': 1,
        'transform': 'scale(1.0)'
      }
    },
    slide: {
      start: {
        'opacity': 0.5,
        'transform': 'scaleY(0.01)',
        'transform-origin': 'bottom'
      },
      end: {
        'opacity': 1,
        'transform': 'scaleY(1)',
        'transform-origin': 'bottom'
      }
    }
  };

})(jQuery, window, document);

$('#fading').transition('fade', {
  duration: 1000,
  delay: 1000
});
$('#scaling').transition('scale', {
  duration: 1000,
  delay: 1000
});
$('#sliding').transition('slide', {
  duration: 1000,
  delay: 1000
});
&#13;
div {
  display: inline-block;
  margin-bottom: 1em;
  padding: 3em 2em;
  background-color: #EEE;
  border: 1px solid red;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fading">Fading block</div>
<div id="scaling">Scaling block</div>
<div id="sliding">Sliding block</div>
&#13;
&#13;
&#13;