diff --git a/src/client/components/modal-page-window.vue b/src/client/components/modal-page-window.vue
index e7d96f7a6f..f57516360d 100644
--- a/src/client/components/modal-page-window.vue
+++ b/src/client/components/modal-page-window.vue
@@ -3,10 +3,11 @@
 	<div class="hrmcaedk _window _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
 		<div class="header" @contextmenu="onContextmenu">
 			<span class="title">
-				<XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="$refs.modal.close()"/>
+				
 			</span>
 		</div>
 		<div class="body _flat_">
+			<XHeader :info="pageInfo"/>
 			<keep-alive>
 				<component :is="component" v-bind="props" :ref="changePage"/>
 			</keep-alive>
diff --git a/src/client/components/page-window.vue b/src/client/components/page-window.vue
index fbc9f0b7fd..a8a8b76100 100644
--- a/src/client/components/page-window.vue
+++ b/src/client/components/page-window.vue
@@ -3,14 +3,20 @@
 	:initial-width="500"
 	:initial-height="500"
 	:can-resize="true"
-	:close-button="false"
+	:close-button="true"
 	:contextmenu="contextmenu"
 	@closed="$emit('closed')"
 >
 	<template #header>
-		<XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()" :title-only="true"/>
+		<template v-if="pageInfo">
+			{{ pageInfo.title }}
+		</template>
+	</template>
+	<template #headerLeft>
+		<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
 	</template>
 	<div class="yrolvcoq _flat_">
+		<XHeader :info="pageInfo"/>
 		<component :is="component" v-bind="props" :ref="changePage"/>
 	</div>
 </XWindow>
diff --git a/src/client/components/ui/window.vue b/src/client/components/ui/window.vue
index 773c3b9b13..6a7c61a7d5 100644
--- a/src/client/components/ui/window.vue
+++ b/src/client/components/ui/window.vue
@@ -3,11 +3,16 @@
 	<div class="ebkgocck" :class="{ front }" v-if="showing">
 		<div class="body _window _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
 			<div class="header" :class="{ mini }" @contextmenu.prevent.stop="onContextmenu">
-				<button v-if="closeButton" class="_button" @click="close()"><i class="fas fa-times"></i></button>
-
+				<span class="left">
+					<slot name="headerLeft"></slot>
+				</span>
 				<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
 					<slot name="header"></slot>
 				</span>
+				<span class="right">
+					<slot name="headerRight"></slot>
+					<button v-if="closeButton" class="_button" @click="close()"><i class="fas fa-times"></i></button>
+				</span>
 			</div>
 			<div class="body" v-if="padding">
 				<div class="_section">
@@ -418,12 +423,14 @@ export default defineComponent({
 			height: var(--height);
 			border-bottom: solid 1px var(--divider);
 
-			> ::v-deep(button) {
-				height: var(--height);
-				width: var(--height);
+			> .left, > .right {
+				> ::v-deep(button) {
+					height: var(--height);
+					width: var(--height);
 
-				&:hover {
-					color: var(--fgHighlighted);
+					&:hover {
+						color: var(--fgHighlighted);
+					}
 				}
 			}
 
diff --git a/src/client/directives/get-size.ts b/src/client/directives/get-size.ts
new file mode 100644
index 0000000000..e3b5dea0f3
--- /dev/null
+++ b/src/client/directives/get-size.ts
@@ -0,0 +1,34 @@
+import { Directive } from 'vue';
+
+export default {
+	mounted(src, binding, vn) {
+		const calc = () => {
+			const height = src.clientHeight;
+			const width = src.clientWidth;
+
+			// 要素が(一時的に)DOMに存在しないときは計算スキップ
+			if (height === 0) return;
+
+			binding.value(width, height);
+		};
+
+		calc();
+
+		// Vue3では使えなくなった
+		// 無くても大丈夫か...?
+		// TODO: ↑大丈夫じゃなかったので解決策を探す
+		//vn.context.$on('hook:activated', calc);
+
+		const ro = new ResizeObserver((entries, observer) => {
+			calc();
+		});
+		ro.observe(src);
+
+		src._get_size_ro_ = ro;
+	},
+
+	unmounted(src, binding, vn) {
+		binding.value(0, 0);
+		src._get_size_ro_.unobserve(src);
+	}
+} as Directive;
diff --git a/src/client/directives/index.ts b/src/client/directives/index.ts
index f0a0123771..cd71bc26d3 100644
--- a/src/client/directives/index.ts
+++ b/src/client/directives/index.ts
@@ -2,6 +2,7 @@ import { App } from 'vue';
 
 import userPreview from './user-preview';
 import size from './size';
+import getSize from './get-size';
 import particle from './particle';
 import tooltip from './tooltip';
 import hotkey from './hotkey';
@@ -14,6 +15,7 @@ export default function(app: App) {
 	app.directive('userPreview', userPreview);
 	app.directive('user-preview', userPreview);
 	app.directive('size', size);
+	app.directive('get-size', getSize);
 	app.directive('particle', particle);
 	app.directive('tooltip', tooltip);
 	app.directive('hotkey', hotkey);
diff --git a/src/client/pages/settings/index.vue b/src/client/pages/settings/index.vue
index cb86fdca71..3a8503ac55 100644
--- a/src/client/pages/settings/index.vue
+++ b/src/client/pages/settings/index.vue
@@ -74,6 +74,7 @@ export default defineComponent({
 			title: i18n.locale.settings,
 			icon: 'fas fa-cog',
 			bg: 'var(--bg)',
+			hide: true,
 		};
 		const INFO = ref(indexInfo);
 		const page = ref(props.initialPage);
diff --git a/src/client/pages/settings/profile.vue b/src/client/pages/settings/profile.vue
index 3c93e93480..eb9bc6565f 100644
--- a/src/client/pages/settings/profile.vue
+++ b/src/client/pages/settings/profile.vue
@@ -77,7 +77,8 @@ export default defineComponent({
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.profile,
 				icon: 'fas fa-user',
-				bg: 'var(--bg)'
+				bg: 'var(--bg)',
+				hide: true,
 			},
 			host,
 			langs,
diff --git a/src/client/ui/_common_/header.vue b/src/client/ui/_common_/header.vue
index f21be2f9cd..5405c43f8c 100644
--- a/src/client/ui/_common_/header.vue
+++ b/src/client/ui/_common_/header.vue
@@ -1,10 +1,5 @@
 <template>
-<div class="fdidabkb" :class="{ slim: titleOnly || narrow }" :style="`--height:${height};`" :key="key">
-	<transition :name="$store.state.animation ? 'header' : ''" mode="out-in" appear>
-		<div class="buttons left" v-if="backButton">
-			<button class="_button button back" @click.stop="$emit('back')" @touchstart="preventDrag" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button>
-		</div>
-	</transition>
+<div class="fdidabkb" :class="{ slim: narrow, thin }" :key="key">
 	<template v-if="info">
 		<div class="titleContainer" @click="showTabsPopup">
 			<i v-if="info.icon" class="icon" :class="info.icon"></i>
@@ -34,7 +29,6 @@
 			<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
 		</template>
 		<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
-		<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" @touchstart="preventDrag" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
 	</div>
 </div>
 </template>
@@ -52,20 +46,9 @@ export default defineComponent({
 		menu: {
 			required: false
 		},
-		backButton: {
-			type: Boolean,
+		thin: {
 			required: false,
-			default: false,
-		},
-		closeButton: {
-			type: Boolean,
-			required: false,
-			default: false,
-		},
-		titleOnly: {
-			type: Boolean,
-			required: false,
-			default: false,
+			default: false
 		},
 	},
 
@@ -99,11 +82,9 @@ export default defineComponent({
 	},
 
 	mounted() {
-		this.height = this.$el.parentElement.offsetHeight + 'px';
-		this.narrow = this.titleOnly || this.$el.parentElement.offsetWidth < 500;
+		this.narrow = this.$el.offsetWidth < 500;
 		new ResizeObserver((entries, observer) => {
-			this.height = this.$el.parentElement.offsetHeight + 'px';
-			this.narrow = this.titleOnly || this.$el.parentElement.offsetWidth < 500;
+			this.narrow = this.$el.offsetWidth < 500;
 		}).observe(this.$el);
 	},
 
@@ -161,8 +142,13 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .fdidabkb {
+	--height: 60px;
 	display: flex;
 
+	&.thin {
+		--height: 50px;
+	}
+
 	&.slim {
 		text-align: center;
 
@@ -220,6 +206,7 @@ export default defineComponent({
 		text-align: left;
 		font-weight: bold;
 		flex-shrink: 0;
+		margin-left: 24px;
 
 		> .avatar {
 			$size: 32px;
diff --git a/src/client/ui/chat/index.vue b/src/client/ui/chat/index.vue
index e8275def81..7090c9486a 100644
--- a/src/client/ui/chat/index.vue
+++ b/src/client/ui/chat/index.vue
@@ -74,7 +74,7 @@
 
 	<main class="main" @contextmenu.stop="onContextmenu">
 		<header class="header">
-			<XHeader class="header" :info="pageInfo" :menu="menu" :center="false" :back-button="true" @back="back()" @click="onHeaderClick"/>
+			<XHeader class="header" :info="pageInfo" :menu="menu" :center="false" @click="onHeaderClick"/>
 		</header>
 		<router-view v-slot="{ Component }">
 			<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
diff --git a/src/client/ui/chat/side.vue b/src/client/ui/chat/side.vue
index ebf1cf9979..3e8904596d 100644
--- a/src/client/ui/chat/side.vue
+++ b/src/client/ui/chat/side.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mrajymqm _narrow_" v-if="component">
 	<header class="header" @contextmenu.prevent.stop="onContextmenu">
-		<XHeader class="title" :info="pageInfo" :center="false" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()"/>
+		<XHeader class="title" :info="pageInfo" :center="false"/>
 	</header>
 	<component :is="component" v-bind="props" :ref="changePage" class="body _flat_"/>
 </div>
diff --git a/src/client/ui/deck/main-column.vue b/src/client/ui/deck/main-column.vue
index 4c591022a5..42d963cda6 100644
--- a/src/client/ui/deck/main-column.vue
+++ b/src/client/ui/deck/main-column.vue
@@ -1,9 +1,12 @@
 <template>
 <XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked">
 	<template #header>
-		<XHeader :info="pageInfo" :back-button="true" @back="back()"/>
+		<template v-if="pageInfo">
+			{{ pageInfo.title }}
+		</template>
 	</template>
 
+	<XHeader :info="pageInfo"/>
 	<router-view v-slot="{ Component }" class="_flat_">
 		<transition>
 			<keep-alive :include="['timeline']">
diff --git a/src/client/ui/default.header.vue b/src/client/ui/default.header.vue
index 6fbdd625c7..75c5c0c051 100644
--- a/src/client/ui/default.header.vue
+++ b/src/client/ui/default.header.vue
@@ -29,7 +29,7 @@
 				<MkAvatar :user="$i" class="avatar"/><MkAcct class="acct" :user="$i"/>
 			</button>
 			<div class="post" @click="post">
-				<MkButton class="button" primary full>
+				<MkButton class="button" primary full rounded>
 					<i class="fas fa-pencil-alt fa-fw"></i>
 				</MkButton>
 			</div>
diff --git a/src/client/ui/default.side.vue b/src/client/ui/default.side.vue
index 4d65779612..c453781e80 100644
--- a/src/client/ui/default.side.vue
+++ b/src/client/ui/default.side.vue
@@ -4,9 +4,10 @@
 		<header class="header" @contextmenu.prevent.stop="onContextmenu">
 			<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
 			<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
-			<XHeader class="title" :info="pageInfo" :back-button="false"/>
+			<span class="title">{{ pageInfo.title }}</span>
 			<button class="_button" @click="close()"><i class="fas fa-times"></i></button>
 		</header>
+		<XHeader class="pageHeader" :info="pageInfo"/>
 		<component :is="component" v-bind="props" :ref="changePage"/>
 	</div>
 </div>
diff --git a/src/client/ui/default.vue b/src/client/ui/default.vue
index a5ec243e9e..4ceb3e1650 100644
--- a/src/client/ui/default.vue
+++ b/src/client/ui/default.vue
@@ -1,5 +1,5 @@
 <template>
-<div class="mk-app" :class="{ wallpaper, isMobile }">
+<div class="mk-app" :class="{ wallpaper, isMobile }" :style="`--headerHeight:` + headerHeight + 'px'">
 	<XHeaderMenu v-if="showMenuOnTop"/>
 
 	<div class="columns" :class="{ fullView, withGlobalHeader: showMenuOnTop }">
@@ -14,7 +14,7 @@
 
 		<main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
 			<header class="header" @click="onHeaderClick">
-				<XHeader :info="pageInfo" :back-button="true" @back="back()"/>
+				<XHeader :info="pageInfo" v-get-size="(w, h) => headerHeight = h" :thin="true"/>
 			</header>
 			<div class="content" :class="{ _flat_: !fullView }">
 				<router-view v-slot="{ Component }">
@@ -88,6 +88,7 @@ export default defineComponent({
 	data() {
 		return {
 			pageInfo: null,
+			headerHeight: 0,
 			menuDef: menuDef,
 			isMobile: window.innerWidth <= MOBILE_THRESHOLD,
 			isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
@@ -257,7 +258,6 @@ export default defineComponent({
 }
 
 .mk-app {
-	$header-height: 50px;
 	$ui-font-size: 1em;
 	$widgets-hide-threshold: 1200px;
 	$nav-icon-only-width: 78px; // TODO: どこかに集約したい
@@ -330,7 +330,6 @@ export default defineComponent({
 				position: sticky;
 				z-index: 1000;
 				top: var(--globalHeaderHeight, 0px);
-				height: $header-height;
 				-webkit-backdrop-filter: var(--blur, blur(32px));
 				backdrop-filter: var(--blur, blur(32px));
 				background-color: var(--header);
@@ -338,11 +337,11 @@ export default defineComponent({
 			}
 
 			> .content {
-				--stickyTop: calc(var(--globalHeaderHeight, 0px) + #{$header-height});
+				--stickyTop: calc(var(--globalHeaderHeight, 0px) + var(--headerHeight));
 			}
 
 			@media (max-width: 850px) {
-				padding-top: $header-height;
+				padding-top: var(--headerHeight);
 
 				> .header {
 					position: fixed;
diff --git a/src/client/ui/universal.vue b/src/client/ui/universal.vue
index ec9254b697..5b51752dda 100644
--- a/src/client/ui/universal.vue
+++ b/src/client/ui/universal.vue
@@ -1,10 +1,10 @@
 <template>
-<div class="mk-app" :class="{ wallpaper }">
+<div class="mk-app" :class="{ wallpaper }" :style="`--headerHeight:` + headerHeight + 'px'">
 	<XSidebar ref="nav" class="sidebar"/>
 
 	<div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
 		<header class="header" ref="header" @click="onHeaderClick" :style="{ background: pageInfo?.bg }">
-			<XHeader :info="pageInfo" :back-button="true" @back="back()"/>
+			<XHeader v-if="!pageInfo?.hide" :info="pageInfo" v-get-size="(w, h) => headerHeight = h"/>
 		</header>
 		<main ref="main">
 			<div class="content">
@@ -86,6 +86,7 @@ export default defineComponent({
 	data() {
 		return {
 			pageInfo: null,
+			headerHeight: 0,
 			isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
 			menuDef: menuDef,
 			navHidden: false,
@@ -243,7 +244,6 @@ export default defineComponent({
 }
 
 .mk-app {
-	$header-height: 58px; // TODO: どこかに集約したい
 	$ui-font-size: 1em; // TODO: どこかに集約したい
 	$widgets-hide-threshold: 1090px;
 
@@ -263,19 +263,14 @@ export default defineComponent({
 	> .contents {
 		width: 100%;
 		min-width: 0;
-		--stickyTop: #{$header-height};
-		padding-top: $header-height;
+		--stickyTop: var(--headerHeight);
+		padding-top: var(--headerHeight);
 		background: var(--panel);
 
 		> .header {
 			position: fixed;
 			z-index: 1000;
 			top: 0;
-			height: $header-height;
-			width: 100%;
-			line-height: $header-height;
-			text-align: center;
-			font-weight: bold;
 			//background-color: var(--panel);
 			-webkit-backdrop-filter: var(--blur, blur(32px));
 			backdrop-filter: var(--blur, blur(32px));
@@ -287,13 +282,6 @@ export default defineComponent({
 		> main {
 			min-width: 0;
 
-			> .content {
-				> * {
-					// ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
-					min-height: calc((var(--vh, 1vh) * 100) - #{$header-height});
-				}
-			}
-
 			> .spacer {
 				height: 82px;