TL: DR
Как мне вообще начать описывать это?Было бы намного проще, если бы стандарт клипа CSS 2 поддерживал что-либо, кроме значения "rect", а именно "circle" или "ellipse", но ... поскольку этого не существует, я приложил все усилия, чтобы что-то собратьвместе это сделает то, что вы просите.Предостережения много.Во-первых, это будет работать только на чем-то с однотонным фоном, если вы хотите, чтобы изображение обрезало фон.Другое - то, что, хотя я и пытался учесть время обновления CSS в разных браузерах, рендеринг все еще не "идеален".Мой первоначальный подход состоял в том, чтобы просто анимировать клип на изображении, которое заменялось, но это не сработало из-за того, как были сделаны обновления в отсечении с помощью функции замедления в плагине, который я нашел.Окончательный подход приведен ниже.
Подход
Идея состоит в том, чтобы установить изображение как свойство background-image
контейнера, такого как <div>
, с background-position
из center center
и position
контейнера до relative
, или что-нибудь нестатичное.Следующее - генерировать элементы отсечения как дочерние элементы контейнера.Первый - это position: absolute
изображение обтравочного круга цвета вашего фона, либо прозрачный PNG, либо GIF (я предпочитаю первый), а следующие четыре - это div, также с позициями absolute
, которые имеют left
, * 1034Атрибуты *, top
и bottom
установлены в 0 для каждой из соответствующих сторон, которые они будут обрезать.Идея состоит в том, чтобы анимировать top
, left
, width
и height
изображения обтравочного круга и синхронизировать ширину и высоту обтравочных элементов с помощью опции обратного вызова шага вызова .animate ()сопоставляя их с текущими значениями left
и top
.Между анимациями вы изменяете background-image
контейнера на новое изображение и затем запускаете анимацию обратно в противоположном направлении.
Это потребовало небольшого перебора в браузерах IE7, 8 и Webkit, когда анимация обрезаласьгораздо более чисто в Firefox и IE9.Это будет переменная adjust
, которую вы увидите в рабочем демо.
Пример кода ниже:
Разметка
<div class="imageContainer image1">
<img class="clip" src="http://www.mysite.com/images/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 для этого вида)анимации).Обратите внимание на пару моментов:
- Изображение должно быть внутри контейнера, чтобы мы могли обрезать его центр, а не его верхний левый угол.
- Граница -Атрибут radius не будет обрезать дочерние изображения внутри контейнера.По этой причине изображение должно стать атрибутом background-image контейнера.
- jQuery в настоящее время неправильно анимирует border-radius.Вы можете либо заменить текущую функциональность анимации 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(http://www.mysite.com/images/myFirstImage.png);
}
div.image2
{
background-image: url(http://www.mysite.com/images/mySecondImage.png);
}
The Script
// 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
}
});
Опять демо находится здесь.