Zephyrnet Logosu

3D'de bir CSS Slinky mi? Meydan okuma kabul edildi!

Tarih:

Braydon Coyer son zamanlarda aylık başlattı CSS sanat mücadelesi. Aslında kitabımın bir kopyasını bağışlama konusunda bana ulaşmıştı. Nesneleri CSS ile Taşı meydan okumanın galibi için bir ödül olarak kullanmak - ki bunu yapmaktan çok mutlu oldum!

İlk ayın mücadelesi? bahar. Ve meydan okuma için ne yapacağını düşünürken, hemen Slinkys aklıma geldi. Slinkys'i biliyorsun, değil mi? Merdivenleri indirdiğiniz o klasik oyuncak, kendi ivmesiyle hareket ediyor.

sinsi sinsi

CSS'de bunun gibi merdivenlerden inen bir Slinky oluşturabilir miyiz? Bu tam olarak sevdiğim türden bir meydan okuma, bu yüzden bu makalede birlikte üstesinden gelebileceğimizi düşündüm. Yuvarlanmaya hazır mısınız? (Pun amaçlı.)

Slinky HTML'yi ayarlama

Bunu esnek hale getirelim. (Punto amaçlanmamıştır.) Bununla demek istediğim, Slinky'nin davranışını CSS özel özellikleri aracılığıyla kontrol edebilmek ve bize gerektiğinde değerleri değiş tokuş etme esnekliği vermek istiyoruz.

Kısa olması için Pug ile yazılmış sahneyi şu şekilde kuruyorum:

- const RING_COUNT = 10;
.container
  .scene
    .plane(style=`--ring-count: ${RING_COUNT}`)
      - let rings = 0;
      while rings < RING_COUNT
        .ring(style=`--index: ${rings};`)
        - rings++;

Bu satır içi özel özellikler, çalma sayısını güncellememiz için kolay bir yoldur ve bu zorluğun derinliklerine indikçe kullanışlı olacaktır. Yukarıdaki kod bize 10 görünen HTML ile halkalar Böyle bir şey derlendiğinde:

<div class="container">
  <div class="scene">
    <div class="plane" style="--ring-count: 10">
      <div class="ring" style="--index: 0;"></div>
      <div class="ring" style="--index: 1;"></div>
      <div class="ring" style="--index: 2;"></div>
      <div class="ring" style="--index: 3;"></div>
      <div class="ring" style="--index: 4;"></div>
      <div class="ring" style="--index: 5;"></div>
      <div class="ring" style="--index: 6;"></div>
      <div class="ring" style="--index: 7;"></div>
      <div class="ring" style="--index: 8;"></div>
      <div class="ring" style="--index: 9;"></div>
    </div>
  </div>
</div>

İlk Slinky CSS

Bazı stillere ihtiyacımız olacak! İstediğimiz bir üç boyutlu sahne. Daha sonra yapmak isteyebileceğimiz bazı şeylere dikkat ediyorum, bu yüzden fazladan bir sarmalayıcı bileşenine sahip olmanın ardındaki düşünce bu. .scene sınıf.

“Sonsuz-slinky” sahnemiz için bazı özellikler tanımlayarak başlayalım:

:root {
  --border-width: 1.2vmin;
  --depth: 20vmin;
  --stack-height: 6vmin;
  --scene-size: 20vmin;
  --ring-size: calc(var(--scene-size) * 0.6);
  --plane: radial-gradient(rgb(0 0 0 / 0.1) 50%, transparent 65%);
  --ring-shadow: rgb(0 0 0 / 0.5);
  --hue-one: 320;
  --hue-two: 210;
  --blur: 10px;
  --speed: 1.2s;
  --bg: #fafafa;
  --ring-filter: brightness(1) drop-shadow(0 0 0 var(--accent));
}

Bu özellikler, Slinky'mizin ve sahnenin özelliklerini tanımlar. 3D CSS sahnelerinin çoğuyla, transform-style yönüyle:

* {
  box-sizing: border-box;
  transform-style: preserve-3d;
}

Şimdi bizim için stillere ihtiyacımız var .scene. İşin püf noktası tercüme etmektir. .plane bu yüzden CSS Slinky'miz bir kat merdivenden sonsuza kadar iniyor gibi görünüyor. İşleri tam olarak istediğim gibi elde etmek için biraz oynamam gerekti, o yüzden şimdilik sihirli sayıya katlanın, çünkü daha sonra anlam ifade edecekler.

.container {
  /* Define the scene's dimensions */
  height: var(--scene-size);
  width: var(--scene-size);
  /* Add depth to the scene */
  transform:
    translate3d(0, 0, 100vmin)
    rotateX(-24deg) rotateY(32deg)
    rotateX(90deg)
    translateZ(calc((var(--depth) + var(--stack-height)) * -1))
    rotate(0deg);
}
.scene,
.plane {
  /* Ensure our container take up the full .container */
  height: 100%;
  width: 100%;
  position: relative;
}
.scene {
  /* Color is arbitrary */
  background: rgb(162 25 230 / 0.25);
}
.plane {
  /* Color is arbitrary */
  background: rgb(25 161 230 / 0.25);
  /* Overrides the previous selector */
  transform: translateZ(var(--depth));
}

Burada oldukça fazla şey oluyor .container dönüşüm. özellikle:

  • translate3d(0, 0, 100vmin): Bu .container ilerler ve 3D çalışmamızın vücut tarafından kesilmesini engeller. kullanmıyoruz perspective bu seviyede, böylece ondan kurtulabiliriz.
  • rotateX(-24deg) rotateY(32deg): Bu, sahneyi tercihlerimize göre döndürür.
  • rotateX(90deg): Bu döndürür .container düzleştiren çeyrek tur .scene ve .plane Varsayılan olarak, Aksi takdirde, iki katman bir 3B küpün üstü ve altı gibi görünür.
  • translate3d(0, 0, calc((var(--depth) + var(--stack-height)) * -1)): Bunu sahneyi hareket ettirmek ve y ekseninde (aslında z ekseninde) ortalamak için kullanabiliriz. Bu tasarımcının gözünde. Burada, kullandığımız --depth ve --stack-height şeyleri merkeze almak.
  • rotate(0deg): Şu anda kullanımda olmasa da, sahneyi döndürmek veya sahnenin dönüşünü daha sonra canlandırmak isteyebiliriz.

ile neler olduğunu görselleştirmek için .container, bu demoyu kontrol edin ve görmek için herhangi bir yere dokunun. transform uygulandı (üzgünüz, yalnızca Chromium. 😭):

Artık stil sahibi bir sahnemiz var! 💪

Slinky'nin yüzüklerini şekillendirmek

Bu CSS özel özelliklerinin rollerini oynayacağı yer burasıdır. Satır içi özelliklere sahibiz --index ve --ring-count bizim HTML'mizden. Ayrıca, CSS'de daha önce gördüğümüz önceden tanımlanmış özelliklere de sahibiz. :root.

Satır içi özellikler, her bir halkanın konumlandırılmasında rol oynayacaktır:

.ring {
  --origin-z:
    calc(
      var(--stack-height) - (var(--stack-height) / var(--ring-count))
      * var(--index)
    );
  --hue: var(--hue-one);
  --accent: hsl(var(--hue) 100% 55%);
  height: var(--ring-size);
  width: var(--ring-size);
  border-radius: 50%;
  border: var(--border-width) solid var(--accent);
  position: absolute;
  top: 50%;
  left: 50%;
  transform-origin: calc(100% + (var(--scene-size) * 0.2)) 50%;
  transform:
    translate3d(-50%, -50%, var(--origin-z))
    translateZ(0)
    rotateY(0deg);
}
.ring:nth-of-type(odd) {
  --hue: var(--hue-two);
}

nasıl hesapladığımıza dikkat edin. --origin-z değerin yanı sıra her bir halkayı nasıl konumlandırdığımızı transform Emlak. Bu, her bir halkayı konumlandırdıktan sonra gelir. position: absolute .

Bu son kural setinde her bir halkanın rengini nasıl değiştirdiğimizi de belirtmekte fayda var. Bunu ilk uyguladığımda, halkaların tonlardan geçtiği bir gökkuşağı sinsi oluşturmak istedim. Ancak bu, etkiye biraz karmaşıklık katar.

Şimdi yükselttiğimizde bazı yüzüklerimiz var .plane:

Slinky halkalarını dönüştürmek

İşleri hareketlendirmenin zamanı geldi! belirlediğimizi fark etmiş olabilirsiniz. transform-origin her birinde .ring bunun gibi:

.ring {
  transform-origin: calc(100% + (var(--scene-size) * 0.2)) 50%;
}

Bu, .scene boy. O 0.2 değer, kalan kullanılabilir boyutun yarısıdır. .scene sonra .ring konumlanmıştır.

Bunu kesinlikle biraz toparlayabiliriz!

:root {
  --ring-percentage: 0.6;
  --ring-size: calc(var(--scene-size) * var(--ring-percentage));
  --ring-transform:
    calc(
      100%
      + (var(--scene-size) * ((1 - var(--ring-percentage)) * 0.5))
    ) 50%;
}

.ring {
  transform-origin: var(--ring-transform);
}

Neden bu transform-origin? Yüzüğün merkezden uzaklaşıyormuş gibi görünmesine ihtiyacımız var. ile oynamak transform bireysel bir yüzüğün çalışması, transform başvurmak istiyoruz. Halka çevirmeyi görmek için bu demodaki kaydırıcıyı hareket ettirin:

Tüm halkaları geri ekleyin ve tüm yığını çevirebiliriz!

Hmm, ama bir sonraki basamağa düşmüyorlar. Her halkayı doğru konuma nasıl düşürebiliriz?

Eh, hesapladık --origin-z, öyleyse hesaplayalım --destination-z yani halkalar gibi derinlik değişir transform. Yığının üstünde bir halkamız varsa, düştükten sonra alttan sarılmalıdır. Her halka için bir hedef kapsamı belirlemek için özel özelliklerimizi kullanabiliriz:

ring {
  --destination-z: calc(
    (
      (var(--depth) + var(--origin-z))
      - (var(--stack-height) - var(--origin-z))
    ) * -1
  );
  transform-origin: var(--ring-transform);
  transform:
    translate3d(-50%, -50%, var(--origin-z))
    translateZ(calc(var(--destination-z) * var(--flipped, 0)))
    rotateY(calc(var(--flipped, 0) * 180deg));
}

Şimdi yığını hareket ettirmeyi deneyin! oraya geliyoruz. 🙌

Halkaları canlandırmak

Yüzüğümüzün dönmesini ve sonra düşmesini istiyoruz. İlk deneme şöyle görünebilir:

.ring {
  animation-name: slink;
  animation-duration: 2s;
  animation-fill-mode: both;
  animation-iteration-count: infinite;
}

@keyframes slink {
  0%, 5% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(0)
      rotateY(0deg);
  }
  25% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(0)
      rotateY(180deg);
  }
  45%, 100% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(var(--destination-z))
      rotateY(180deg);
  }
}

Offf, bu hiç doğru değil!

Ama bu sadece kullanmadığımız için animation-delay. Bütün yüzükler, um, sinsi sinsi aynı zamanda. bir tanıtalım animation-delay göre --index yüzüğün arka arkaya kayması için.

.ring {
  animation-delay: calc(var(--index) * 0.1s);
}

Tamam, bu gerçekten "daha iyi". Ama zamanlama hala kapalı. Bununla birlikte, daha fazla göze çarpan şey, eksikliktir. animation-delay. Yalnızca ilk animasyon yinelemesinde uygulanır. Ondan sonra etkiyi kaybederiz.

Bu noktada halkaları renk tonu çarkında ilerleyecek şekilde renklendirelim. Bu, neler olup bittiğini görmeyi kolaylaştıracak.

.ring {
  --hue: calc((360 / var(--ring-count)) * var(--index));
}

Bu daha iyi! ✨

Soruna geri dön. Her yinelemeye uygulanacak bir gecikme belirleyemediğimiz için, istediğimiz efekti de elde edemiyoruz. Slinky'miz için, eğer tutarlı bir animation-delay, istediğimiz etkiyi elde edebiliriz. Kapsamlı özel özelliklerimize güvenirken bir ana kare kullanabiliriz. Hatta bir animation-repeat-delay ilginç bir ek olabilir.

Bu işlevsellik, JavaScript animasyon çözümlerinde mevcuttur. Örneğin GreenSock, bir delay ve repeatDelay.

Ancak, Slinky örneğimiz bu sorunu göstermenin en kolay yolu değil. Bunu temel bir örneğe ayıralım. İki kutu düşünün. Ve onların eğirmeyi değiştirmelerini istiyorsunuz.

Bunu CSS ile ve "hile" olmadan nasıl yaparız? Bir fikir, kutulardan birine gecikme eklemektir:

.box {
  animation: spin 1s var(--delay, 0s) infinite;
}
.box:nth-of-type(2) {
  --delay: 1s;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

Ancak bu işe yaramayacak çünkü kırmızı kutu dönmeye devam edecek. Başlangıcından sonra mavi olan da öyle olacak animation-delay.

Gibi bir şeyle YeşilÇorap, yine de istediğimiz etkiyi nispeten kolaylıkla elde edebiliriz:

import gsap from 'https://cdn.skypack.dev/gsap'

gsap.to('.box', {
  rotate: 360,
  /**
   * A function based value, means that the first box has a delay of 0 and
   * the second has a delay of 1
  */
  delay: (index) > index,
  repeatDelay: 1,
  repeat: -1,
  ease: 'power1.inOut',
})

Ve işte burada!

Ancak bunu JavaScript olmadan nasıl yapabiliriz?

Şey, bizim "hacklememiz" gerekiyor. @keyframes ve tamamen ortadan kaldırmak animation-delay. Bunun yerine, @keyframes boş alan ile. Bu, çeşitli tuhaflıklarla birlikte gelir, ancak önce devam edelim ve yeni bir ana kare oluşturalım. Bu, öğeyi iki kez tamamen döndürür:

@keyframes spin {
  50%, 100% {
    transform: rotate(360deg);
  }
}

Ana kareyi yarıya indirmiş gibiyiz. Ve şimdi ikiye katlamamız gerekecek animation-duration aynı hızı elde etmek için. Kullanmadan animation-delay, ayarlamayı deneyebiliriz animation-direction: reverse ikinci kutuda:

.box {
  animation: spin 2s infinite;
}

.box:nth-of-type(2) {
  animation-direction: reverse;
}

Neredeyse.

Rotasyon yanlış yönde. Bir sarmalayıcı eleman kullanabilir ve bunu döndürebiliriz, ancak dengelenecek daha çok şey olduğu için bu zor olabilir. Diğer yaklaşım, bir yerine iki ana kare oluşturmaktır:

@keyframes box-one {
  50%, 100% {
    transform: rotate(360deg);
  }
}
@keyframes box-two {
  0%, 50% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

Ve işte elimizde:

Tekrarlama gecikmesini şunun gibi bir şeyle belirtmenin bir yolu olsaydı, bu çok daha kolay olurdu:

/* Hypothetical! */
animation: spin 1s 0s 1s infinite;

Veya tekrarlanan gecikme ilk gecikmeyle eşleşirse, muhtemelen bunun için bir birleştiricimiz olabilir:

/* Hypothetical! */
animation: spin 1s 1s+ infinite;

Kesinlikle ilginç bir ekleme yapacaktı!

Yani tüm bu halkalar için anahtar karelere mi ihtiyacımız var?

Evet, yani tutarlı bir gecikme istiyorsak. Bunu da animasyon penceresi olarak kullanacağımız şeye göre yapmamız gerekiyor. Ana kareler tekrarlanmadan önce tüm halkaların "kayması" ve oturması gerekir.

Bunu elle yazmak korkunç olurdu. Ama bu yüzden CSS ön işlemcilerimiz var, değil mi? En azından web'de döngüler ve bazı ekstra özel özellik özellikleri elde edene kadar. 😉

Bugünün tercih edilen silahı Stylus olacak. Bu benim favori CSS ön işlemcim ve bir süredir öyle. Alışkanlık, Sass'a taşınmadığım anlamına gelir. Artı, Stylus'un gerekli gramer ve esneklikten yoksun olmasını seviyorum.

İyi ki bunu sadece bir kez yazmamız gerekiyor:

// STYLUS GENERATED KEYFRAMES BE HERE...
$ring-count = 10
$animation-window = 50
$animation-step = $animation-window / $ring-count

for $ring in (0..$ring-count)
  // Generate a set of keyframes based on the ring index
  // index is the ring
  $start = $animation-step * ($ring + 1)
  @keyframes slink-{$ring} {
    // In here is where we need to generate the keyframe steps based on ring count and window.
    0%, {$start * 1%} {
      transform
        translate3d(-50%, -50%, var(--origin-z))
        translateZ(0)
        rotateY(0deg)
    }
    // Flip without falling
    {($start + ($animation-window * 0.75)) * 1%} {
      transform
        translate3d(-50%, -50%, var(--origin-z))
        translateZ(0)
        rotateY(180deg)
    }
    // Fall until the cut-off point
    {($start + $animation-window) * 1%}, 100% {
      transform
        translate3d(-50%, -50%, var(--origin-z))
        translateZ(var(--destination-z))
        rotateY(180deg)
    }
  }

İşte bu değişkenlerin anlamı:

  • $ring-count: Sinsimizdeki yüzük sayısı.
  • $animation-window: Bu, içeri girebildiğimiz ana karenin yüzdesidir. Örneğimizde, üzerinden geçmek istediğimizi söylüyoruz. 50% anahtar kareler. Kalan 50% gecikmelere alışmak gerekir.
  • $animation-step: Bu, her halka için hesaplanan kademedir. Bunu, her halka için benzersiz ana kare yüzdelerini hesaplamak için kullanabiliriz.

En azından ilk birkaç yineleme için CSS'yi şu şekilde derler:

Tam kodu görüntüle
@keyframes slink-0 {
  0%, 4.5% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(0)
      rotateY(0deg);
  }
  38.25% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(0)
      rotateY(180deg);
  }
  49.5%, 100% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(var(--destination-z))
      rotateY(180deg);
  }
}
@keyframes slink-1 {
  0%, 9% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(0)
      rotateY(0deg);
  }
  42.75% {
    transform:
      translate3d(-50%, -50%, var(--origin-z))
      translateZ(0)
      rotateY(180deg);
  }
  54%, 100% {
    transform:
       translate3d(-50%, -50%, var(--origin-z))
       translateZ(var(--destination-z))
       rotateY(180deg);
  }
}

Yapılacak son şey, her bir anahtar kare setini her bir halkaya uygulamaktır. İstersek, her ikisini de tanımlayacak şekilde güncelleyerek, işaretlememizi kullanarak bunu yapabiliriz. --index ve a --name:

- const RING_COUNT = 10;
.container
  .scene
    .plane(style=`--ring-count: ${RING_COUNT}`)
      - let rings = 0;
      while rings < RING_COUNT
        .ring(style=`--index: ${rings}; --name: slink-${rings};`)
        - rings++;

Hangi derlendiğinde bize bunu verir:

<div class="container">
  <div class="scene">
    <div class="plane" style="--ring-count: 10">
      <div class="ring" style="--index: 0; --name: slink-0;"></div>
      <div class="ring" style="--index: 1; --name: slink-1;"></div>
      <div class="ring" style="--index: 2; --name: slink-2;"></div>
      <div class="ring" style="--index: 3; --name: slink-3;"></div>
      <div class="ring" style="--index: 4; --name: slink-4;"></div>
      <div class="ring" style="--index: 5; --name: slink-5;"></div>
      <div class="ring" style="--index: 6; --name: slink-6;"></div>
      <div class="ring" style="--index: 7; --name: slink-7;"></div>
      <div class="ring" style="--index: 8; --name: slink-8;"></div>
      <div class="ring" style="--index: 9; --name: slink-9;"></div>
    </div>
  </div>
</div>

Ve sonra stilimiz buna göre güncellenebilir:

.ring {
  animation: var(--name) var(--speed) both infinite cubic-bezier(0.25, 0, 1, 1);
}

Zamanlama herşeydir. Bu yüzden varsayılanı bıraktık animation-timing-function ve biz bir kullanıyoruz cubic-bezier. Biz de kullanıyoruz --speed başlangıçta tanımladığımız özel özellik.

Ah evet. Şimdi sinsi bir CSS Slinky'miz var! Koddaki bazı değişkenlerle oynayın ve ne gibi farklı davranışlar sergileyebileceğinizi görün.

Sonsuz bir animasyon oluşturma

Artık işin en zor kısmı bizde olduğuna göre, bunu animasyonun sonsuz tekrar ettiği yere getirebiliriz. Bunu yapmak için, sahneyi Sinsi sinsi sinsi olarak çevireceğiz, böylece orijinal konumuna geri dönüyormuş gibi görünecek.

.scene {
  animation: step-up var(--speed) infinite linear both;
}

@keyframes step-up {
  to {
    transform: translate3d(-100%, 0, var(--depth));
  }
}

Vay, bu çok az çaba gerektirdi!

Platform renklerini şuradan kaldırabiliriz: .scene ve .plane animasyonun çok sarsıcı olmasını önlemek için:

Neredeyse bitti! Ele alınması gereken son şey, halka yığınının tekrar kaymadan önce dönmesidir. Daha önce renk kullanımının kullanışlı olacağından bahsetmiştik. Çalma sayısını, örneğin, tek bir sayıyla değiştirin 11ve halka rengini değiştirmeye geri dönün:

Boom! Çalışan bir CSS kurnazlığımız var! Ayrıca yapılandırılabilir!

eğlenceli varyasyonlar

"Flip flop" efektine ne dersiniz? Bununla, Slink'in farklı yollardan sinsi sinsi dolaşmasını sağlamaktan bahsediyorum. Sahneye fazladan bir sarmalayıcı öğe eklersek, sahneyi şu şekilde döndürebiliriz: 180deg her slinkte.

- const RING_COUNT = 11;
.container
  .flipper
    .scene
      .plane(style=`--ring-count: ${RING_COUNT}`)
        - let rings = 0;
        while rings < RING_COUNT
          .ring(style=`--index: ${rings}; --name: slink-${rings};`)
          - rings++;

Animasyon söz konusu olduğunda, şunu kullanabiliriz: steps() zamanlama işlevi ve iki kez kullanın --speed:

.flipper {
  animation: flip-flop calc(var(--speed) * 2) infinite steps(1);
  height: 100%;
  width: 100%;
}

@keyframes flip-flop {
  0% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(180deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

Son olarak, ama en az değil, yolu değiştirelim .scene elementler step-up animasyon çalışmaları. Artık x ekseni üzerinde hareket etmesine gerek yok.

@keyframes step-up {
  0% {
    transform: translate3d(-50%, 0, 0);
  }
  100% {
    transform: translate3d(-50%, 0, var(--depth));
  }
}

Not animation-timing-function kullandığımız. Bu kullanımı steps(1) mümkün kılan şeydir.

Başka bir eğlenceli kullanım istiyorsanız steps(), Bu kontrol #SpeedyCSSTipucu!

Ekstra bir dokunuş için tüm sahneyi yavaş döndürebiliriz:

.container {
  animation: rotate calc(var(--speed) * 40) infinite linear;
}
@keyframes rotate {
  to {
    transform:
      translate3d(0, 0, 100vmin)
      rotateX(-24deg)
      rotateY(-32deg)
      rotateX(90deg)
      translateZ(calc((var(--depth) + var(--stack-height)) * -1))
      rotate(360deg);
  }
}

Beğendim! Tabii ki, stil özneldir… bu yüzden, Slinky'nizi yapılandırmak için kullanabileceğiniz küçük bir uygulama yaptım:

Ve işte gölgeler ve temalarla biraz daha ileri götürdüğüm “Original” ve “Flip-Flop” versiyonları.

Son demolar

Bu kadar!

Bu, hem 3D hem de yapılandırılabilir saf bir CSS Slinky yapmanın en az bir yolu. Elbette, her gün böyle bir şeye ulaşamayabilirsiniz, ancak ilginç CSS animasyon tekniklerini gündeme getiriyor. sahip olup olmadığı sorusunu da gündeme getirmektedir. animation-repeat-delay CSS'deki özellik yararlı olacaktır. Ne düşünüyorsun? Bunun için bazı iyi kullanım durumları olacağını düşünüyor musunuz? bilmek isterim.

Kodla oynadığınızdan emin olun - hepsi şurada mevcuttur: bu CodePen Koleksiyonu!

spot_img

En Son İstihbarat

spot_img

Bizimle sohbet

Merhaba! Size nasıl yardım edebilirim?