在所有可能的世界中做到最好:将JavaScript与CSS动画混合

and are two separate technologies with individual strengths and weaknesses, and will always remain so. Traditionally, the two have been characterized as controlling “behavior” and “appearance” respectively, but over the last several years CSS has grown significantly in scale, scope and power, causing it to tread on JavaScript’s toes in some areas. As one example, CSS offers smoother, more performant animation,  at the cost of compatibility with older versions of Internet Explorer. Due to these complications, it’s not always clear which option is best for a developer to take: do we create animations purely in CSS, or in JavaScript?

是两种具有各自优点和缺点的独立技术,并且将始终保持这种状态。 传统上,这两者的特征分别是控制“行为”和“外观”,但是在过去的几年中,CSS的规模,范围和功能都得到了显着增长,使其在某些领域陷入了JavaScript的困境。 作为一个示例,CSS提供了更平滑,更高效的动画,但以与旧版本的Internet Explorer兼容为代价。 由于这些复杂性,并不清楚总是哪个选项最适合开发人员:我们是纯粹用CSS还是JavaScript来创建动画?

The ideal solution is to use both: employ JavaScript where it works best, and use CSS for the rest. A good example would be my article a year ago on Animating Elements Sequentially, which used JQuery to change a series of photographs. A best practice would be to build the fade in effect for each image in CSS, and apply that using JavaScript.

理想的解决方案是同时使用这两种方法:在效果最好的地方使用JavaScript,而在其余部分使用CSS。 一个很好的例子是我一年前在Animating Sequencesly上的文章,该文章使用JQuery更改了一系列照片。 最好的做法是建立淡入效果在CSS每个图像,并申请使用 JavaScript。

HTML (The HTML)

Let’s start with fresh markup:

让我们从新的标记开始:

<div id="planets">
	<img src="jupiter.jpg" alt="Jupiter">
	<img src="earth.jpg" alt="Earth">
	<img src="mars.jpg" alt="Mars">
	<img src="saturn.jpg" alt="Saturn">
	<img src="neptune.jpg" alt="Neptune">
	<img src="venus.jpg" alt="Venus">
</div>

CSS (The CSS)

With a little code to ensure that the images display well on smaller screens:

使用少量代码来确保图像在较小的屏幕上显示良好:

div#planets {
	font-size: 0;
	background: #000;
	overflow: hidden;
}
div#planets img {
	float: left;
	width: 33.33%;
}
@media (max-width: 500px) { 
	div#planets img {
		width: 50%;
	} 
}

Each of these images will fade in sequentially over several seconds. Writing a transition for each image would be tiresome in the extreme, but we can describe the transition generally:

这些图像中的每一个都会在几秒钟内逐渐消失。 在极端情况下为每个图像编写过渡会很累,但是我们可以大致描述过渡:

div#planets img {
	float: left;
	width: 33.33%;
	opacity: 0;
	transition: .4s opacity;
}

(Note that I’ve kept the code free of vendor prefixes for clarity).

(请注意,为清楚起见,我使代码中没有供应商前缀 )。

添加JavaScript (Adding JavaScript)

Unlike the previous example, I’m going to use pure JavaScript rather than JQuery to loop through the images in the container: it’s silly to load 100K of a library just to execute an iteration. First, we need to identify just how many images there are. At the end of your page, add a script:

与前面的示例不同,我将使用纯JavaScript而不是JQuery遍历容器中的图像:加载库的100K只是执行迭代是很愚蠢的。 首先,我们需要确定有多少张图片。 在页面的结尾,添加一个脚本:

var planets = document.getElementById("planets"),
numplanets = document.querySelectorAll("#planets > img").length;

(The use of querySelector will limit this solution to IE 8 and above, although there’s longer and more traditional code you could use if you wanted to gain greater backward compatibility).

(使用querySelector会将此解决方案限制为IE 8及更高版本,但如果希望获得更大的向后兼容性,则可以使用更长和更多的传统代码)。

Then we need to loop through each image in the container:

然后,我们需要遍历容器中的每个图像:

var planets = document.getElementById("planets"),
numPlanets = document.querySelectorAll("#planets > img").length,
planetPhotos = planets.childNodes;
for (var i = 0; i < numPlanets; i++) {
	...      
}

Before animating the images, let’s see what we have in our collection of objects. Inside the loop, add:

在对图像进行动画处理之前,让我们看一下对象集合中的内容。 在循环内,添加:

alert(planetPhotos[i]);

(Or, if you want the result to be less annoying and know a little bit about the console:

(或者,如果您希望结果不那么令人讨厌并且对控制台有所了解:

console.write(planetPhotos[i]); )

格式化节点列表 (Formatting A Nodelist)

Taking a look at the output in a browser may reveal something odd: the nodelist (a collection of all the child elements inside planet) may have some errant additions. In some browsers you’ll see reports of six HTMLImageElement objects together with a number of text objects. We want the former, but not the latter. What’s going on?

在浏览器中查看输出可能会发现一些奇怪的事情:nodelist( planet内部所有子元素的集合)可能有一些错误的添加。 在某些浏览器中,您将看到六个HTMLImageElement对象以及许多文本对象的报告。 我们需要前者,而不是后者。 这是怎么回事?

The browser is interpreting whitespace as text nodes, and adding them to the collection. That’s annoying, and can be treated in several ways: right now we’ll take the easiest solution, and set font-size inside the <div> to 0:

浏览器将空白解释为文本节点,并将其添加到collection中 。 这很烦人,可以通过几种方法进行处理:现在,我们将采用最简单的解决方案,并将<div> font-size设置为0:

div#planets { font-size: 0; }

With that done, let’s replace the alert/console write with something useful:

完成此操作后,让我们用一些有用的内容替换警报/控制台写入:

for (var i = 0, numPlanets; i < numPlanets; i++) {
planetPhotos[i].style.opacity = 1;
}

That works, but the result is almost instantaneous for all the images: we want a pause between each transition.

可以,但是所有图像的结果几乎都是瞬时的:我们希望在每个过渡之间都暂停一下。

暂停JavaScript (Pausing JavaScript)

JavaScript is made to respond to events, not to be shackled: generally speaking we want our scripts to run as fast as possible, without blocking any other activity on the page. For that reason, JavaScript “pauses” are abstracted into two functions: setInterval and setTimeout.

使JavaScript响应事件,而不是束手无策:一般来说,我们希望我们的脚本尽可能快地运行,而不会阻塞页面上的任何其他活动。 因此,JavaScript“暂停”被抽象为两个函数: setIntervalsetTimeout

You would think that something like this might work:

您会认为这样的事情可能会起作用:

setTimeout(planetPhotos[i].style.opacity = 1), 500)

But sadly, no: the timeouts will essentially all execute at the same time.  Instead, we have to abstract things out a little further. The complete script becomes:

但是可悲的是,没有:超时基本上将在同一时间执行。 相反,我们必须进一步抽象一些东西。 完整的脚本变为:

function createTimer(i) {
	setTimeout(function() {
planetPhotos[i].style.opacity = 1;
    }, 1000 + 1000 * i)
}
function iterate(numPlanets) {
    for (var i = 0; i < numPlanets; i++) {
    	createTimer(i);
    }
}
var planets = document.getElementById("planets"),
numPlanets = document.querySelectorAll("#planets > img").length,
planetPhotos = planets.childNodes;
iterate(numPlanets);

(Note that the 1000 + 1000 part of the setTimeOut function is present so that the first image is also delayed in appearing on the page).

(请注意,存在setTimeOut函数的1000 + 1000部分,因此也会延迟第一张图像在页面上的显示)。

If you wanted to create greater separation between appearance and behavior, rewrite the new appearance of the images as a class, and use JavaScript to add the class to each image, rather than changing its opacity directly:

如果要在外观和行为之间建立更大的隔离,请重写图像的新外观作为一个类,并使用JavaScript将类添加到每个图像中,而不是直接更改其不透明度:

div#planets img.wax {
	opacity: 1;
}

And the JavaScript:

和JavaScript:

function createTimer(i) {
	setTimeout(function() {
planetPhotos[i].className = "wax";
		}, 1000 + 1000 * i)
}

This also allows you to alter the animation very quickly: if you wanted the effect of the images both growing in size and fading in at the same time, as in the example above, simply change the CSS:

这也使您可以非常快速地更改动画:如果您想要图像同时增大和渐弱的效果(如上例所示),只需更改CSS:

div#planets img {
	float: left;
	width: 33.33%;
	opacity: 0;
	transform: scale(0); 
	transition: .4s all;
}
div#planets img.wax {
	opacity: 1;
	transform: scale(1);
}

This result is the best of all possible worlds: gaining smooth animations from CSS while leveraging the power of JavaScript. One drawback is that the code lacks a fallback for IE 8 and 9, which do not support CSS transitions. I’ll demonstrate at a solution for those browsers in the next article.

这个结果是所有可能的世界中最好的:在利用JavaScript的功能的同时,从CSS获得流畅的动画。 缺点之一是该代码缺少IE 8和9的后备功能,后者不支持CSS过渡。 在下一篇文章中,我将为这些浏览器演示一种解决方案。

翻译自: https://thenewcode.com/709/The-Best-Of-All-Possible-Worlds-Hybridizing-JavaScript-With-CSS-Animations

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值