问题描述
我正在尝试在 Vue 中实现一个 CSS 类型指示器.没有Vue,它看起来像这样:
.typing-indicator {背景颜色:#E6E7ED;宽度:自动;边框半径:50px;填充:20px;显示:表;边距:0 自动;位置:相对;-webkit-animation:2s 凸起无限缓出;动画:2s 凸起无限缓出;}.typing-indicator:before, .typing-indicator:after {内容: '';位置:绝对;底部:-2px;左:-2px;高度:20px;宽度:20px;边界半径:50%;背景颜色:#E6E7ED;}.typing-indicator:after {高度:10px;宽度:10px;左:-10px;底部:-10px;}.typing-indicator 跨度 {高度:15px;宽度:15px;向左飘浮;边距:0 1px;背景色:#9E9EA1;显示:块;边界半径:50%;不透明度:0.4;}.typing-indicator span:nth-of-type(1) {-webkit-animation:1s 闪烁无限 0.3333s;动画:1s 无限闪烁 0.3333s;}.typing-indicator span:nth-of-type(2) {-webkit-animation:1s 闪烁无限 0.6666s;动画:1s 无限闪烁 0.6666s;}.typing-indicator span:nth-of-type(3) {-webkit-animation:1s 闪烁无限 0.9999s;动画:1s 无限闪烁 0.9999s;}@-webkit-keyframes 闪烁 {50%{不透明度:1;}}@keyframes 闪烁 {50%{不透明度:1;}}@-webkit-keyframes 凸起 {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}@keyframes 凸起 {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}html {显示:表;高度:100%;宽度:100%;}身体 {显示:表格单元格;垂直对齐:中间;}
<span></span><span></span><span></span>
– 来源:http://jsfiddle.net/Arlina/gtttgo93/
问题是将 scoped
属性添加到组件的样式定义 () 时,动画不起作用.我认为这可能与应该全局声明的关键帧有关.
带有 .typing-indicator
的元素位于具有作用域样式的组件的模板中.
有没有人知道如何在使关键帧动画正常工作的同时允许我的组件具有范围样式?
问题
问题在于 Vue (vue-loader) 的 Webpack 加载器如何错误地, 在向作用域选择器和其他标识符添加 ID 时解析动画名称.这很重要,因为 vue-loader 的 CSS 范围使用添加到元素的独特属性来复制 CSS 范围的行为.虽然您的关键帧名称会附加 ID,但范围样式中动画规则中对关键帧的引用不会.
你的 CSS:
@-webkit-keyframes 闪烁 {50%{不透明度:1;}}@keyframes 闪烁 {50%{不透明度:1;}}@-webkit-keyframes 凸起 {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}@keyframes 凸起 {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}.typing-indicator {...-webkit-animation:2s 凸起无限缓出;动画:2s 凸起无限缓出;}.typing-indicator span:nth-of-type(1) {-webkit-animation:1s 闪烁无限 0.3333s;动画:1s 无限闪烁 0.3333s;}.typing-indicator span:nth-of-type(2) {-webkit-animation:1s 闪烁无限 0.6666s;动画:1s 无限闪烁 0.6666s;}.typing-indicator span:nth-of-type(3) {-webkit-animation:1s 闪烁无限 0.9999s;动画:1s 无限闪烁 0.9999s;}
应该变成:
@-webkit-keyframes 闪烁-数据-v-xxxxxxxx {50%{不透明度:1;}}@keyframes 闪烁数据-v-xxxxxxxx {50%{不透明度:1;}}@-webkit-keyframes bulge-data-v-xxxxxxxx {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}@keyframes 凸起数据-v-xxxxxxxx {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}.typing-indicator {...-webkit-animation: 2s bulge-data-v-xxxxxxxx 无限缓出;动画:2 秒 bulge-data-v-xxxxxxxx 无限缓出;}.typing-indicator span:nth-of-type(1) {-webkit-animation: 1s 闪烁-数据-v-xxxxxxxx 无限 0.3333s;动画:1s 闪烁-数据-v-xxxxxxxx 无限 0.3333s;}.typing-indicator span:nth-of-type(2) {-webkit-animation:1s 闪烁-数据-v-xxxxxxxx 无限 0.6666s;动画:1s 闪烁-数据-v-xxxxxxxx 无限 0.6666s;}.typing-indicator span:nth-of-type(3) {-webkit-animation: 1s 闪烁数据-v-xxxxxxxx 无限 0.9999s;动画:1s 闪烁-数据-v-xxxxxxxx 无限 0.9999s;}
然而它只会被转换为:
@-webkit-keyframes 闪烁-数据-v-xxxxxxxx {50%{不透明度:1;}}@keyframes 闪烁数据-v-xxxxxxxx {50%{不透明度:1;}}@-webkit-keyframes bulge-data-v-xxxxxxxx {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}@keyframes 凸起数据-v-xxxxxxxx {50%{-webkit-transform: scale(1.05);变换:比例(1.05);}}.typing-indicator {...-webkit-animation:2s 凸起无限缓出;动画:2s 凸起无限缓出;}.typing-indicator span:nth-of-type(1) {-webkit-animation:1s 闪烁无限 0.3333s;动画:1s 无限闪烁 0.3333s;}.typing-indicator span:nth-of-type(2) {-webkit-animation:1s 闪烁无限 0.6666s;动画:1s 无限闪烁 0.6666s;}.typing-indicator span:nth-of-type(3) {-webkit-animation:1s 闪烁无限 0.9999s;动画:1s 无限闪烁 0.9999s;}
注意事项:在实际转换中,动画规则中关键帧名称的引用缺少末尾的-data-v-xxxxxxxx
.这是错误.
目前(截至 47c3317)简写动画规则声明中的动画名称通过从任何空白字符分割动画规则中获取第一个值来标识.然而,动画属性的正式定义声明动画名称可以出现在规则定义中的任何位置.
=<时间>||<单一计时功能>||<时间>||<单动画迭代次数>||<单动画方向>||<单一动画填充模式>||<单一动画播放状态>||[ 无 |<关键帧名称>]
– animation
正式语法
因此,虽然您的动画声明有效,但 vue-loader 无法解析它.
解决方法
当前的解决方法是将动画名称移到动画规则声明的开头.您的关键帧声明不需要更改,它们保留在范围样式表中.您的动画声明现在应如下所示:
.typing-indicator {...-webkit-animation:凸起 2s 无限缓出;动画:凸起 2s 无限缓出;}.typing-indicator span:nth-of-type(1) {-webkit-animation:闪烁 1s 无限 0.3333s;动画:闪烁 1s 无限 0.3333s;}.typing-indicator span:nth-of-type(2) {-webkit-animation:闪烁 1s 无限 0.6666s;动画:闪烁 1s 无限 0.6666s;}.typing-indicator span:nth-of-type(3) {-webkit-animation:闪烁 1s 无限 0.9999s;动画:闪烁 1s 无限 0.9999s;}
参考文献
- [1] vue-loader/lib/style-compiler/plugins/scope-id.js#L67 @ 47c3317
- [2] 中
animation
的定义W3C 规范 CSS Animations Level 1 编辑草稿
I'm trying to implement a CSS typing indicator in Vue. Without Vue, it looks like this:
.typing-indicator {
background-color: #E6E7ED;
width: auto;
border-radius: 50px;
padding: 20px;
display: table;
margin: 0 auto;
position: relative;
-webkit-animation: 2s bulge infinite ease-out;
animation: 2s bulge infinite ease-out;
}
.typing-indicator:before, .typing-indicator:after {
content: '';
position: absolute;
bottom: -2px;
left: -2px;
height: 20px;
width: 20px;
border-radius: 50%;
background-color: #E6E7ED;
}
.typing-indicator:after {
height: 10px;
width: 10px;
left: -10px;
bottom: -10px;
}
.typing-indicator span {
height: 15px;
width: 15px;
float: left;
margin: 0 1px;
background-color: #9E9EA1;
display: block;
border-radius: 50%;
opacity: 0.4;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink infinite 0.3333s;
animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink infinite 0.6666s;
animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink infinite 0.9999s;
animation: 1s blink infinite 0.9999s;
}
@-webkit-keyframes blink {
50% {
opacity: 1;
}
}
@keyframes blink {
50% {
opacity: 1;
}
}
@-webkit-keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
@keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
html {
display: table;
height: 100%;
width: 100%;
}
body {
display: table-cell;
vertical-align: middle;
}
<div class="typing-indicator">
<span></span>
<span></span>
<span></span>
</div>
– source: http://jsfiddle.net/Arlina/gtttgo93/
The problem is that the animation does not work when adding the scoped
attribute to the component's style definition (<style lang="scss" scoped>
). I believe it may be related to keyframes that should be declared globally.
The element with .typing-indicator
is in the template of the component with scoped styling.
Does anyone have an idea of how I can allow my component to have scoped styling while making the keyframe animations work?
Problem
The problem is down to how the Webpack loader for Vue (vue-loader), incorrectly, parses animation names when adding IDs to scoped selectors and other identifiers. This is important because vue-loader's CSS scoping uses unique attributes added to elements to replicate the behaviour of CSS scoping. While your keyframe names get IDs appended, references to keyframes in animation rules in scoped styles do not.
Your CSS:
@-webkit-keyframes blink {
50% {
opacity: 1;
}
}
@keyframes blink {
50% {
opacity: 1;
}
}
@-webkit-keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
@keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
.typing-indicator {
...
-webkit-animation: 2s bulge infinite ease-out;
animation: 2s bulge infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink infinite 0.3333s;
animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink infinite 0.6666s;
animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink infinite 0.9999s;
animation: 1s blink infinite 0.9999s;
}
Should get transformed to:
@-webkit-keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
@keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
@-webkit-keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
@keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
.typing-indicator {
...
-webkit-animation: 2s bulge-data-v-xxxxxxxx infinite ease-out;
animation: 2s bulge-data-v-xxxxxxxx infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.3333s;
animation: 1s blink-data-v-xxxxxxxx infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.6666s;
animation: 1s blink-data-v-xxxxxxxx infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.9999s;
animation: 1s blink-data-v-xxxxxxxx infinite 0.9999s;
}
However it only get's transformed to:
@-webkit-keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
@keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
@-webkit-keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
@keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
.typing-indicator {
...
-webkit-animation: 2s bulge infinite ease-out;
animation: 2s bulge infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink infinite 0.3333s;
animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink infinite 0.6666s;
animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink infinite 0.9999s;
animation: 1s blink infinite 0.9999s;
}
Currently (as of 47c3317) the animation name in shorthand animation rule declarations is identified by getting the first value out of splitting the animation rule by any whitespace character. However the formal definition for the animation property states the animation name could appear anywhere within the rule definition.
– animation
formal syntax
Therefore, while your animation declarations are valid, vue-loader is not able to parse it.
Workaround
The current workaround for this is to move your animation names to the beginning of animation rule declarations. Your keyframe declarations do not need changing, they remain inside the scoped stylesheet. Your animation declarations should now look like this:
.typing-indicator {
...
-webkit-animation: bulge 2s infinite ease-out;
animation: bulge 2s infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: blink 1s infinite 0.3333s;
animation: blink 1s infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: blink 1s infinite 0.6666s;
animation: blink 1s infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: blink 1s infinite 0.9999s;
animation: blink 1s infinite 0.9999s;
}
References
- [1] vue-loader/lib/style-compiler/plugins/scope-id.js#L67 @ 47c3317
- [2] Definition for
animation
in the Editor's Draft of W3C specification CSS Animations Level 1
这篇关于为什么 CSS 关键帧动画在具有作用域样式的 Vue 组件中被破坏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!