diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue
index a88311efa1395e9d77306d17b0948c473bd6e3b5..4af9d6baa2e1b6a5a2c78015a79b37510d2fef99 100644
--- a/packages/frontend/src/components/MkReactionsViewer.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.vue
@@ -1,6 +1,8 @@
 <template>
 <div class="tdflqwzn" :class="{ isMe }">
-	<XReaction v-for="(count, reaction) in note.reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/>
+	<TransitionGroup :name="$store.state.animation ? 'x' : ''">
+		<XReaction v-for="(count, reaction) in note.reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/>
+	</TransitionGroup>
 </div>
 </template>
 
@@ -20,6 +22,17 @@ const isMe = computed(() => $i && $i.id === props.note.userId);
 </script>
 
 <style lang="scss" scoped>
+.x-move, .x-enter-active, .x-leave-active {
+	transition: opacity 0.2s cubic-bezier(0,.5,.5,1), transform 0.2s cubic-bezier(0,.5,.5,1) !important;
+}
+.x-enter-from, .x-leave-to {
+	opacity: 0;
+	transform: scale(0.7);
+}
+.x-leave-active {
+  position: absolute;
+}
+
 .tdflqwzn {
 	margin: 4px -2px 0 -2px;
 
diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue
index 6a029d43c7f112b3a4cd3245f012ff310b340312..8ebfbe58e86d80081e07626297185ebc90f0a103 100644
--- a/packages/frontend/src/components/MkUrlPreview.vue
+++ b/packages/frontend/src/components/MkUrlPreview.vue
@@ -7,7 +7,7 @@
 	<iframe ref="tweet" scrolling="no" frameborder="no" :style="{ position: 'relative', width: '100%', height: `${tweetHeight}px` }" :src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${$store.state.darkMode ? 'dark' : 'light'}&amp;id=${tweetId}`"></iframe>
 </div>
 <div v-else class="mk-url-preview">
-	<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+	<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 		<component :is="self ? 'MkA' : 'a'" v-if="!fetching" class="link" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url">
 			<div v-if="thumbnail" class="thumbnail" :style="`background-image: url('${thumbnail}')`">
 			</div>
diff --git a/packages/frontend/src/components/MkUrlPreviewPopup.vue b/packages/frontend/src/components/MkUrlPreviewPopup.vue
index a24aebe66fea77f0cd0137f3d1dd48ebf061950b..a0ad3c7fdd29f9f99e6a1ab3ebe22f1eecad0de7 100644
--- a/packages/frontend/src/components/MkUrlPreviewPopup.vue
+++ b/packages/frontend/src/components/MkUrlPreviewPopup.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="fgmtyycl" :style="{ zIndex, top: top + 'px', left: left + 'px' }">
-	<Transition :name="$store.state.animation ? 'zoom' : ''" @after-leave="emit('closed')">
+	<Transition :name="$store.state.animation ? '_transition_zoom' : ''" @after-leave="emit('closed')">
 		<MkUrlPreview v-if="showing" class="_popup _shadow" :url="url"/>
 	</Transition>
 </div>
diff --git a/packages/frontend/src/components/global/MkError.vue b/packages/frontend/src/components/global/MkError.vue
index a19103041c3702a82e92da9691277ffc056ad74c..6e297b9f5eca50675613ba96fee521ea041d5fc3 100644
--- a/packages/frontend/src/components/global/MkError.vue
+++ b/packages/frontend/src/components/global/MkError.vue
@@ -1,5 +1,5 @@
 <template>
-<Transition :name="$store.state.animation ? 'zoom' : ''" appear>
+<Transition :name="$store.state.animation ? '_transition_zoom' : ''" appear>
 	<div class="mjndxjcg">
 		<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
 		<p><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
diff --git a/packages/frontend/src/pages/_error_.vue b/packages/frontend/src/pages/_error_.vue
index ebadccb812b7f595e0b1136246f78c1b807bf3ad..da2889ba2705e5743bf24be52bee1fd9e4d14fe1 100644
--- a/packages/frontend/src/pages/_error_.vue
+++ b/packages/frontend/src/pages/_error_.vue
@@ -1,6 +1,6 @@
 <template>
 <MkLoading v-if="!loaded"/>
-<Transition :name="$store.state.animation ? 'zoom' : ''" appear>
+<Transition :name="$store.state.animation ? '_transition_zoom' : ''" appear>
 	<div v-show="loaded" class="mjndxjch">
 		<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
 		<p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p>
diff --git a/packages/frontend/src/pages/admin/overview.instances.vue b/packages/frontend/src/pages/admin/overview.instances.vue
index 6d2ac67418fab4704ce01eee5cfb2e6e247a1b33..ae10017aa85c9a7b73ed09e6426ac44b413f2e60 100644
--- a/packages/frontend/src/pages/admin/overview.instances.vue
+++ b/packages/frontend/src/pages/admin/overview.instances.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="wbrkwale">
-	<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+	<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 		<MkLoading v-if="fetching"/>
 		<div v-else class="instances">
 			<MkA v-for="(instance, i) in instances" :key="instance.id" v-tooltip.mfm.noDelay="`${instance.name}\n${instance.host}\n${instance.softwareName} ${instance.softwareVersion}`" :to="`/instance-info/${instance.host}`" class="instance">
diff --git a/packages/frontend/src/pages/admin/overview.moderators.vue b/packages/frontend/src/pages/admin/overview.moderators.vue
index ea8eed5bf2cfece9ff1e1fc39f5702b3eaef7b5d..3192b321772649246bd3a56cd21546a7162840a7 100644
--- a/packages/frontend/src/pages/admin/overview.moderators.vue
+++ b/packages/frontend/src/pages/admin/overview.moderators.vue
@@ -1,6 +1,6 @@
 <template>
 <div>
-	<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+	<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 		<MkLoading v-if="fetching"/>
 		<div v-else :class="$style.root" class="_panel">
 			<MkA v-for="user in moderators" :key="user.id" class="user" :to="`/user-info/${user.id}`">
diff --git a/packages/frontend/src/pages/admin/overview.stats.vue b/packages/frontend/src/pages/admin/overview.stats.vue
index 28d80e3118ad008528e32fae175bc4ea97492f1c..9012234c2e6c73a24a2a338aef3a98aa077ce926 100644
--- a/packages/frontend/src/pages/admin/overview.stats.vue
+++ b/packages/frontend/src/pages/admin/overview.stats.vue
@@ -1,6 +1,6 @@
 <template>
 <div>
-	<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+	<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 		<MkLoading v-if="fetching"/>
 		<div v-else :class="$style.root">
 			<div class="item _panel users">
diff --git a/packages/frontend/src/pages/admin/overview.users.vue b/packages/frontend/src/pages/admin/overview.users.vue
index 0022108e4142a073025ca16eb8002c1cb4b804f2..5390d9d8cbbe2b1619f46b6b93b5cb4c90933eb1 100644
--- a/packages/frontend/src/pages/admin/overview.users.vue
+++ b/packages/frontend/src/pages/admin/overview.users.vue
@@ -1,6 +1,6 @@
 <template>
 <div :class="$style.root">
-	<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+	<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 		<MkLoading v-if="fetching"/>
 		<div v-else class="users">
 			<MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/user-info/${user.id}`" class="user">
diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue
index 2d514d76709930de0ae4526f2f6a01dfed23eee1..714a8d44584c6f893290a858d472e3198ab5721d 100644
--- a/packages/frontend/src/pages/my-lists/list.vue
+++ b/packages/frontend/src/pages/my-lists/list.vue
@@ -3,7 +3,7 @@
 	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
 	<MkSpacer :content-max="700">
 		<div class="mk-list-page">
-			<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+			<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 				<div v-if="list" class="_section">
 					<div class="_content">
 						<MkButton inline @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
@@ -13,7 +13,7 @@
 				</div>
 			</Transition>
 
-			<Transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
+			<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
 				<div v-if="list" class="_section members _gap">
 					<div class="_title">{{ i18n.ts.members }}</div>
 					<div class="_content">
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index 8b7a8468635dff40193767ca3a6bab4dd8ebe3e9..51ea1bd343b0e4d7b9b2c9bf0eb067ac0c0ff82a 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -512,10 +512,10 @@ hr {
 	transition-timing-function: cubic-bezier(0,.5,.5,1);
 }
 
-.zoom-enter-active, .zoom-leave-active {
+._transition_zoom-enter-active, ._transition_zoom-leave-active {
 	transition: opacity 0.5s, transform 0.5s !important;
 }
-.zoom-enter-from, .zoom-leave-to {
+._transition_zoom-enter-from, ._transition_zoom-leave-to {
 	opacity: 0;
 	transform: scale(0.9);
 }