diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index e1864ae124..e1aaee1d49 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -106,8 +106,29 @@
 
 	//#region Theme
 	const theme = localStorage.getItem('theme');
+	const themeFontFaceName = 'sharkey-theme-font-face';
 	if (theme) {
-		for (const [k, v] of Object.entries(JSON.parse(theme))) {
+		let existingFontFace;
+		document.fonts.forEach((v,k,s)=>{if (v.family === themeFontFaceName) existingFontFace=v;});
+		if (existingFontFace) document.fonts.delete(existingFontFace);
+
+		const themeProps = JSON.parse(theme);
+		const fontFaceSrc = themeProps.fontFaceSrc;
+		const fontFaceOpts = themeProps.fontFaceOpts || {};
+		if (fontFaceSrc) {
+			const fontFace = new FontFace(
+				themeFontFaceName,
+				fontFaceSrc, fontFaceOpts || {},
+			);
+			document.fonts.add(fontFace);
+			fontFace.load().catch(
+				(failure) => {
+					console.log(failure)
+				}
+			);
+		}
+		for (const [k, v] of Object.entries(themeProps)) {
+			if (k.startsWith('font')) continue;
 			document.documentElement.style.setProperty(`--${k}`, v.toString());
 
 			// HTMLの theme-color 適用
diff --git a/packages/frontend/src/scripts/theme.ts b/packages/frontend/src/scripts/theme.ts
index d2474bf10f..8bfb03f0dd 100644
--- a/packages/frontend/src/scripts/theme.ts
+++ b/packages/frontend/src/scripts/theme.ts
@@ -54,6 +54,8 @@ export const getBuiltinThemesRef = () => {
 	return builtinThemes;
 };
 
+const themeFontFaceName = 'sharkey-theme-font-face';
+
 let timeout = null;
 
 export function applyTheme(theme: Theme, persist = true) {
@@ -84,7 +86,32 @@ export function applyTheme(theme: Theme, persist = true) {
 		}
 	}
 
+	let existingFontFace;
+	document.fonts.forEach(
+		(fontFace) => {
+			if (fontFace.family === themeFontFaceName) existingFontFace = fontFace;
+		},
+	);
+	if (existingFontFace) document.fonts.delete(existingFontFace);
+
+	const fontFaceSrc = props.fontFaceSrc;
+	const fontFaceOpts = props.fontFaceOpts || {};
+
+	if (fontFaceSrc) {
+		const fontFace = new FontFace(
+			themeFontFaceName,
+			fontFaceSrc, fontFaceOpts,
+		);
+		document.fonts.add(fontFace);
+		fontFace.load().catch(
+			(failure) => {
+				console.log(failure);
+			},
+		);
+	}
+
 	for (const [k, v] of Object.entries(props)) {
+		if (k.startsWith('font')) continue;
 		document.documentElement.style.setProperty(`--${k}`, v.toString());
 	}
 
@@ -128,6 +155,10 @@ function compile(theme: Theme): Record<string, string> {
 
 	for (const [k, v] of Object.entries(theme.props)) {
 		if (k.startsWith('$')) continue; // ignore const
+		if (k.startsWith('font')) { // font specs are different
+			props[k] = v;
+			continue;
+		}
 
 		props[k] = v.startsWith('"') ? v.replace(/^"\s*/, '') : genValue(getColor(v));
 	}
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index 8c531fc2cc..b863f61cb4 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -62,7 +62,7 @@ html {
 	accent-color: var(--accent);
 	overflow: auto;
 	overflow-wrap: break-word;
-	font-family: 'Lexend', 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif;
+	font-family: 'sharkey-theme-font-face', 'Lexend', 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif;
 	font-size: 14px;
 	line-height: 1.35;
 	text-size-adjust: 100%;