はじめに
友人との共同開発時に使用したホバー時に形が変わるメールアイコンを作成したので、その作り方を紹介します。この方法を覚えれば、メールアイコン以外にもホバー時に変化させることができます。
実装
準備
Iconには Lucide Icon を使用しました。以下のコマンドでインストールしてください。
pnpm install lucide-react
Lucide の詳しい使い方はこちらをご覧ください。
要件定義
- ホバーするとメールが開くような演出
- 通知の数がわかるように左上に赤丸の数字
- サイズとカウントを Props として渡せるようにする
コード
'use client'
import React, { useState } from 'react';
import { Mail, MailOpen } from 'lucide-react';
interface MailIconProps {
count?: number;
size?: number;
}
export const MailIcon = (p: MailIconProps) => {
const [hovered, setHovered] = useState(false);
const count = p.count || 0;
const iconSize = p.size || 24;
const badgeSize = Math.max(iconSize * 0.45, 16);
const fontSize = Math.max(iconSize * 0.25, 10);
const offset = Math.max(iconSize * 0.2, 6);
return (
<div>
<div
style={{ position: 'relative', display: 'inline-block' }}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
{hovered ? (
<MailOpen size={iconSize} />
) : (
<Mail size={iconSize} />
)}
{count > 0 && (
<div
style={{
position: 'absolute',
top: -offset,
right: -offset,
backgroundColor: '#E74C3C',
color: 'white',
borderRadius: '50%',
padding: '2px',
fontSize: `${fontSize}px`,
minWidth: `${badgeSize}px`,
height: `${badgeSize}px`,
lineHeight: `${badgeSize - 4}px`,
textAlign: 'center'
}}
>
{count >= 100 ? '99+' : count}
</div>
)}
</div>
</div>
);
};
コードの説明
-
コンポーネントの入力の定義
メール数とアイコンサイズを定義します。
?
はオプショナルといい、入力があってもなくてもいいことを示します。interface MailIconProps { count?: number; // メール数 size?: number; // アイコンサイズ }
-
状態管理
ホバー状態の管理や、カウント・サイズの初期値設定を行います。
const [hovered, setHovered] = useState(false); // ホバー状態の管理 const count = p.count || 0; // カウント未指定時は0 const iconSize = p.size || 24; // サイズ未指定時は24px
-
サイズ計算
通知バッジのサイズ計算をします。
const badgeSize = Math.max(iconSize * 0.45, 16); // バッジの大きさ(最小16px) const fontSize = Math.max(iconSize * 0.25, 10); // フォントサイズ(最小10px) const offset = Math.max(iconSize * 0.2, 6); // オフセット(最小6px)
-
アイコンのレンダリング
React での hover 管理は
onMouseEnter
がホバーされた時の動作で、onMouseLeave
はホバーが離れた時の動作を表します。<div style={{ position: 'relative', display: 'inline-block' }} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} > {hovered ? ( <MailOpen size={iconSize} /> ) : ( <Mail size={iconSize} /> )}
-
通知バッジのレンダリング
メールがある時だけバッジを表示し、100 以上は '99+' と表示してスタイルを崩さないようにしています。
{count > 0 && ( // カウントが0より大きい時だけバッジを表示 <div style={{ position: 'absolute', top: -offset, // 上方向にオフセット right: -offset, // 右方向にオフセット backgroundColor: '#E74C3C', // 赤色背景 color: 'white', // 白文字 borderRadius: '50%', // 円形に padding: '4px', fontSize: `${fontSize}px`, minWidth: `${badgeSize}px`, height: `${badgeSize}px`, lineHeight: `${badgeSize - 8}px`, // 縦方向の中央揃えpadding分の8px textAlign: 'center' // 横方向の中央揃え }} > {count >= 100 ? '99+' : count} // 100以上の場合は'99+'と表示 </div> )}
-
コンポーネントの使用例
<MailIcon count={5} size={32} />
また、このようにすると画面遷移のアイコンとして利用できます。
<a href="/mail"> <MailIcon count={ notificationNumber } size={ iconSize }/> </a>
結果
まとめ
今回は、ホバー時に形が変わる通知付きのメールアイコンの作り方を紹介しました。細かい点ではありますが、少しでもアニメーションがあると楽しくなりますよね。メールアイコン以外にも、同様の手法が使えると思います。
それでは、みなさんよいエンジニアライフを〜👋