diff --git a/components/common/CommonInputImage.vue b/components/common/CommonInputImage.vue
index 595d5786..4a002ed2 100644
--- a/components/common/CommonInputImage.vue
+++ b/components/common/CommonInputImage.vue
@@ -88,17 +88,19 @@ watch(file, (image, _, onCleanup) => {
       w-full
       h-full
     >
-    <div absolute bg="black/50" text-white rounded-full text-xl w12 h12 flex justify-center items-center hover="bg-black/40 text-primary">
-      <div i-ri:upload-line />
-    </div>
+    <span absolute bg="black/50" text-white rounded-full text-xl w12 h12 flex justify-center items-center hover="bg-black/40 text-primary">
+      <span block i-ri:upload-line />
+    </span>
 
-    <div
+    <span
       v-if="loading"
       absolute inset-0
       bg="black/30" text-white
       flex justify-center items-center
     >
-      <div class="i-ri:loader-4-line animate-spin animate-duration-[2.5s]" text-4xl />
-    </div>
+      <span class="animate-spin animate-duration-[2.5s] preserve-3d">
+        <span block i-ri:loader-4-line text-4xl />
+      </span>
+    </span>
   </label>
 </template>
diff --git a/components/notification/NotificationEnablePushNotification.client.vue b/components/notification/NotificationEnablePushNotification.client.vue
index 3b1c654b..2df3248b 100644
--- a/components/notification/NotificationEnablePushNotification.client.vue
+++ b/components/notification/NotificationEnablePushNotification.client.vue
@@ -66,7 +66,10 @@ const isLegacyAccount = computed(() => !currentUser.value?.vapidKey)
       :disabled="busy || isLegacyAccount"
       @click="$emit('subscribe')"
     >
-      <span aria-hidden="true" :class="busy && animate ? 'i-ri:loader-2-fill animate-spin' : 'i-ri:check-line'" />
+      <span v-if="busy && animate" aria-hidden="true" block animate-spin preserve-3d>
+        <span block i-ri:loader-2-fill aria-hidden="true" />
+      </span>
+      <span v-else aria-hidden="true" block i-ri:check-line />
       <span>{{ $t('settings.notifications.push_notifications.warning.enable_desktop') }}</span>
     </button>
     <slot name="error" />
diff --git a/components/notification/NotificationPreferences.client.vue b/components/notification/NotificationPreferences.client.vue
index 0cda3c27..77b8f273 100644
--- a/components/notification/NotificationPreferences.client.vue
+++ b/components/notification/NotificationPreferences.client.vue
@@ -147,7 +147,10 @@ onActivated(() => (busy = false))
                   :class="busy || !saveEnabled ? 'border-transparent' : null"
                   :disabled="busy || !saveEnabled"
                 >
-                  <span :class="busy && animateSave ? 'i-ri:loader-2-fill animate-spin' : 'i-ri:save-2-fill'" />
+                  <span v-if="busy && animateSave" aria-hidden="true" block animate-spin preserve-3d>
+                    <span block i-ri:loader-2-fill aria-hidden="true" />
+                  </span>
+                  <span v-else block aria-hidden="true" i-ri:save-2-fill />
                   {{ $t('settings.notifications.push_notifications.save_settings') }}
                 </button>
                 <button
@@ -157,7 +160,7 @@ onActivated(() => (busy = false))
                   :disabled="busy || !saveEnabled"
                   @click="undoChanges"
                 >
-                  <span aria-hidden="true" class="i-material-symbols:undo-rounded" />
+                  <span aria-hidden="true" class="block i-material-symbols:undo-rounded" />
                   {{ $t('settings.notifications.push_notifications.undo_settings') }}
                 </button>
               </div>
@@ -169,7 +172,10 @@ onActivated(() => (busy = false))
                 :class="busy ? 'border-transparent' : null"
                 :disabled="busy"
               >
-                <span aria-hidden="true" :class="busy && animateRemoveSubscription ? 'i-ri:loader-2-fill animate-spin' : 'i-material-symbols:cancel-rounded'" />
+                <span v-if="busy && animateRemoveSubscription" aria-hidden="true" block animate-spin preserve-3d>
+                  <span block i-ri:loader-2-fill aria-hidden="true" />
+                </span>
+                <span v-else block aria-hidden="true" i-material-symbols:cancel-rounded />
                 {{ $t('settings.notifications.push_notifications.unsubscribe') }}
               </button>
             </form>
diff --git a/components/publish/PublishWidget.vue b/components/publish/PublishWidget.vue
index 02e0e97a..5dfe1c97 100644
--- a/components/publish/PublishWidget.vue
+++ b/components/publish/PublishWidget.vue
@@ -145,7 +145,9 @@ defineExpose({
         </div>
 
         <div v-if="isUploading" flex gap-1 items-center text-sm p1 text-primary>
-          <div i-ri:loader-2-fill animate-spin />
+          <div animate-spin preserve-3d>
+            <div i-ri:loader-2-fill />
+          </div>
           {{ $t('state.uploading') }}
         </div>
         <div
@@ -274,7 +276,9 @@ defineExpose({
             aria-describedby="publish-tooltip"
             @click="publish"
           >
-            <div v-if="isSending" i-ri:loader-2-fill animate-spin />
+            <span v-if="isSending" block animate-spin preserve-3d>
+              <div block i-ri:loader-2-fill />
+            </span>
             <span v-if="draft.editingStatus">{{ $t('action.save_changes') }}</span>
             <span v-else-if="draft.params.inReplyToId">{{ $t('action.reply') }}</span>
             <span v-else>{{ !isSending ? $t('action.publish') : $t('state.publishing') }}</span>
diff --git a/components/tiptap/TiptapHashtagList.vue b/components/tiptap/TiptapHashtagList.vue
index d8c063aa..0aa486aa 100644
--- a/components/tiptap/TiptapHashtagList.vue
+++ b/components/tiptap/TiptapHashtagList.vue
@@ -46,7 +46,9 @@ defineExpose({
   <div v-if="isPending || items.length" relative bg-base text-base shadow border="~ base rounded" text-sm py-2 overflow-x-hidden overflow-y-auto max-h-100>
     <template v-if="isPending">
       <div flex gap-1 items-center p2 animate-pulse>
-        <div i-ri:loader-2-line animate-spin />
+        <div animate-spin preserve-3d>
+          <div i-ri:loader-2-line />
+        </div>
         <span>Fetching...</span>
       </div>
     </template>
diff --git a/components/tiptap/TiptapMentionList.vue b/components/tiptap/TiptapMentionList.vue
index 08bad3d6..81f0e5c6 100644
--- a/components/tiptap/TiptapMentionList.vue
+++ b/components/tiptap/TiptapMentionList.vue
@@ -46,7 +46,9 @@ defineExpose({
   <div v-if="isPending || items.length" relative bg-base text-base shadow border="~ base rounded" text-sm py-2 overflow-x-hidden overflow-y-auto max-h-100>
     <template v-if="isPending">
       <div flex gap-1 items-center p2 animate-pulse>
-        <div i-ri:loader-2-line animate-spin />
+        <div animate-spin preserve-3d>
+          <div i-ri:loader-2-line />
+        </div>
         <span>Fetching...</span>
       </div>
     </template>
diff --git a/components/user/UserSignIn.vue b/components/user/UserSignIn.vue
index e74b5fdc..f64cdc7f 100644
--- a/components/user/UserSignIn.vue
+++ b/components/user/UserSignIn.vue
@@ -208,7 +208,10 @@ onClickOutside($$(input), () => {
       </span>
     </div>
     <button flex="~ row" gap-x-2 items-center btn-solid mt2 :disabled="!server || busy">
-      <span aria-hidden="true" inline-block :class="busy ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:login-circle-line'" class="rtl-flip" />
+      <span v-if="busy" aria-hidden="true" block animate animate-spin preserve-3d class="rtl-flip">
+        <span block i-ri:loader-2-fill aria-hidden="true" />
+      </span>
+      <span v-else aria-hidden="true" block i-ri:login-circle-line class="rtl-flip" />
       {{ $t('action.sign_in') }}
     </button>
   </form>
diff --git a/error.vue b/error.vue
index 897b1d5b..1e5aa429 100644
--- a/error.vue
+++ b/error.vue
@@ -47,7 +47,9 @@ const reload = async () => {
             {{ message }}
           </div>
           <button flex items-center gap-2 justify-center btn-solid text-center :disabled="state === 'reloading'">
-            <span v-if="state === 'reloading'" i-ri:loader-2-fill animate-spin inline-block />
+            <span v-if="state === 'reloading'" block animate-spin preserve-3d>
+              <span block i-ri:loader-2-fill />
+            </span>
             {{ state === 'reloading' ? 'Reloading' : 'Reload' }}
           </button>
         </form>
diff --git a/pages/settings/profile/appearance.vue b/pages/settings/profile/appearance.vue
index f1636580..60ce26f0 100644
--- a/pages/settings/profile/appearance.vue
+++ b/pages/settings/profile/appearance.vue
@@ -172,10 +172,10 @@ onReactivated(refreshInfo)
             flex gap-x-2 items-center
             :disabled="submitting || !isCanSubmit"
           >
-            <div
-              aria-hidden="true"
-              :class="submitting ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:save-line'"
-            />
+            <span v-if="submitting" aria-hidden="true" block animate-spin preserve-3d>
+              <span block i-ri:loader-2-fill aria-hidden="true" />
+            </span>
+            <span v-else aria-hidden="true" block i-ri:save-line />
             {{ $t('action.save') }}
           </button>
         </div>