TL:DR
- 跨浏览器:[**查看工作演示
这里**](http://jsfiddle.net/lthibodeaux/8DSjz/)。
嗯,主要是工作......和
跨浏览器。可以做得更糟。 ;]
- 纯 CSS3 解决方案:[**查看工作演示
这里**](http://jsfiddle.net/lthibodeaux/8DSjz/16/)
我该如何开始描述这个?如果 CSS 2 剪辑标准支持除“rect”值之外的任何内容,即“circle”或“ellipse”,那就容易多了,但是......因为不存在,我已经尽力拼凑一些东西一起做你所要求的。警告有很多。一个是,如果您希望将图片剪辑到背景,这仅适用于具有纯色背景的东西。另一个原因是,虽然我尝试考虑跨浏览器的 CSS 更新时间,但渲染仍然不是“完美的”。我最初的方法是简单地对要替换的图像上的剪辑进行动画处理,但是由于通过我找到的插件中的缓动功能对剪辑进行更新的方式,这不起作用。最后的方法如下。
方法
概念是将图像设置为容器的background-image 属性,如<div> 与center center 的background-position,容器的position 为relative,或任何非-静止的。接下来是生成剪辑元素作为容器的子项。第一个是背景颜色的position: absolute 剪裁圆图像,可以是透明的PNG 或GIF(我更喜欢前者),接下来的四个是div,还有absolute 的位置,有left、@987654332 @、top 和 bottom 属性设置为 0,它们将剪裁的每一边。这个想法是动画top,left,width,和height 的剪辑圆图像,并使用 .animate() 调用的 step 回调选项同步剪辑 div 的宽度和高度通过将它们与当前的 left 和 top 值匹配。在动画之间,您将容器的background-image 更改为新图像,然后以相反的方向重新启动动画。
这需要在 IE7、8 和 Webkit 浏览器中进行一些微调,因为动画在 Firefox 和 IE9 中剪辑得更加清晰。这将是您将在工作演示中看到的 adjust 变量。
示例代码如下:
标记
<div class="imageContainer image1">
<img class="clip" src="clipCircle.png" />
<div class="top fill"></div>
<div class="left fill"></div>
<div class="right fill"></div>
<div class="bottom fill"></div>
</div>
CSS
div.imageContainer
{
background-position: center;
width: 300px;
height: 300px;
position: relative;
}
img.clip
{
width: 100%;
height: 100%;
position: absolute;
}
div.fill
{
position: absolute;
background-color: White;
}
div.left, div.right
{
height: 100%;
top: 0;
width: 0;
}
div.left
{
left: 0;
}
div.right
{
right: 0;
}
div.top, div.bottom
{
width: 100%;
left: 0;
height: 0;
}
div.top
{
top: 0;
}
div.bottom
{
bottom: 0;
}
脚本
var speed = 1000;
$clip = $("img.clip");
$clip.animate({
top: $clip.parent().height() / 2,
left: $clip.parent().width() / 2,
width: 0,
height: 0
}, {
duration: speed,
step: function(now, fx) {
switch (fx.prop) {
case "top":
$("div.top").css("height", now);
$("div.bottom").css("height", now + adjust);
break;
case "left":
$("div.left").css("width", now);
$("div.right").css("width", now + adjust);
}
},
complete: function() {
$(this).parent().addClass("image2");
$(this).animate({
top: 0,
left: 0,
width: $clip.parent().width(),
height: $clip.parent().height()
}, {
duration: speed,
step: function(now, fx) {
switch (fx.prop) {
case "top":
$("div.top").css("height", now);
$("div.bottom").css("height", now + adjust);
break;
case "left":
$("div.left").css("width", now);
$("div.right").css("width", now + adjust);
}
},
complete: function() {
$("div.imageContainer > *").removeAttr("style");
}
});
}
});
编辑:
CSS3 解决方案
当跨浏览器兼容性不太重要时,CSS3 是一种选择(尽管我可能会建议看看新的 HTML5 Canvas 可以为这种动画做什么)。有几点需要注意:
- 图像必须位于容器内,以便我们可以向其中心而不是左上角剪辑。
- border-radius 属性不会裁剪容器内的子图像。为此,图片必须成为容器的背景图片属性。
- jQuery 目前不能正确地为边界半径设置动画。您可以替换该属性的当前 jQuery 动画功能或构建自定义边框半径动画对象以使 jQuery 表现得更好。我选择了后者。每个角的边界半径必须单独设置动画。
- 动画输入或输出由两个单独的段组成,因此“线性”缓动函数可能最适合用于最清晰的结果。
该方法在下面内联注释:
标记
<div class="imageContainer image1">
</div>
CSS
div.imageContainer
{
background-position: 0px 0px;
background-repeat: no-repeat;
width: 300px;
height: 300px;
position: absolute;
top: 0;
left: 0;
}
div.image1
{
background-image: url(/images/myFirstImage.png);
}
div.image2
{
background-image: url(/images/mySecondImage.png);
}
脚本
// Total animation speed in or out will be speed * 1.5
var speed = 600;
// Store a reference to the object to be clipped
var $clip = $("div")
// A function to build a mapping object for border radius parameters
var buildRadiusObj = function(value) {
// Dimension an option object
var opts = {};
// Use specialized Mozilla CSS attributes when needed
var attributes = $.browser.mozilla ?
["-moz-border-radius-topleft",
"-moz-border-radius-bottomleft",
"-moz-border-radius-topright",
"-moz-border-radius-bottomright"] :
["border-top-left-radius",
"border-bottom-left-radius",
"border-top-right-radius",
"border-bottom-right-radius"];
// Build the option object
$.each(attributes, function(i, key) {
opts[key] = value;
});
// Return the result
return opts;
}
$clip.animate(buildRadiusObj($clip.width() * 0.5), { // Animate the border radius until circular
duration: speed * 0.5,
easing: "linear"
}).animate({ // Resize and reposition the container
width: 0,
left: $clip.width() / 2,
height: 0,
top: $clip.height() / 2
}, {
duration: speed,
easing: "linear",
step: function(now, fx) { // Synch up the background-position
if (fx.prop == "top") {
$(this).css("background-position", "-" + $(this).css("top") + " -" + $(this).css("left"));
}
},
complete: function() { // Swap the image
$(this).addClass("image2");
}
}).animate({ // Restore position and size
width: $clip.width(),
left: 0,
height: $clip.height(),
top: 0
}, {
duration: speed,
easing: "linear",
step: function(now, fx) { // Synch the background-position
if (fx.prop == "top") {
$(this).css("background-position", "-" + $(this).css("top") + " -" + $(this).css("left"));
}
},
complete: function() { // Remove inline styles but reapply border-radius
$(this).removeAttr("style").css(buildRadiusObj($clip.width() * 0.5));
}
}).animate(buildRadiusObj(0), { // Restore border-radius to block
duration: speed * 0.5,
easing: "linear",
complete: function() {
$(this).removeAttr("style"); // Remove inline styles
}
});
Again, the demo is located here.