最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Element.animate() in HTML4 - Stack Overflow

programmeradmin7浏览0评论

It seems the people at Chrome have appropriated Element.animate() for themselves, effectively breaking all existing HTML pages using something along the lines of onclick="animate();".

Is this legal for a browser under the HTML 4/Transitional spec? Is this something that W3C would formally have authority over?

Is there anything small-time website owners can do to prevent any further transgressions of this sort?

EDIT: Test Case:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    ".dtd">
<html>
<head>
    <title>test</title>
    <script type="text/javascript">
        function animate() {
            alert('this should work');
        }
    </script>
</head>
<body>
    <input type="button" onclick="animate();" value="push me!">
</body>
</html>

Results in Uncaught TypeError: Failed to execute 'animate' on 'Element': 1 argument required, but only 0 present. on Chrome, but works in FireFox.

It seems the people at Chrome have appropriated Element.animate() for themselves, effectively breaking all existing HTML pages using something along the lines of onclick="animate();".

Is this legal for a browser under the HTML 4/Transitional spec? Is this something that W3C would formally have authority over?

Is there anything small-time website owners can do to prevent any further transgressions of this sort?

EDIT: Test Case:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
    <title>test</title>
    <script type="text/javascript">
        function animate() {
            alert('this should work');
        }
    </script>
</head>
<body>
    <input type="button" onclick="animate();" value="push me!">
</body>
</html>

Results in Uncaught TypeError: Failed to execute 'animate' on 'Element': 1 argument required, but only 0 present. on Chrome, but works in FireFox.

Share Improve this question edited Jul 21, 2014 at 17:49 Dexter asked Jul 21, 2014 at 17:26 DexterDexter 3,1225 gold badges32 silver badges34 bronze badges 7
  • 2 I'm pretty sure nobody can prevent Google from doing pretty much anything. – Pointy Commented Jul 21, 2014 at 17:28
  • 2 The .animate() method is defined by a currently-in-draft specification hosted by W3C (linked in the 3rd paragraph of the article). It isn't just for Chrome and stands a good chance at seeing adoption by other browsers. One option to avoid conflicts is to avoid depending on obtrusive/embedded JavaScript and the implied with (this) {} block that onevent attributes use. – Jonathan Lonowski Commented Jul 21, 2014 at 17:40
  • I'm not sure they've "appropriated" anything. They've added a method to the prototype of elements in the DOM, probably according to some draft standard being worked on with other browser vendors. I'm not even sure your example is affected, because surely animate() there will look for window.animate() whereas the new method would be this.animate() – IMSoP Commented Jul 21, 2014 at 17:41
  • 2 Attach event listeners properly, and you’ll be fine. – Ry- Commented Jul 21, 2014 at 17:52
  • 1 It seems I was wrong, and this.animate is used if set. However, you can always qualify the function name explicitly to run a global function. See this example: jsfiddle/bKB8E/4 – IMSoP Commented Jul 21, 2014 at 17:56
 |  Show 2 more ments

1 Answer 1

Reset to default 9

The change you are referring to is not a unilateral move by Google, but part of a draft W3C standard called Web Animations 1.0. The specific modification you are running into trouble with is the extension to the DOM Element interface which adds three new methods, including animate():

Since DOM Elements may be the target of an animation, the Element interface [DOM4] is extended as follows: Element implements Animatable;

This allows the following kind of usage. elem.animate({ color: 'red' }, 2000);

DOM here stands for "Document Object Model", which is another standard, separate from HTML which defines how JavaScript and other languages should expose and interact with an HTML, XML, or similar document. This standard has had many expansions over the years, so the addition of this new method to Element objects is by no means unprecedented or likely to be controversial.


Your specific problem is one of namespace collision. JavaScript's scoping rules are relatively plex in any situation, and when you embed an event handler in an HTML attribute, there is some special logic, as explained in this MDN article about "event attributes".

The upshot is that when you write onclick="animate();", animate is looked up as a property in multiple scopes, or namespaces, including:

  • as a property of the clicked element, which has been bound to this; if found, animate() will behave the same as this.animate()
  • as a property of the global window object, which is always the last scope checked in any situation; thus if nothing else is found, animate() will be equivalent to window.animate()

Your problem is that you are relying on something being called from the global namespace, but the changes to the DOM mean that it is now defined on this as well (specifically, it is in the prototype of all descendants of Element). Since the new function takes precedence over your existing one, an unexpected behaviour change occurs.

The simplest fix to your code is therefore to qualify your event more specifically, as onclick="window.animate();". You should do this not just for methods and variables you know have conflicts now, but on all of them, so that they won't be affected by other changes to the DOM in future. (Here is a demo of that approach.)


However, if you want to make your code more robust, there are more extensive changes you should make to bring it in line with more up to date coding practices:

  • Rather than using "event attributes" such as onclick, add event listeners programmatically. The modern API for this is addEventListener, although many people prefer a library like jQuery which makes it easier to work with different browsers, and simplifies mon tasks (in this case, you'd use the .on() method).
  • Rather than putting functions into a global scope, make them properties of some object, so that you can keep track of your own namespaces. Even better, if you keep them separate from the HTML (using something like addEventListener or jQuery's .on), you can make them private variables, not even accessible from global scope, by using an IIFE (an enclosing function which exists only to create a new variable scope).
发布评论

评论列表(0)

  1. 暂无评论