#css #svg #css-animations
#css #svg #css-анимация
Вопрос:
Я не могу сделать анимацию CSS с моим SVG-спрайтом, похожим на Pinterest. Спрайт состоит из 90 кадров, но я не могу заставить его работать
Эмодзи реакций Pinterest
Просмотр 90 кадров Pinterest Sprite в формате Svg
Мой код:
.emoji{
width: 110px;
height: 110px;
background-image : url(https://s.pinimg.com/webapp/style/images/wow-0a7ea725.svg);
animation: moveX 1s steps(90) infinite;
}
@keyframes moveX{
from{background-position-x:0px;}
to{background-position-x:-500px;}
}
<div class="emoji"></div>
Мой JSFiddle:
Комментарии:
1. Единственная проблема с вашим кодом заключалась в том, что вы неправильно установили ширину изображения… если бы вы вместо этого пошли с
to{background-position-x:-100%;}
этим, это сработало бы как шарм;-)
Ответ №1:
Вот так
.emoji {
width: 110px;
display: inline-flex;
background-image: url(https://s.pinimg.com/webapp/style/images/wow-0a7ea725.svg);
background-size: auto 100%;
animation: moveX 1s steps(90) infinite;
}
.emoji::before {
content: "";
padding-top: 100%; /* keep the square ratio */
}
@keyframes moveX {
to {
background-position: right; /* you only need to move to right */
}
}
<div class="emoji"></div>
<div class="emoji" style="width:50px"></div>
Комментарии:
1. Отличный друг, спасибо. но у меня есть вопрос… почему анимация вибрирует по оси X?
2. @DavidPumaRios либо спрайты не идеально выровнены, либо, возможно, проблема с отображением в браузере
3. @DavidPumaRios Я обновил код, чтобы избавиться от него. Используйте 100% по оси Y, чтобы не было места для прыжков
4.
::before
для чего? Я не вижу в этом никакой пользы … в противном случае, отличный ответ!5. @Christoph чтобы сохранить квадратное соотношение, обратите внимание, как я использовал два div с разной шириной, и я никогда не указывал высоту, потому что это сделает псевдоэлемент.
Ответ №2:
Если вы возьмете у Темани его отличный ответ, добавьте современный стандартный веб-компонент W3C, который использует буквальный синтаксический анализ шаблонов для создания клиентской части SVG sprite в ShadowDOM
(и сделайте несколько улучшенных вычислений анимации в <template>
)
Вы сохраняете загрузку SVG-файла размером 65 КБ и получаете:
<svg-spriter w=100 h=100 s=40 width="130px">
<template>
<g id="sprite${n}_${s}" transform="translate(${n*w})">
<rect x='5' y='5' width='90' height='90' rx='20' fill='#ffad65'></rect>
<circle cx='30' cy='30' r='${12 (n<10?-n:n)*.1}'></circle>
<circle cx='80' cy='30' r='${12 (n<10?n:-n)*.1}'></circle>
<ellipse cx='60' cy='70' rx="${10 (n<20?n*0.5:((20-n)*-0.5))}" ry="5"></ellipse>
</g>
</template>
</svg-spriter>
<script>
customElements.define("svg-spriter", class extends HTMLElement {
constructor() { super().attachShadow({mode: "open"}) }
connectedCallback() {
const parsed = (template, vars = {}) => new Function('vars', [
'let f = ( ' Object.keys(vars).join(', ') ' ) =>',
'`' template '`','return f(...Object.values(vars))'
].join('n'))(vars);
setTimeout(() => { // wait till <template> is parsed by the Browser
let attr = (x) => this.getAttribute(x);
let [w, h, s] = ["w", "h", "s"].map(a => ~~attr(a));
let width = attr("width");
let frame = this.querySelector("template").innerHTML;
let svg =
(`data:image/svg xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${s*w} ${h}'>`
Array(s).fill().map((s, n) => parsed(frame, {n,w,h,s})).join("") "</svg>").replace(/#/g, "#").replace(/n/g, "").replace(/</g, "<").replace(/>/g, ">").replaceAll('"', "'");
let html = `<style>div{width:${width};display:inline-flex;background-image: url("${svg}");background-size: auto ${width};animation:moveX 1s steps(${s-1}) infinite}div::before{content:"";padding-top:100%;}@keyframes moveX{to{background-position:right}}</style><div></div>`;
html = `<br>Sprite as IMG:<br><img src="${svg}">`;
this.shadowRoot.innerHTML = html;
})
}
});
</script>