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

- 110,146
- 23
- 114
- 384
- 55
3 Answers
Кратко
- С помощью
stroke-dasharrayиstroke-linecap="round"получаете первую окружность с красными кружками - Добавляете поверх первой окружности точно такую же окружность с серыми кружками.
- Создаете маску состоящую из прямоугольника и третьей окружности.
- Анимируете маску, которая с помощью 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" />
<!-- окружность c красными кружками -->
<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>
- Добавляете поверх первой окружности точно такую же окружность с серыми кружками.
<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>
- Остается добавить условие запуска и остановки всей анимации при наведении
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>
<!-- окружность c красными кружками -->
<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>
- 110,146
- 23
- 114
- 384
Исключительно на правах эксперимента — попытка сделать совсем без 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,509
-
конический градиент не работает же в файерфоксе ? – Резидент Казахстана Aug 15 '21 at 13:26
-
1@MaximLensky Конический градиент работает в FF, но там пока нет поддержки @property, чтобы можно было его анимировать. – Alexey Vladimirov Aug 15 '21 at 14:49
Вариант 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>
- 110,146
- 23
- 114
- 384