diff --git a/packages/frontend/src/components/MkContainer.vue b/packages/frontend/src/components/MkContainer.vue
index b4b67198306df950952ca268229e7e8254413f68..962bcaf7e9bf937a4230ffdd0ea86d9092f8be10 100644
--- a/packages/frontend/src/components/MkContainer.vue
+++ b/packages/frontend/src/components/MkContainer.vue
@@ -131,7 +131,7 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .container-toggle-enter-active, .container-toggle-leave-active {
-	overflow-y: hidden;
+	overflow-y: clip;
 	transition: opacity 0.5s, height 0.5s !important;
 }
 .container-toggle-enter-from {
diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue
index d76ea43888fc8ee4bf650959cf3127bfe6418d4e..5a406c8635f85fc3163d32322ca4da8e5560bbcd 100644
--- a/packages/frontend/src/components/MkFolder.vue
+++ b/packages/frontend/src/components/MkFolder.vue
@@ -98,7 +98,7 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .folder-toggle-enter-active, .folder-toggle-leave-active {
-	overflow-y: hidden;
+	overflow-y: clip;
 	transition: opacity 0.5s, height 0.5s !important;
 }
 .folder-toggle-enter-from {
diff --git a/packages/frontend/src/components/form/folder.vue b/packages/frontend/src/components/form/folder.vue
index 1256dfcbb460d7696c8dcd7e726cfbb56d7a73cd..d7603e58d1a746771ad4e3cf5df209d135d5777f 100644
--- a/packages/frontend/src/components/form/folder.vue
+++ b/packages/frontend/src/components/form/folder.vue
@@ -1,5 +1,5 @@
 <template>
-<div class="dwzlatin" :class="{ opened }">
+<div class="dwzlatin" :class="{ opened }" ref="root">
 	<div class="header _button" @click="toggle">
 		<span class="icon"><slot name="icon"></slot></span>
 		<span class="text"><slot name="label"></slot></span>
@@ -9,17 +9,29 @@
 			<i v-else class="ti ti-chevron-down icon"></i>
 		</span>
 	</div>
-	<KeepAlive>
-		<div v-if="openedAtLeastOnce" v-show="opened" class="body">
-			<MkSpacer :margin-min="14" :margin-max="22">
-				<slot></slot>
-			</MkSpacer>
-		</div>
-	</KeepAlive>
+	<div v-if="openedAtLeastOnce" class="body">
+		<Transition
+			:name="$store.state.animation ? 'folder-toggle' : ''"
+			@enter="enter"
+			@after-enter="afterEnter"
+			@leave="leave"
+			@after-leave="afterLeave"
+		>
+			<KeepAlive>
+				<div v-show="opened">
+					<MkSpacer :margin-min="14" :margin-max="22" :container="root">
+						<slot></slot>
+					</MkSpacer>
+				</div>
+			</KeepAlive>
+		</Transition>
+	</div>
 </div>
 </template>
 
 <script lang="ts" setup>
+import { nextTick } from 'vue';
+
 const props = withDefaults(defineProps<{
 	defaultOpen: boolean;
 }>(), {
@@ -28,16 +40,50 @@ const props = withDefaults(defineProps<{
 
 let opened = $ref(props.defaultOpen);
 let openedAtLeastOnce = $ref(props.defaultOpen);
+let root = $ref<HTMLElement>();
+
+function enter(el) {
+	const elementHeight = el.getBoundingClientRect().height;
+	el.style.height = 0;
+	el.offsetHeight; // reflow
+	el.style.height = elementHeight + 'px';
+}
+
+function afterEnter(el) {
+	el.style.height = null;
+}
+
+function leave(el) {
+	const elementHeight = el.getBoundingClientRect().height;
+	el.style.height = elementHeight + 'px';
+	el.offsetHeight; // reflow
+	el.style.height = 0;
+}
 
-const toggle = () => {
-	opened = !opened;
-	if (opened) {
+function afterLeave(el) {
+	el.style.height = null;
+}
+
+function toggle() {
+	if (!opened) {
 		openedAtLeastOnce = true;
 	}
-};
+
+	nextTick(() => {
+		opened = !opened;
+	});
+}
 </script>
 
 <style lang="scss" scoped>
+.folder-toggle-enter-active, .folder-toggle-leave-active {
+	overflow-y: clip;
+	transition: opacity 0.3s, height 0.3s, transform 0.3s !important;
+}
+.folder-toggle-enter-from, .folder-toggle-leave-to {
+	opacity: 0;
+}
+
 .dwzlatin {
 	display: block;
 
diff --git a/packages/frontend/src/components/form/range.vue b/packages/frontend/src/components/form/range.vue
index db21c35717f76ad9ef8319966b24172d6c3432d1..cdaecb84c8a24d2bb191111338d7a895938f116b 100644
--- a/packages/frontend/src/components/form/range.vue
+++ b/packages/frontend/src/components/form/range.vue
@@ -59,16 +59,17 @@ const finalValue = computed(() => {
 	}
 });
 
-const thumbWidth = computed(() => {
+const getThumbWidth = () => {
 	if (thumbEl.value == null) return 0;
 	return thumbEl.value!.offsetWidth;
-});
+};
 const thumbPosition = ref(0);
 const calcThumbPosition = () => {
 	if (containerEl.value == null) {
 		thumbPosition.value = 0;
 	} else {
-		thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedRawValue.value;
+		thumbPosition.value = (containerEl.value.offsetWidth - getThumbWidth()) * steppedRawValue.value;
+		console.log(containerEl.value.offsetWidth, getThumbWidth());
 	}
 };
 watch([steppedRawValue, containerEl], calcThumbPosition);
@@ -110,12 +111,14 @@ const onMousedown = (ev: MouseEvent | TouchEvent) => {
 	style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
 	document.head.appendChild(style);
 
+	const thumbWidth = getThumbWidth();
+
 	const onDrag = (ev: MouseEvent | TouchEvent) => {
 		ev.preventDefault();
 		const containerRect = containerEl.value!.getBoundingClientRect();
 		const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX;
-		const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth.value / 2));
-		rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth.value)));
+		const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth / 2));
+		rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth)));
 	};
 
 	let beforeValue = finalValue.value;
diff --git a/packages/frontend/src/components/global/MkSpacer.vue b/packages/frontend/src/components/global/MkSpacer.vue
index b3a42d77e7c75f8c89b3b9fea77d3f5417a16c5f..01e7409801aa769cedaa2e1e102f47ac58dd80d0 100644
--- a/packages/frontend/src/components/global/MkSpacer.vue
+++ b/packages/frontend/src/components/global/MkSpacer.vue
@@ -14,6 +14,9 @@ const props = withDefaults(defineProps<{
 	contentMax?: number | null;
 	marginMin?: number;
 	marginMax?: number;
+
+	// MkFolderとかで開閉アニメーションの際にheightを正しく伝えるため
+	container?: HTMLElement,
 }>(), {
 	contentMax: null,
 	marginMin: 12,
@@ -23,7 +26,7 @@ const props = withDefaults(defineProps<{
 let ro: ResizeObserver;
 let root = $ref<HTMLElement>();
 let content = $ref<HTMLElement>();
-let margin = $ref(0);
+let margin = $ref(props.marginMin);
 const widthHistory = [null, null] as [number | null, number | null];
 const heightHistory = [null, null] as [number | null, number | null];
 const shouldSpacerMin = inject('shouldSpacerMin', false);
@@ -41,6 +44,15 @@ const adjust = (rect: { width: number; height: number; }) => {
 	}
 };
 
+if (props.container) {
+	const width = props.container.offsetWidth;
+	const height = props.container.offsetHeight;
+	adjust({
+		width,
+		height,
+	});
+}
+
 onMounted(() => {
 	ro = new ResizeObserver((entries) => {
 		/* iOSが対応していない
@@ -50,8 +62,8 @@ onMounted(() => {
 		});
 		*/
 
-		const width = root!.offsetWidth;
-		const height = root!.offsetHeight;
+		const width = props.container ? props.container.offsetWidth : root!.offsetWidth;
+		const height = props.container ? props.container.offsetHeight : root!.offsetHeight;
 
 		//#region Prevent infinite resizing
 		// https://github.com/misskey-dev/misskey/issues/9076