チャットの見た目だけでなく、「大きさを変える」「ドラッグで移動する」といった操作性も、HTML/CSS/JavaScriptで簡単に実装できます。
- チャポット: https://chapot.net/
はじめに
チャットボットや埋め込みチャットを作るとき、見た目だけでなく操作性が重要になります。
たとえば、ユーザーがチャットを小さくしたい、右下に寄せたい、必要に応じて最大化したいと考えることがあります。
このようなUIでは、固定サイズのままでは使いづらくなります。そこで、チャットウィンドウに「サイズ変更」と「移動」を追加する設計が役立ちます。
最初の1歩として、チャットの本体をドラッグで動かし、リサイズハンドルでサイズを変更するような基本構造を考えていきます。
実際には、最初から高度な機能を入れようとすると難しくなるので、まずは次の2つだけを意識するとわかりやすくなります。
- どこをドラッグして移動するのか
- どこをドラッグしてサイズを変えるのか
この2つが明確になれば、実装の見通しがかなり良くなります。
まずは構造を考える
チャットウィンドウは、一般的には次のような構造になります。
<div class="chat-window" id="chatWindow">
<div class="chat-header">チャット</div>
<div class="chat-body">
<div class="message user">こんにちは</div>
<div class="message bot">どうできますか?</div>
</div>
<div class="chat-footer">
<input type="text" />
<button>送信</button>
</div>
<div class="resize-handle"></div>
</div>
ここで重要なのは、チャット全体を1つのコンテナとして管理することです。
-
chat-window: ウィンドウ本体 -
chat-header: 上部のヘッダー -
chat-body: メッセージ領域 -
chat-footer: 入力欄 -
resize-handle: リサイズ用ハンドル
これを分けておくと、ドラッグやサイズ変更を実装しやすくなります。
サイズ変更の設計ポイント
チャットウィンドウのサイズ変更は、CSSだけで完結するわけではなく、JavaScriptで位置やサイズを更新する必要があります。
一般的には、右下の角に小さなハンドルを置き、そこをドラッグして幅と高さを変更します。
.chat-window {
position: absolute;
left: 100px;
top: 100px;
width: 360px;
height: 480px;
min-width: 260px;
min-height: 220px;
border: 1px solid #d1d5db;
background: white;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.resize-handle {
position: absolute;
right: 0;
bottom: 0;
width: 18px;
height: 18px;
cursor: nwse-resize;
background: linear-gradient(135deg, transparent 0 50%, #94a3b8 50% 100%);
}
ここでのポイントは、最小サイズを決めておくことです。
もし最小サイズがないと、ユーザーが小さくしすぎて見づらい状態になってしまいます。
-
min-width: 260px -
min-height: 220px
このように制約を入れると、UIが壊れにくくなります。
ドラッグ移動の基本
チャットウィンドウを移動できるようにするには、ドラッグ中の座標差分を計算して、現在位置に加算します。
まずは HTML 側の構造をシンプルに考えます。
<div class="chat-window" id="chatWindow">
<div class="chat-header" id="chatHeader">チャット</div>
<div class="chat-body">...</div>
<div class="resize-handle" id="resizeHandle"></div>
</div>
次に、JavaScriptでドラッグ開始位置を記録します。
const chatWindow = document.getElementById('chatWindow');
const chatHeader = document.getElementById('chatHeader');
let dragging = false;
let dragOffsetX = 0;
let dragOffsetY = 0;
chatHeader.addEventListener('mousedown', (e) => {
dragging = true;
dragOffsetX = e.clientX - chatWindow.offsetLeft;
dragOffsetY = e.clientY - chatWindow.offsetTop;
});
document.addEventListener('mousemove', (e) => {
if (!dragging) return;
const newLeft = e.clientX - dragOffsetX;
const newTop = e.clientY - dragOffsetY;
chatWindow.style.left = `${newLeft}px`;
chatWindow.style.top = `${newTop}px`;
});
document.addEventListener('mouseup', () => {
dragging = false;
});
ここで大事なのは「現在の位置からマウスの差分を引く」ことです。
現在のウィンドウ位置とマウス位置の差を保持しておくと、ドラッグ中でも自然に追従できます。
サイズ変更はマウス位置の差分で計算する
リサイズも移動と同じ考え方です。
右下のハンドルをドラッグしたら、差分を使って幅と高さを更新します。
const resizeHandle = document.getElementById('resizeHandle');
let resizing = false;
let startX = 0;
let startY = 0;
let startWidth = 0;
let startHeight = 0;
resizeHandle.addEventListener('mousedown', (e) => {
resizing = true;
startX = e.clientX;
startY = e.clientY;
startWidth = chatWindow.offsetWidth;
startHeight = chatWindow.offsetHeight;
});
document.addEventListener('mousemove', (e) => {
if (!resizing) return;
const width = startWidth + (e.clientX - startX);
const height = startHeight + (e.clientY - startY);
chatWindow.style.width = `${Math.max(width, 260)}px`;
chatWindow.style.height = `${Math.max(height, 220)}px`;
});
document.addEventListener('mouseup', () => {
resizing = false;
});
この処理で重要なのは、Math.max() を使って最小値を守ることです。
これがあると、チャットが小さくなりすぎて中身が潰れることを防げます。
画面外に出ないように制御する
移動やリサイズをそのまま実装すると、画面外に出てしまうことがあります。
ためしに、ブラウザの画面サイズを超えないように制限を入れるだけでも、使いやすさが大きく変わります。
const maxX = window.innerWidth - chatWindow.offsetWidth;
const maxY = window.innerHeight - chatWindow.offsetHeight;
const clampedX = Math.min(Math.max(newLeft, 0), maxX);
const clampedY = Math.min(Math.max(newTop, 0), maxY);
chatWindow.style.left = `${clampedX}px`;
chatWindow.style.top = `${clampedY}px`;
このように、位置を clamp する考え方がとても有効です。
- 最小値: 0
- 最大値: 画面幅や高さからウィンドウサイズを引いた値
こうすると、ユーザーは画面の外に持ち出すことなく使えるようになります。
画面内で使いやすいように少しだけ考える
ここまでの実装だけでも、チャットを動かしたり拡大縮小したりすることはできます。
ただし、実際のアプリでは次のような細部があるとより実用的です。
- ドラッグ中にカーソルが変わる
- ハンドルの見た目が明確
- 画面の端で止まる
- モバイル端末でも操作できる
たとえば、ドラッグ中に cursor: move や cursor: nwse-resize を使うと、直感的なUIになります。
.chat-header {
cursor: move;
user-select: none;
}
.resize-handle {
cursor: nwse-resize;
}
これだけでも、ユーザーにとって「ここを動かす」「ここを広げる」と伝わりやすくなります。
実装の流れをまとめると
サイズ変更と移動は、実装の流れを整理するとかなりシンプルです。
- ウィンドウの位置とサイズを管理する
- ドラッグ開始時の座標を記録する
- マウス移動中に位置やサイズを更新する
- 最小サイズや画面端の制約を入れる
- UIとして見た目にフィードバックを持たせる
この順番に沿って作ると、非常に理解しやすいです。
まとめ
チャットのサイズ変更と移動は、見た目の設計だけでなく、ユーザー操作の設計が重要です。
-
position: absoluteで自由に配置する - ドラッグ開始位置の差分で位置を更新する
- リサイズも同じく差分で幅と高さを更新する
- 最小サイズと画面端の制約を入れる
- ドラッグ中のカーソルや見た目を明確にする
この考え方ができていれば、チャットウィンドウの動的な操作は、かなりシンプルに実装できます。
次の一歩としては、すでにあるチャットUIにこのリサイズ機能とドラッグ移動を足して、実際に動かしてみるのが最も理解が深まります。
最初は「ドラッグで動かす」「角を引っ張る」の2つだけを実装しておくと、基礎をしっかり固められます。
その上で、必要に応じて最小化、最大化、タブ切り替え、モバイル対応などを足していくと、実務レベルのUIへ発展していきます。
