4

Есть изображение с точечной обводкой. Нужно, чтобы при наведении эта обводка постепенно меняла цвет. Долго думал, так ничего нормального и не смог придумать. Подскажите, пожалуйста, как это можно реализовать? Как это должно выглядеть

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384

3 Answers3

6

Кратко

  1. С помощью stroke-dasharrayи stroke-linecap="round" получаете первую окружность с красными кружками
  2. Добавляете поверх первой окружности точно такую же окружность с серыми кружками.
  3. Создаете маску состоящую из прямоугольника и третьей окружности.
  4. Анимируете маску, которая с помощью stroke-dashoffset` будет двигаться и прорезать серые кружки, показывая тем самым красные кружки.

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
<defs>
    <mask id="mask"> 
      <rect width="100%" height="100%" fill="white" /> 
         <circle transform="rotate(-91 75 75)" cx="75" cy="75" r="50" fill="none" stroke="black" 
                stroke-width="6"    stroke-dashoffset="314.15"    stroke-dasharray="314.15" >
              <!-- анимация вращения маски прорезающей серые кружки, показывая тем самым красные кружки -->       
              <animate   attributeName="stroke-dashoffset" begin="svg1.mouseover" end="svg1.mouseleave" 
                 dur="4s" values="314.15;0" fill="freeze" />
        </circle>
    </mask> 
</defs> 
      <!--  Внутренний серый фон, здесь можно расположить иконку -->
   <circle cx="75" cy="75" r="35" fill="#d3d3d3" fill-opacity="0.5" />
 &lt;!--  окружность c красными кружками --&gt;

<circle cx="75" cy="75" r="50" fill="none" stroke="orangered" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/>
<!-- окружность c серыми кружками--> <circle mask="url(#mask)" cx="75" cy="75" r="50" fill="none" stroke="#d3d3d3" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/> </svg>

Более подробно

1.С помощью stroke-dasharrayи stroke-linecap="round" получаете первую окружность с красными кружками Для создания кружков используется эффект, описанный подробно в ответе: Необычные эффекты stroke-dasharray

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
      <!--  окружность c красными кружками -->
 <circle cx="75" cy="75" r="50" fill="none" stroke="orangered" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/> 
 </svg>  
  1. Добавляете поверх первой окружности точно такую же окружность с серыми кружками.

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
      <!--  окружность c красными кружками -->
 <circle cx="75" cy="75" r="50" fill="none" stroke="orangered" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/> 
     <!--  окружность с серыми кружками -->
 <circle cx="75" cy="75" r="50" fill="none" stroke="#d3d3d3" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/> 
 </svg>  
 

3-4 Создание и анимация маски

Одним из свойств маски является прорезание верхнего слоя, в нашем случае серых кружков, до нижнего слоя (красных кружков) при fill="black"
Подробнее здесь: Практические примеры применения масок svg

Ниже код, показывающий анимацию движения маски при прорезании серых кружков

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150" style="border:1px solid">
<!-- <defs> -->
    <!-- <mask id="mask">  -->
      <rect width="100%" height="100%" fill="white" /> 
         <circle transform="rotate(-91 75 75)" cx="75" cy="75" r="50" fill="none" stroke="black" 
                stroke-width="6"    stroke-dashoffset="314.15"    stroke-dasharray="314.15" >
              <!-- анимация вращения маски прорезающей серые кружки, показывая тем самым красные кружки -->       
              <animate   attributeName="stroke-dashoffset" begin="svg1.mouseover" end="svg1.mouseleave" 
                 dur="4s" values="314.15;0" fill="freeze" />
        </circle>
    <!-- </mask>  -->
<!-- </defs>  -->
     <circle mask="url(#mask)" cx="75" cy="75" r="50" fill="none" stroke="#d3d3d3" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/>  
</svg>  
 
  1. Остается добавить условие запуска и остановки всей анимации при наведении begin="svg1.mouseover" и убирания курсора: end="svg1.mouseleave"

Добавлена простая SVG иконка в центр

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
<defs>
    <mask id="mask"> 
      <rect width="100%" height="100%" fill="white" /> 
         <circle transform="rotate(-91 75 75)" cx="75" cy="75" r="50" fill="none" stroke="black" 
                stroke-width="6"    stroke-dashoffset="314.15"    stroke-dasharray="314.15" >
              <!-- анимация вращения маски прорезающей серые кружки, показывая тем самым красные кружки -->       
              <animate   attributeName="stroke-dashoffset" begin="svg1.mouseover" end="svg1.mouseleave" 
                 dur="4s" values="314.15;0" fill="freeze" />
        </circle>
    </mask> 
</defs>

<circle cx="75" cy="75" r="38" fill="#d3d3d3" fill-opacity="0.5" /> <!-- Иконка --> <g transform="scale(0.5) translate(100,100)" fill="#F00" stroke="#3b5998" stroke-width="4" pointer-events="none"> <path d="M28,6h44v16l-22,21l-22-21z" fill="#6d84b4"/> <path d="M28,95h44v-16l-22-21l-22,21z" fill="#6d84b4"/> <path d="M6,30v42h15l21-21l-21-21z" fill="#afbfde"/> <path d="M95,30v42h-15l-21-21l21-21z" fill="#afbfde"/> </g>

 &lt;!--  окружность c красными кружками --&gt;

<circle cx="75" cy="75" r="50" fill="none" stroke="orangered" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/>
<!-- окружность c серыми кружками--> <circle mask="url(#mask)" cx="75" cy="75" r="50" fill="none" stroke="#d3d3d3" stroke-dasharray="0, 15.7075" stroke-width="6" stroke-linecap="round"/>
</svg>

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
5

Исключительно на правах эксперимента — попытка сделать совсем без SVG (Chrome 85+)

.circle {
  width: 80px;
  height: 80px;
  position: relative;
  background-color: #fff;
  transform: rotate(4deg);
}

.circle::before, .circle::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; border-radius: 50%; }

.circle::before { border: dotted 6px #ededed; }

.circle:hover::after { transform: rotate(-4deg); mix-blend-mode: color-burn; background-image: conic-gradient( #ed1a11 var(--angle), transparent 0); animation: progress 1s linear forwards; }

@keyframes progress { to { --angle: 360deg; } }

@property --angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }

<div class="circle"></div>
1

Вариант CSS

Идея решения точно такая же как в варианте SVG:
Используются две окружности, расположенные друг над другом.
Верхняя окружность с серыми кружками прорезается анимированной маской, показывая нижний слой с цветными кружками.

Стили представления SVG и анимация маски перенесены в правила CSS

Добавлена анимация закраски иконки при наведении:

#orange {
fill:none;
stroke:orangered;
stroke-width:6;
stroke-lineCap:round;
stroke-dasharray:0, 15.7075;
} 
#grey {
fill:none;
stroke:#d3d3d3;
stroke-width:6;
stroke-lineCap:round;
stroke-dasharray:0, 15.7075;
}
#circMask{
fill:none;
stroke:black;
stroke-width:6;
stroke-dasharray:0, 15.7075;
stroke-dashoffset:314.15;
stroke-dasharray:314.15;

} #svg1:hover #circMask{ animation: moveMask 4s; } @keyframes moveMask { 0% {stroke-dashoffset: 314.15;} 100% {stroke-dashoffset: 0;} } .blue { fill:#6d84b4; } lightBlue { fill:#afbfde; } #svg1:hover .blue { animation: fillIcon 3s forwards; } @keyframes fillIcon { to {fill:crimson}; }

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" viewBox="0 0 150 150">
<defs>
    <mask id="mask"> 
      <rect width="100%" height="100%" fill="white" /> 
         <circle id="circMask" transform ="rotate(-90, 75, 75)" cx="75" cy="75" r="50"/>
    </mask> 
</defs> 

   <circle cx="75" cy="75" r="38" fill="#d3d3d3" fill-opacity="0.5" /> 
             <!-- Иконка -->
  <g class="icon" transform="scale(0.5) translate(100,100)"  stroke="#3b5998" stroke-width="4" pointer-events="none">
    <path  class="blue" d="M28,6h44v16l-22,21l-22-21z" />
    <path   class="blue" d="M28,95h44v-16l-22-21l-22,21z" />
    <path class="lightBlue" d="M6,30v42h15l21-21l-21-21z" />
    <path class="lightBlue" d="M95,30v42h-15l-21-21l21-21z" />
  </g>

     <!--  окружность c красными кружками -->
 <circle id="orange" cx="75" cy="75" r="50" />    
   <!-- окружность c серыми кружками-->
  <circle id="grey" mask="url(#mask)" cx="75" cy="75" r="50" stroke-width="6" />  
 </svg>  
Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384