サイドバーと本文が並ぶ画面を狭めすぎて崩れる、横に広げすぎて 1 行が長くなり読みにくい、といった問題は、ユーザーがリサイズできる範囲を決めておけば防げます。固定の範囲は tauri.conf.json の minWidth / minHeight / maxWidth / maxHeight、表示内容に応じた変更は JS の setMinSize() / setMaxSize() / setSizeConstraints() か Rust の同名メソッドで行います。制限の対象はタイトルバーと枠を除いた内側のサイズで、単位は論理ピクセルを使うのが基本です。
前提条件
プラグインは不要で、設定ファイルで決めるだけなら権限も要りません。実行時に変える core:window:allow-set-min-size / allow-set-max-size / allow-set-size-constraints はどれも core:window:default に含まれないので、使うものを追加します。後述の例では、狭いウィンドウを広げるために core:window:allow-set-size も使います。innerSize() と scaleFactor() は core:window:default に含まれます。
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"core:window:allow-set-min-size",
"core:window:allow-set-max-size",
"core:window:allow-set-size-constraints",
"core:window:allow-set-size"
]
}
設定ファイルの 4 つのキーは独立していて、書いたものだけが効きます。次の例では高さの上限を付けていません。初期サイズ(width / height)は範囲の内側にしておきます。
{
"app": {
"windows": [
{
"label": "main",
"width": 1024,
"height": 720,
"minWidth": 480,
"minHeight": 360,
"maxWidth": 1600
}
]
}
}
値を決めるときの目安が 2 つあります。1 つは、内側の論理サイズがページの CSS ピクセルの幅(window.innerWidth)と一致することです。minWidth: 480 にすれば、CSS で 480px 未満のレイアウトを用意する必要はありません。もう 1 つは、対応したい一番小さな画面に収まることです。1920x1080 の画面を拡大率 150% で使うと論理解像度は 1280x720 で、タスクバーを除いた作業領域はさらに狭くなります。minHeight: 720 ではこの環境でウィンドウが画面からはみ出します。
| やりたいこと | 使うもの |
|---|---|
| いつも同じ範囲に制限する | 設定ファイルの minWidth など |
| 表示内容に応じて最小サイズを変える | setMinSize() / setMaxSize() |
| 幅だけ・高さだけを実行中に制限する | setSizeConstraints() |
| 大きさを完全に固定する | resizable: false(ユーザーによるリサイズを禁止する) |
| 大きさそのものを変える | setSize()(ウィンドウのサイズを変更する) |
1. フロントエンドから実装する (TypeScript)
表示内容に合わせて最小サイズを変える
サイドバーを開いたときだけ最小幅を広げる例です。setMinSize() / setMaxSize() は幅と高さを組で受け取り、null を渡すと制限を外します。今のウィンドウが新しい最小幅より狭い場合に備えて、setSize() で広げておくと確実です。
import { getCurrentWindow, LogicalSize } from '@tauri-apps/api/window';
const win = getCurrentWindow();
const CONTENT_MIN = 480; // 本文だけのときの最小幅
const SIDEBAR = 240;
export async function setSidebar(open: boolean) {
document.body.classList.toggle('sidebar-open', open);
const minWidth = CONTENT_MIN + (open ? SIDEBAR : 0);
await win.setMinSize(new LogicalSize(minWidth, 360)); // core:window:allow-set-min-size が必要
const now = (await win.innerSize()).toLogical(await win.scaleFactor()); // 物理 → 論理
if (now.width < minWidth) {
await win.setSize(new LogicalSize(minWidth, now.height)); // core:window:allow-set-size が必要
}
}
PhysicalSize でも指定できますが、拡大率 200% のモニターでは見た目が半分の大きさになります。モニターをまたいでも同じ見た目の範囲にするなら LogicalSize を使います。
幅だけを制限する
幅だけ、高さだけを制限したいときは setSizeConstraints() を使います。数値は論理ピクセルとして扱われます。注意点は、呼ぶたびに 4 つの制限をまとめて置き換えることです。書かなかった項目は「制限なし」になるので、設定ファイルの minHeight も消えます。残したい制限は毎回すべて書きます。また 0 は「指定なし」と同じ扱いです。
import { getCurrentWindow } from '@tauri-apps/api/window';
const win = getCurrentWindow();
// 読みやすい行の長さを保つため、幅を 480〜1200 にする。高さの最小 360 も残す
export async function limitWidth() {
await win.setSizeConstraints({ minWidth: 480, maxWidth: 1200, minHeight: 360 }); // core:window:allow-set-size-constraints が必要
}
// 制限をすべて外す
export async function clearConstraints() {
await win.setSizeConstraints(null);
}
2. バックエンドから実装する (Rust)
実行中の変更は set_min_size() / set_max_size()(引数は Option)と set_size_constraints() です。Rust で作るウィンドウには、ビルダーの min_inner_size() / max_inner_size()(論理ピクセル)か、項目ごとに決められる inner_size_constraints() を付けます。WindowSizeConstraints の各項目は PixelUnit で、None が制限なしです。ウィンドウを作るコマンドは、Windows で固まらないよう async にします。
use tauri::{LogicalSize, LogicalUnit, PixelUnit, WebviewUrl, WebviewWindowBuilder, WindowSizeConstraints};
fn logical(v: f64) -> Option<PixelUnit> {
Some(LogicalUnit::new(v).into())
}
/// 呼び出し元ウィンドウの最小サイズを変える。幅か高さが無ければ制限を外す
#[tauri::command]
fn set_min_window_size(window: tauri::WebviewWindow, width: Option<f64>, height: Option<f64>) -> Result<(), String> {
let result = match (width, height) {
(Some(w), Some(h)) => window.set_min_size(Some(LogicalSize::new(w, h))),
// None だけでは型が決まらないので型を付ける
_ => window.set_min_size(None::<LogicalSize<f64>>),
};
result.map_err(|e| e.to_string())
}
/// 幅 400〜720・高さ 300 以上に制限した設定ウィンドウを開く
#[tauri::command]
async fn open_settings(app: tauri::AppHandle) -> Result<(), String> {
WebviewWindowBuilder::new(&app, "settings", WebviewUrl::App("settings.html".into()))
.title("設定")
.inner_size(520.0, 400.0)
.inner_size_constraints(WindowSizeConstraints {
min_width: logical(400.0),
min_height: logical(300.0),
max_width: logical(720.0),
max_height: None, // 高さの上限なし
})
.build()
.map_err(|e| e.to_string())?;
Ok(())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![set_min_window_size, open_settings])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
import { invoke } from '@tauri-apps/api/core';
await invoke('set_min_window_size', { width: 720, height: 480 });
await invoke('set_min_window_size', {}); // 引数を省くと None になり、制限が外れる
await invoke('open_settings');
動作確認
npm run tauri dev で起動し、次のコードを読み込んでから枠をドラッグして縮めます。
import { getCurrentWindow } from '@tauri-apps/api/window';
const win = getCurrentWindow();
await win.onResized(async ({ payload }) => {
const logical = payload.toLogical(await win.scaleFactor());
console.log(`inner ${payload.width}x${payload.height} / logical ${Math.round(logical.width)}x${Math.round(logical.height)} / css ${window.innerWidth}x${window.innerHeight}`);
});
前述の設定ファイルのまま、拡大率 150% の Windows で最小まで縮めると、次のところで止まります。物理ピクセルは 1.5 倍ですが、論理ピクセルと CSS ピクセルは minWidth / minHeight と同じです。
inner 720x540 / logical 480x360 / css 480x360
setSidebar(true) を呼ぶと、狭めていたウィンドウが幅 720 まで広がり、それ以下には縮められなくなります。
よくあるエラーと対処法
- 「window.set_min_size not allowed. Permissions associated with this command: core:window:allow-set-min-size」: 権限の追加漏れです。この文面はデバッグビルドのもので、リリースビルドでは「Command plugin:window|set_min_size not allowed by ACL」だけになります。
setSizeConstraints()ならcore:window:allow-set-size-constraintsを足します。 setSizeConstraints()を呼んだら設定ファイルの最小高さが効かなくなった: 4 つの制限がまとめて置き換わるためです。残したい項目も一緒に渡します。- Rust で
set_min_size(None)がコンパイルできない: 引数の型が決まらないという趣旨のエラーになります。None::<LogicalSize<f64>>のように型を付けます。 - 小さい画面でウィンドウがはみ出す: 最小サイズが作業領域より大きいと、ウィンドウは画面に収まりません。最小サイズを小さめにし、狭い幅のレイアウトは CSS で用意します。
OS ごとの違いと注意点
- 最大化との関係: 最大サイズを付けたウィンドウでも、最大化ボタンを押したときの見え方が意図と違うことがあります。最大化させたくないなら
maximizable: falseを併用します(resizable: falseのときは無視されます)。macOS ではタイトルバーのズームボタンが無効になり、これはフルスクリーンへの入口も兼ねています。Linux・iOS・Android では効きません。 - ページのズーム:
zoomHotkeysEnabledなどでページを拡大すると、CSS ピクセルは論理ピクセルより大きくなります。125% に拡大するとminWidth: 480のウィンドウでも CSS の幅は 384px になるので、ズームを許すなら狭い幅のレイアウトも用意します。 - 大きさの固定: 最小と最大を同じ値にするより
resizable: falseを使います。こちらは最大化ボタンも自動で無効になります。
