крутящийся граница с помощью html и css

Как мне сделать такую анимацию?

У меня получилось вот такая хрень, в какую сторону сне идть?

*{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            background-color: royalblue;
        }

        .block{
            width: 800px;
            height: 400px;
            margin: 200px auto 0;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0px 0px 15px 1px rgba(0, 0, 0, .75);
            -moz-box-shadow: 0px 0px 15px 1px rgba(0, 0, 0, .75);
            -webkit-box-shadow: 0px 0px 15px 1px rgba(0, 0, 0, .75);
        }

        .centerBlock{
            width: 410px;
            height: 110px;
            border-radius: 100px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;    
            background-image: linear-gradient(to right, white, grey, grey, black, black);
            z-index: 10;
        }

        .back{
            width: 400px;
            height: 100px;
            border-radius: 100px;
            background-image: linear-gradient(to right, white, grey, black, black);
            z-index: 15;
        }

        .bl{
            position: absolute;
            width: 110px;
            height: 110px;
        }

        .left{
            transform: translateY(-5px) translateX(-5px);
            background-color: black;
            border: 5px solid white;
            border-radius: 50%;
            z-index: 2;
        }

        .right{
            transform: translateX(155px);
            background-color: black;
            z-index: 2;
            width: 110px;
        height: 110px;
        border-radius: 110px;
          border: 5px solid black;
          border-left: 5px solid white;
          animation: rotate 5s infinite linear;
        }

        .lineTop{
            position: absolute;
            height: 5px;
            width: 100px;
            transform: translateY(-52.5px) translateX(-100px);
            background-color: white;
            z-index: 10;
            border-radius: 25px;
            animation: anim_top 5s infinite linear;
        }

        .lineBottom{
            position: absolute;
            height: 5px;
            width: 0;
            transform: translateY(52px) translateX(150px);
            background-color: white;
            z-index: 10;
            border-radius: 25px;
            animation: anim_bot 5s infinite linear;
        }

        @keyframes rotate {
            0%,30%{
                transform: translateX(155px);
            }

            55%,100%{
                transform: translateX(155px) rotate(360deg);
            }
        }

        @keyframes anim_top {
            0%{
                transform: translateY(-52px) translateX(-100px);
            }
            35%{
                transform: translateY(-52px) translateX(120px);
                width: 100px;
            }
            45%,100%{
                transform: translateY(-52px) translateX(155px);
                width: 0;
            }
        }

        @keyframes anim_bot {
            45%{
                width: 0;
                transform: translateY(52px) translateX(150px);
            }
            50%{
                width: 100px;
                transform: translateY(52px) translateX(110px);
            }
            80%{
                transform: translateY(52px) translateX(-110px);
                width: 100px;
            }
            90%,100%{
                transform: translateY(52px) translateX(-155px);
                width: 0;
            }
        }
<div class="block">
        <div class="centerBlock">
            <div class="lineTop"></div>
            <div class="lineBottom"></div>
            <div class="bl right">
                <div class="border"></div>
            </div>
            <div class="back">
                <div class="bl left"></div>
            </div>
        </div>
    </div>


Ответы (2 шт):

Автор решения: Alexandr_TT

Как мне сделать такую анимацию?

Короткий ответ

  • Нарисовать в векторном редакторе необходимую фигуру
  • Добавить атрибуты представления SVG fill="url(#grad)" stroke="white" stroke-width="10"
  • Разбить линию на три сектора с помощью stroke-dasharray
  • Анимировать вращение секторов с помощью stroke-dashoffset

Подробно, по шагам:

Шаг 1. Рисуем фигуру

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

1.1 Полуокружность создаем с помощью команды Дуга эллипса – Elliptical Arc (A,a)

Из нижней точки 150,250 c радиусом A50 в верхнюю точку 150,150

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
  <path  fill="none" stroke="black" stroke-width="10"
     d="M 150,250 A50,50 0 0 1 150,150" />
</svg>

1.2 Добавляем горизонтальную линию h500

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
  <path  fill="none" stroke="black" stroke-width="10"
     d="M 150,250 A50,50 0 0 1 150,150 h500" />
</svg>

1.3 Добавляем вторую полуокружность A50,50 0 0 1 650,250
до нижней точки с координатами 650,250

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
  <path  fill="none" stroke="black" stroke-width="10"
     d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250" />
</svg>

1.4 Добавляем вторую (нижнюю) горизонтальную линию h -500

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
      <path  fill="none" stroke="black" stroke-width="10"
         d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" />
    </svg>

Фигура готова, мы смогли нарисовать её без векторного редактора!

Шаг 2. Разбить линию на три сектора с помощью stroke-dasharray

С помощью метода getTotalLength() находим общую длину линии -- 1314px

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
      <path  id="path" fill="none" stroke="black" stroke-width="10"
         d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" />
    </svg>

 <script>
  let total = Math.round(path.getTotalLength()); 
   console.log(total + ` px`); 
</script>

Длина каждого сектора 1314 / 3 = 438px

Добавляем в stroke-dasharray="280,158", где первая цифра длина черты, вторая длина пробела.
В сумме должно быть: 438px

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
      <path  id="path" fill="none" stroke="black" stroke-width="10" stroke-dasharray="280,158" stroke-dashoffset="1314" stroke-lineCap="round"
         d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" />
    </svg>

Шаг 3. Анимаруем вращение линии

<animate attributeName="stroke-dashoffset" values="1314;0" dur="10s"
  fill="freeze" repeatCount="indefinite" />

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="800" height="400" viewBox="0 0 800 400" style="border:1px solid gray;" > 
      <path  id="path" fill="none" stroke="black" stroke-width="10" stroke-dasharray="280,158"      stroke-dashoffset="1314" stroke-lineCap="round"
         d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" >
           <animate attributeName="stroke-dashoffset" values="1314;0" dur="10s" fill="freeze" repeatCount="indefinite" />
     </path>     
    </svg>

Шаг 4. Оформление графических деталей

  • Добавляем левую, белую окружность

<circle cx="150" cy="200" r="50" fill="#151515" stroke="white" stroke-width="10" />

  • Добавляем градиенты фона и линий

Смотрите комментарии в коде.

.container {
width:75vw;
height:auto;
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"   viewBox="0 0 800 400" style="border:1px solid gray;" > 
 <defs>
   <linearGradient id="grad1" x2="1" y2="0">
      <stop offset="0.1" stop-color="white" stop-opacity="0.8"/>
      <stop offset="0.8" stop-color="black" />
      <stop offset="1" stop-color="transparent"/>
    </linearGradient> 
      <linearGradient id="grad2" x2="1" y2="0">
      <stop offset="0.25" stop-color="white"  />
      <stop offset="0.95" stop-color="black"  />
      <stop offset="1" stop-color="transparent" />
      
    </linearGradient>
</defs> 
    <rect width="100%" height="100%" fill="#151515" />
    
    <path fill="url(#grad1)" stroke="none" stroke-width="10"   
     d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" />
      <!-- Трасса движения -->
    <path fill="none" stroke="url(#grad2)" stroke-width="10" stroke-lineCap="round"  stroke-dasharray="657" stroke-dashoffset="250" 
     d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" />
            
    <!-- Анимация 3-х секторов  -->  
      <path  fill="none" stroke="white" stroke-width="10" stroke-lineCap="round" stroke-dasharray="239,199" stroke-dashoffset="1314" d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" >
           <!-- Анимация вращения белой линии -->
         <animate attributeName="stroke-dashoffset" values="1314;0" dur="10s" fill="freeze" repeatCount="indefinite" />
       </path>  
          <!-- Окружность слева     -->
    <circle cx="150" cy="200" r="50" fill="#151515" stroke="white" stroke-width="10" />     
 </svg>
</div> 

→ Ссылка
Автор решения: Alexandr_TT

На основе первого ответа, с минимальными изменениями, можно сделать, например, цепную, зубчатую передачу.

  • Делим линию на равные отрезки с помощью stroke-dasharray="15.7, 15.7"

Запуск анимации по клику:

.container {
width:75vw;
height:auto;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"   viewBox="0 0 800 400" style="border:1px solid gray;" > 
 
    <rect width="100%" height="100%" fill="#151515" />
               <!-- Цепь между двумя шестеренками -->
<path  fill="none" stroke="grey" stroke-width="10"
  stroke-dasharray="15.7, 15.7"  d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" > 
  <animate attributeName="stroke-dashoffset" values="1314;0" begin="svg1.click" dur="10s" fill="freeze" repeatCount="indefinite" />
</path>     
 </svg>
</div>

  • Точно также, с помощью stoke-dasharray разбиваем окружность на равные отрезки (зубцы)

.container {
width:75vw;
height:auto;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"   viewBox="0 0 800 400" style="border:1px solid gray;" > 
 
      <rect width="100%" height="100%" fill="#151515" /> 
    <!-- Левая шестеренка     -->
     <g id="left">
     <circle cx="150" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />     
    <circle cx="150" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
       <animate attributeName="stroke-dashoffset" values="1314;0" begin="svg1.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
         
    </g>  
               <!-- Цепь между двумя шестеренками -->
    <path  fill="none" stroke="grey" stroke-width="10"  stroke-dasharray="15.7, 15.7" 
        d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" > 
            <animate attributeName="stroke-dashoffset" values="1314;0" begin="svg1.click" dur="10s" fill="freeze" repeatCount="indefinite" />
    </path>     
 </svg>
</div> 

  • Добавляем симметрично вторую шестеренку

.container {
width:75vw;
height:auto;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"   viewBox="0 0 800 400" style="border:1px solid gray;" > 
 
      <rect width="100%" height="100%" fill="#151515" /> 
    <!-- Левая шестеренка     -->
     <g id="left">
      <circle cx="150" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />    
        <circle cx="150" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
          <animate attributeName="stroke-dashoffset" values="1314;0" begin="svg1.click" dur="10s" fill="freeze" repeatCount="indefinite" />          
    </g>  
       <!-- Правая шестеренка     -->
 <g id="right">
     <circle cx="650" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />     
    <circle cx="650" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
       <animate attributeName="stroke-dashoffset" values="1314;0" begin="svg1.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
        
    </g>        
               <!-- Цепь между двумя шестеренками -->
    <path  fill="none" stroke="grey" stroke-width="10"  stroke-dasharray="15.7, 15.7" 
        d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" > 
            <animate attributeName="stroke-dashoffset" values="1314;0" begin="svg1.click" dur="10s" fill="freeze" repeatCount="indefinite" />
    </path>     
 </svg>
</div> 

Пример с изменением вращения по клику

Немного усложним анимацию: при клике по левой шестеренке происходит вращение цепи и шестерёнок по часовой стрелке. При клике по правой шестерёнке вращение против часовой стрелки.

Изменение направления вращения достигается изменением значения: values="1314;0" - вперёд и values="0;1314" - назад

.container {
width:75vw;
height:auto;
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"   viewBox="0 0 800 400" style="border:1px solid gray;" > 
 
    <rect width="100%" height="100%" fill="#151515" />
      
          <!-- Окружность слева     -->  
           
     <g id="left">
     <circle cx="150" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />     
    <circle cx="150" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
       <animate attributeName="stroke-dashoffset" values="1314;0" begin="left.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
         <animate attributeName="stroke-dashoffset" values="0;1314" begin="right.click" dur="10s" fill="freeze" repeatCount="indefinite" />
    </g>  
        <!-- Окружность справа      -->  
           
     <g id="right">
     <circle cx="650" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />     
    <circle cx="650" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
       <animate attributeName="stroke-dashoffset" values="1314;0" begin="left.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
         <animate attributeName="stroke-dashoffset" values="0;1314" begin="right.click" dur="10s" fill="freeze" repeatCount="indefinite" />
    </g>    
     <path  fill="none" stroke="grey" stroke-width="10"  stroke-dasharray="15.7"  d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" > 
           <!-- Анимация вращения белой линии -->
         <animate attributeName="stroke-dashoffset" values="1314;0" begin="left.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
            <animate attributeName="stroke-dashoffset" values="0;1314" begin="right.click" dur="10s" fill="freeze" repeatCount="indefinite" />
       </path>   
   <text x="121" y="205" font-size="18px" fill="white" pointer-events="none"> Вперёд </text> 
     <text x="625" y="205" font-size="18px" fill="white" pointer-events="none"> Назад </text>
       
 </svg>
</div> 

3d попытка

.container {
width:75vw;
height:auto;
}
#p1{
transform: rotateX(24deg) rotateY(-10deg) rotateZ(12deg) skew(-15deg);
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"   viewBox="0 0 800 400" style="border:1px solid gray;" > 
 
    <rect width="100%" height="100%" fill="#151515" />
      
          <!-- Окружность слева     -->  
    <g   id="p1" > 
     <g id="left">
     <circle cx="150" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />     
    <circle cx="150" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
       <animate attributeName="stroke-dashoffset" values="1314;0" begin="left.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
         <animate attributeName="stroke-dashoffset" values="0;1314" begin="right.click" dur="10s" fill="freeze" repeatCount="indefinite" />
    </g>  
        <!-- Окружность справа      -->  
           
     <g id="right">
     <circle cx="650" cy="200" r="40" fill="#151515" stroke="white" stroke-width="10"  />     
    <circle cx="650" cy="200" r="50" fill="none" stroke="white" stroke-width="10" stroke-dasharray="15.7" />  
       <animate attributeName="stroke-dashoffset" values="1314;0" begin="left.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
         <animate attributeName="stroke-dashoffset" values="0;1314" begin="right.click" dur="10s" fill="freeze" repeatCount="indefinite" />
    </g>    
     <path  fill="none" stroke="grey" stroke-width="10"  stroke-dasharray="15.7"  d="M 150,250 A50,50 0 0 1 150,150 h500 A50,50 0 0 1  650,250 h-500" > 
           <!-- Анимация вращения белой линии -->
         <animate attributeName="stroke-dashoffset" values="1314;0" begin="left.click" dur="10s" fill="freeze" repeatCount="indefinite" /> 
            <animate attributeName="stroke-dashoffset" values="0;1314" begin="right.click" dur="10s" fill="freeze" repeatCount="indefinite" />
       </path>   
   <text x="121" y="205" font-size="18px" fill="white" pointer-events="none"> Вперёд </text> 
     <text x="625" y="205" font-size="18px" fill="white" pointer-events="none"> Назад </text>
    </g>   
 </svg>
</div> 

→ Ссылка