简体   繁体   中英

Element.animate() in HTML4

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.org/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.

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 complex 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 common 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM