Как сделать анимацию, которая создает окончательное изображение из кусочков одинакового размера, которые собираются со всех сторон? - PullRequest
2 голосов
/ 30 марта 2020

Анимация похожа на переход одного слайда в PowerPoint. Я бы сделал это с помощью преобразований skew и translate (из случайного положения на полях страницы). Я начал использовать CSS спрайтов и CSS сетки. Первая проблема, с которой я сталкиваюсь, - это расстояние между элементами сетки, которое не объяснено в Chrome DevTools. Я в порядке с использованием anime.js или других библиотек.

Проблема ниже - это расстояние между частями, и они не показывают полные части изображения, которые необходимы. Исходное изображение здесь .

/* The photo resolution: 2400 x 1600 */
.slideshow {
    display: grid;
    grid-template-rows: auto auto auto;
    grid-template-columns: auto auto auto;
}

.tile {
    background-image: url(https://unsplash.com/photos/hzgs56Ze49s/download?force=true&w=2400);
    /* width: 800px;
    height: 533px; */
    width: calc(800px / 2);
    height: calc(533px / 2);
    transform: scale(0.5, 0.5);
}
 
.piece1 {
    background-position: 0 0;
    grid-row: 1/1;
    grid-column: 1/1;
}
.piece2 {
    background-position: -800px 0;
    grid-row: 1/1;
    grid-column: 2/2;
}
.piece3 {
    background-position: -1600px 0;
    grid-row: 1/1;
    grid-column: 3/3;
}

.piece4 {
    background-position: 0 -533px;
    grid-row: 2/2;
    grid-column: 1/1;
}
.piece5 {
    background-position: -800px -533px;
    grid-row: 2/2;
    grid-column: 2/2;
}
.piece6 {
    background-position: -1600px -533px;
    grid-row: 2/2;
    grid-column: 3/3;
}

.piece7 {
    background-position: 0 -1066px;
    grid-row: 3/3;
    grid-column: 1/1;
}
.piece8 {
    background-position: -800px -1066px;
    grid-row: 3/3;
    grid-column: 2/2;
}
.piece9 {
    background-position: -1600px -1066px;
    grid-row: 3/3;
    grid-column: 3/3;
}
<div class="slideshow">
  <div class="tile piece1"></div>
  <div class="tile piece2"></div>
  <div class="tile piece3"></div>

  <div class="tile piece4"></div>
  <div class="tile piece5"></div>
  <div class="tile piece6"></div>

  <div class="tile piece7"></div>
  <div class="tile piece8"></div>
  <div class="tile piece9"></div>
</div>

Я пока не уверен, сработает ли способ, которым я начал ходить.

Спасибо.

Ответы [ 2 ]

2 голосов
/ 30 марта 2020

Один из способов сделать это с несколькими изменениями:

1) background-position, должно быть "left top", "top", "right top", "left", "center", " справа »,« внизу слева »,« внизу в центре »и« внизу справа », чтобы разделить изображения на 9 частей.
https://www.w3schools.com/cssref/pr_background-position.asp

2) Поскольку размеры исходного изображения 2400 x 1600, установите «background-size» меньшим, а затем рассчитайте, используя cal c в соответствии с меньшими размерами, скажем:

width: calc(600px / 3);
height: calc(600px / 3);

3) Установите абсолютное положение плиток.

4) Назначьте абсолютные позиции каждой плитки, используя верхнюю и левую сторону.

5) Назначьте каждую плитку с уникальными идентификаторами.

6) Используйте setInterval javascript и оператор if else, чтобы изменить абсолютные позиции элементов, используя идентификатор каждого элемента, чтобы решить, как их верхний и левый атрибуты должны изменяться со временем.

7) В примере я использую кнопку «Click Me» для выполнения скрипта, но вы можете сделать это с помощью onload или, если хотите, вызвать функцию moveElements().

<style>
    /* The photo resolution: 2400 x 1600 */
.slideshow {
    display: grid;
    grid-template-rows: auto auto auto;
    grid-template-columns: auto auto auto;
}

.tile {
    background-image: url(https://unsplash.com/photos/hzgs56Ze49s/download?force=true&w=2400);
    background-size: 600px 600px;
    /* width: 800px;
    height: 533px; */
    width: calc(600px / 3);
    height: calc(600px / 3);
    transform: scale(0.5, 0.5);
    position:absolute;
}

.piece1 {
    background-position: left top;
    grid-row: 1/1;
    grid-column: 1/1;
    top:0;
    left:0;
}
.piece2 {
    background-position: top;
    grid-row: 1/1;
    grid-column: 2/2;
    top:0;
    left:250;
}
.piece3 {
    background-position: right top;
    grid-row: 1/1;
    grid-column: 3/3;
    top:0;
    left:500;
}

.piece4 {
    background-position: left;
    grid-row: 2/2;
    grid-column: 1/1;
    top:250;
    left:0;
}
.piece5 {
    background-position: center;
    grid-row: 2/2;
    grid-column: 2/2;
    top:250;
    left: 250;
}
.piece6 {
    background-position: right;
    grid-row: 2/2;
    grid-column: 3/3;
    top:250;
    left:500;
}

.piece7 {
    background-position: bottom left;
    grid-row: 3/3;
    grid-column: 1/1;
    top:500;
    left:0;
}
.piece8 {
    background-position: bottom center;
    grid-row: 3/3;
    grid-column: 2/2;
    top:500;
    left:250;
}
.piece9 {
    background-position: bottom right;
    grid-row: 3/3;
    grid-column: 3/3;
    top:500;
    left:500;
}
</style>
<p><button onclick="moveElements()">Click Me</button></p> 
<div class="slideshow">
  <div id="topleft" class="tile piece1"></div>
  <div id="top" class="tile piece2"></div>
  <div id="topright" class="tile piece3"></div>

  <div id="left" class="tile piece4"></div>
  <div id="center" class="tile piece5"></div>
  <div id="right" class="tile piece6"></div>

  <div id="bottomleft" class="tile piece7"></div>
  <div id="bottomcenter" class="tile piece8"></div>
  <div id="bottomright" class="tile piece9"></div>
</div>


<script>
function moveElements() {
  var elem1 = document.getElementById("topleft");   
  var pos1 = 0;
  var id1 = setInterval(frame1, 5);
  function frame1() {
    if (pos1 == 151) {
      clearInterval(id1);
    } else {
      pos1++; 
      elem1.style.top = pos1 + "px"; 
      elem1.style.left = pos1 + "px"; 
    }
  }

  var elem2 = document.getElementById("top");   
  var pos2 = 0;
  var id2 = setInterval(frame2, 5);
  function frame2() {
    if (pos2 == 151) {
      clearInterval(id2);
    } else {
      pos2++; 
      elem2.style.top = pos2 + "px"; 

    }
  }

  var elem3 = document.getElementById("topright");   
  var pos3t = 0;
  var pos3l = 500;
  var id3 = setInterval(frame3, 5);
  function frame3() {
    if (pos3t == 151) {
      clearInterval(id3);
    } else {
      pos3t++; 
      pos3l--;
      elem3.style.top = pos3t + "px"; 
      elem3.style.left = pos3l + "px"; 
    }
  }

  var elem4 = document.getElementById("left");   
  var pos4 = 0;
  var id4 = setInterval(frame4, 5);
  function frame4() {
    if (pos4 == 151) {
      clearInterval(id4);
    } else {
      pos4++; 
      elem4.style.left = pos4 + "px"; 
    }
  }

  // element5, the center tile stays still

  var elem6 = document.getElementById("right");   
  var pos6 = 500;
  var id6 = setInterval(frame6, 5);
  function frame6() {
    if (pos6 == 349) {
      clearInterval(id6);
    } else {
      pos6--; 
      elem6.style.left = pos6 + "px"; 
    }
  }

  var elem7 = document.getElementById("bottomleft");   
  var pos7t = 500;
  var pos7l = 0;
  var id7 = setInterval(frame7, 5);
  function frame7() {
    if (pos7t == 349) {
      clearInterval(id7);
    } else {
      pos7t--;
      pos7l++; 
      elem7.style.top = pos7t + "px"; 
      elem7.style.left = pos7l + "px"; 
    }
  }

  var elem8 = document.getElementById("bottomcenter");   
  var pos8 = 500;
  var id8 = setInterval(frame8, 5);
  function frame8() {
    if (pos8 == 349) {
      clearInterval(id8);
    } else {
      pos8--; 
      elem8.style.top = pos8 + "px"; 
    }
  }

  var elem9 = document.getElementById("bottomright");   
  var pos9 = 500;
  var id9 = setInterval(frame9, 5);
  function frame9() {
    if (pos9 == 349) {
      clearInterval(id9);
    } else {
      pos9--; 
      elem9.style.top = pos9 + "px"; 
      elem9.style.left = pos9 + "px"; 
    }
  }
}
</script>
1 голос
/ 30 марта 2020

Я бы рассмотрел все слои изображения друг над другом, используя position:absolute, и я буду полагаться на mask (или путь обрезки), чтобы показать только его часть. Тогда вы можете легко применить перевод.

Наведите, чтобы увидеть эффект:

.slideshow {
  width: 400px;
  height: 261px;
  margin:100px auto;
  position:relative;
  background-image: url(https://unsplash.com/photos/hzgs56Ze49s/download?force=true&w=2400);
  background-size: 0 0;
}

.tile {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-image: inherit;
  background-size: cover;
  -webkit-mask:linear-gradient(#fff,#fff) no-repeat;
  -webkit-mask-size:33.4% 33.4%;
  -webkit-mask-position:var(--p);
          mask:linear-gradient(#fff,#fff) no-repeat;
          mask-size:33.4% 33.4%;
          mask-position:var(--p);
   transition:0.5s;
}

.piece1 {--p:top    left;  --t:-10%, -10%;}
.piece2 {--p:center left;  --t:-10%,  0%;}
.piece3 {--p:bottom left;  --t:-10%,  10%;}

.piece4 {--p:top    center;--t: 0%,  -10%;}
.piece5 {--p:center center;--t: 0%,   0%;}
.piece6 {--p:bottom center;--t: 0%,   10%;}

.piece7 {--p:top    right; --t: 10%, -10%;}
.piece8 {--p:center right; --t: 10%,  0%;}
.piece9 {--p:bottom right; --t: 10%,  10%;}

.slideshow:hover .tile{
   transform:translate(var(--t));
}

body {
 background:#f2f2f2;
}
<div class="slideshow">
  <div class="tile piece1"></div>
  <div class="tile piece2"></div>
  <div class="tile piece3"></div>

  <div class="tile piece4"></div>
  <div class="tile piece5"></div>
  <div class="tile piece6"></div>

  <div class="tile piece7"></div>
  <div class="tile piece8"></div>
  <div class="tile piece9"></div>
</div>

Вы можете оптимизировать эффект масштаба, когда вам не нужно много кода, и вы можете повторно использовать mask-position с transform-origin

.slideshow {
  width: 400px;
  height: 261px;
  margin:50px auto;
  position:relative;
  background-image: url(https://unsplash.com/photos/hzgs56Ze49s/download?force=true&w=2400);
  background-size: 0 0;
  transition:0.5s;
}

.tile {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-image: inherit;
  background-size: cover;
  -webkit-mask:linear-gradient(#fff,#fff) no-repeat;
  -webkit-mask-size:33.4% 33.4%;
  -webkit-mask-position:var(--p);
          mask:linear-gradient(#fff,#fff) no-repeat;
          mask-size:33.4% 33.4%;
          mask-position:var(--p);
   transition:inherit;
   transform-origin:var(--p);
}

.piece1 {--p:top    left;}
.piece2 {--p:center left;}
.piece3 {--p:bottom left;}

.piece4 {--p:top    center;}
.piece5 {--p:center center;}
.piece6 {--p:bottom center;}

.piece7 {--p:top    right;}
.piece8 {--p:center right;}
.piece9 {--p:bottom right;}

.slideshow:hover .tile{
   transform:scale(0.8);
}

.slideshow:hover {
   transform:scale(1.25);
}

body {
 background:#f2f2f2;
}
<div class="slideshow">
  <div class="tile piece1"></div>
  <div class="tile piece2"></div>
  <div class="tile piece3"></div>

  <div class="tile piece4"></div>
  <div class="tile piece5"></div>
  <div class="tile piece6"></div>

  <div class="tile piece7"></div>
  <div class="tile piece8"></div>
  <div class="tile piece9"></div>
</div>

Вы можете легко масштабировать до 4x4 или любой сетки NxN:

.slideshow {
  --n:4;
  
  width: 400px;
  height: 261px;
  margin:100px auto;
  position:relative;
  background-image: url(https://unsplash.com/photos/hzgs56Ze49s/download?force=true&w=2400);
  background-size: 0 0;
   transition:0.5s;
}

.tile {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-image: inherit;
  background-size: cover;
  -webkit-mask:linear-gradient(#fff,#fff) no-repeat;
  -webkit-mask-size:calc(100%/var(--n) + 1px) calc(100%/var(--n) + 1px);
  -webkit-mask-position:var(--p);
          mask:linear-gradient(#fff,#fff) no-repeat;
          mask-size:calc(100%/var(--n) + 1px) calc(100%/var(--n) + 1px);
          mask-position:var(--p);
   transition:inherit;
   transform-origin:var(--p);
}

.tile:nth-child(1)  {--p:calc(0*100%/(var(--n) - 1)) calc(0*100%/(var(--n) - 1));}
.tile:nth-child(2)  {--p:calc(1*100%/(var(--n) - 1)) calc(0*100%/(var(--n) - 1));}
.tile:nth-child(3)  {--p:calc(2*100%/(var(--n) - 1)) calc(0*100%/(var(--n) - 1));}
.tile:nth-child(4)  {--p:calc(3*100%/(var(--n) - 1)) calc(0*100%/(var(--n) - 1));}

.tile:nth-child(5)  {--p:calc(0*100%/(var(--n) - 1)) calc(1*100%/(var(--n) - 1));}
.tile:nth-child(6)  {--p:calc(1*100%/(var(--n) - 1)) calc(1*100%/(var(--n) - 1));}
.tile:nth-child(7)  {--p:calc(2*100%/(var(--n) - 1)) calc(1*100%/(var(--n) - 1));}
.tile:nth-child(8)  {--p:calc(3*100%/(var(--n) - 1)) calc(1*100%/(var(--n) - 1));}

.tile:nth-child(9)  {--p:calc(0*100%/(var(--n) - 1)) calc(2*100%/(var(--n) - 1));}
.tile:nth-child(10) {--p:calc(1*100%/(var(--n) - 1)) calc(2*100%/(var(--n) - 1));}
.tile:nth-child(11) {--p:calc(2*100%/(var(--n) - 1)) calc(2*100%/(var(--n) - 1));}
.tile:nth-child(12) {--p:calc(3*100%/(var(--n) - 1)) calc(2*100%/(var(--n) - 1));}

.tile:nth-child(13) {--p:calc(0*100%/(var(--n) - 1)) calc(3*100%/(var(--n) - 1));}
.tile:nth-child(14) {--p:calc(1*100%/(var(--n) - 1)) calc(3*100%/(var(--n) - 1));}
.tile:nth-child(15) {--p:calc(2*100%/(var(--n) - 1)) calc(3*100%/(var(--n) - 1));}
.tile:nth-child(16) {--p:calc(3*100%/(var(--n) - 1)) calc(3*100%/(var(--n) - 1));}


.slideshow:hover > *{
   transform:scale(0.8);
}
.slideshow:hover {
   transform:scale(1.25);
}

body {
 background:#f2f2f2;
}
<div class="slideshow">
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>

  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>

  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
</div>
...