作成した承認ボタンパーツ
グレーの丸ボタンが、クリックすると赤い印鑑スタンプに変化する承認ボタンです。SVGフィルターで印鑑特有の質感を再現し、ホバー時には立体感のある視覚効果も加えています。
印鑑風承認ボタン
クリックすると承認済みの印鑑スタンプに変化する、インタラクティブなボタンです。
HTML
<svg class="filter-def">
<defs>
<filter id="roughStamp" x="-50%" y="-50%" width="200%" height="200%">
<feTurbulence type="fractalNoise" baseFrequency="0.5" numOctaves="3" seed="17" result="noise1"></feTurbulence>
<feTurbulence type="fractalNoise" baseFrequency="6" numOctaves="2" seed="23" result="noise2"></feTurbulence>
<feBlend in="noise1" in2="noise2" mode="multiply" result="combined"></feBlend>
<feColorMatrix in="combined" type="matrix" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 35 -14" result="threshold"></feColorMatrix>
<feGaussianBlur in="threshold" stdDeviation="1.5" result="smoothed"></feGaussianBlur>
<feTurbulence type="fractalNoise" baseFrequency="1.2" numOctaves="2" seed="5" result="warp"></feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="warp" scale="1.5" xChannelSelector="R" yChannelSelector="G" result="warped"></feDisplacementMap>
<feComposite in="warped" in2="smoothed" operator="in" result="final"></feComposite>
</filter>
<filter id="inkBleed" x="-50%" y="-50%" width="200%" height="200%">
<feTurbulence type="fractalNoise" baseFrequency="0.6" numOctaves="3" seed="29" result="noise1"></feTurbulence>
<feTurbulence type="fractalNoise" baseFrequency="7" numOctaves="2" seed="31" result="noise2"></feTurbulence>
<feBlend in="noise1" in2="noise2" mode="multiply" result="combined"></feBlend>
<feColorMatrix in="combined" type="matrix" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 33 -13" result="threshold"></feColorMatrix>
<feGaussianBlur in="threshold" stdDeviation="1.5" result="smoothed"></feGaussianBlur>
<feComposite in="SourceGraphic" in2="smoothed" operator="in"></feComposite>
</filter>
<filter id="textRough" x="-50%" y="-50%" width="200%" height="200%">
<feTurbulence type="fractalNoise" baseFrequency="0.6" numOctaves="3" seed="41" result="noise1"></feTurbulence>
<feTurbulence type="fractalNoise" baseFrequency="7" numOctaves="2" seed="47" result="noise2"></feTurbulence>
<feBlend in="noise1" in2="noise2" mode="multiply" result="combined"></feBlend>
<feColorMatrix in="combined" type="matrix" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 35 -13" result="threshold"></feColorMatrix>
<feGaussianBlur in="threshold" stdDeviation="1.4" result="smoothed"></feGaussianBlur>
<feTurbulence type="fractalNoise" baseFrequency="1.2" numOctaves="2" seed="13" result="warp"></feTurbulence>
<feDisplacementMap in="SourceGraphic" in2="warp" scale="1.3" xChannelSelector="R" yChannelSelector="G" result="warped"></feDisplacementMap>
<feComposite in="warped" in2="smoothed" operator="in"></feComposite>
</filter>
</defs>
</svg>
<button class="btn" type="button" id="stampBtn" aria-pressed="false">承認</button> CSS
:root {
--ink: #d32f2f;
--btn: #141821;
}
.btn {
appearance: none;
border: none;
background: #d6d6d6;
width: 110px;
height: 110px;
border-radius: 999px;
font-size: 24px;
font-weight: 900;
letter-spacing: 0.1em;
color: rgba(0, 0, 0, 0.5);
cursor: pointer;
transition: all 280ms cubic-bezier(0.16, 1, 0.3, 1);
text-shadow: none;
box-shadow: none;
border-bottom: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
position: relative;
overflow: visible;
}
.btn:focus-visible {
outline: 3px solid rgba(211, 47, 47, 0.4);
outline-offset: 4px;
}
.btn::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
width: 110px;
height: 110px;
transform: translate(-50%, -50%) scale(0.96) rotate(-1deg);
border-radius: 999px;
border: 5px solid rgba(0, 0, 0, 0.15);
opacity: 0;
transition: opacity 280ms cubic-bezier(0.16, 1, 0.3, 1),
transform 280ms cubic-bezier(0.16, 1, 0.3, 1),
border-color 280ms cubic-bezier(0.16, 1, 0.3, 1),
filter 280ms cubic-bezier(0.16, 1, 0.3, 1);
pointer-events: none;
}
.btn:hover:not(.is-stamped) {
background-image: linear-gradient(#e8e8e8 0%, #d6d6d6 100%);
color: rgba(0, 0, 0, 0.4);
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.66);
box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5),
0 2px 2px rgba(0, 0, 0, 0.19);
border-bottom: solid 2px #b5b5b5;
}
.btn:active {
background: #d6d6d6 !important;
color: rgba(0, 0, 0, 0.4) !important;
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.66) !important;
box-shadow: none !important;
border-bottom: none !important;
transform: scale(0.98) translateY(1px) !important;
}
.btn:active::after {
opacity: 0;
}
.btn.is-stamped {
background: transparent;
border: none;
border-bottom: none;
color: var(--ink);
cursor: default;
box-shadow: none;
text-shadow: none;
filter: url(#textRough);
}
.btn.is-stamped::after {
opacity: 0.88;
transform: translate(-50%, -50%) scale(1) rotate(-1deg);
border-color: var(--ink);
filter: url(#roughStamp);
border-style: solid;
border-width: 5px 4px 6px 4px;
}
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0.01ms !important;
}
}
.filter-def {
position: absolute;
width: 0;
height: 0;
pointer-events: none;
} JavaScript
(() => {
const btn = document.getElementById('stampBtn');
if (!btn) return;
btn.addEventListener('click', () => {
if (btn.classList.contains('is-stamped')) return;
btn.classList.add('is-stamped');
btn.setAttribute('aria-pressed', 'true');
btn.disabled = true;
});
})(); AIへのプロンプト例
以下のようなプロンプトをAIに送信します:
button要素を使用して、クリックすると印鑑風のスタンプに変化する承認ボタンを作成してください。
### 初期状態
- グレーの丸いボタン
- 「承認」という文字を中央に配置
- 丸いボタンの形状
### ホバー時
- 立体感のあるグラデーション
- 光沢感のあるテキスト影
- 下部に境界線で押せる印象
### クリック時
- 赤い印鑑風のスタンプに変化
- 印影のようなかすれやにじみを表現
- テキストと枠線に質感を追加
- クリック後は固定され、再度押せない
### その他の要件
- SVGフィルターを使って印鑑特有の質感を表現
- アクセシビリティ対応(aria-pressed属性)
- アニメーション軽減設定に対応
このボタンの特徴
- 印鑑スタンプ効果 SVGフィルターで本物の印鑑のようなかすれとにじみを再現
- 状態の明確化 グレーから赤への変化で承認済みを視覚的に表現
- 立体的なホバー効果 グラデーションと影で押せることを示唆
- 再押下防止 クリック後はボタンを無効化し、誤操作を防止
- アクセシビリティ aria-pressed属性で状態を明示
コードのポイント
SVGフィルターによる印鑑質感の表現
.btn.is-stamped::after {
filter: url(#roughStamp); /* 印鑑のかすれを表現 */
border-color: var(--ink);
opacity: 0.88;
}
.btn.is-stamped {
filter: url(#textRough); /* テキストのにじみを表現 */
color: var(--ink);
} SVGのfeTurbulenceとfeDisplacementMapを組み合わせて、印鑑特有のかすれやにじみを表現しています。
疑似要素による円形の枠線
.btn::after {
content: '';
position: absolute;
width: 110px;
height: 110px;
border-radius: 999px;
border: 5px solid rgba(0, 0, 0, 0.15);
opacity: 0; /* 初期状態では非表示 */
}
.btn.is-stamped::after {
opacity: 0.88; /* スタンプ時に表示 */
transform: translate(-50%, -50%) scale(1) rotate(-1deg);
} ::after疑似要素でボタンの上に円形の枠線を配置し、クリック時に印鑑の外枠として表示します。
JavaScriptによる状態管理
btn.addEventListener('click', () => {
if (btn.classList.contains('is-stamped')) return; // 既に押されていたら何もしない
btn.classList.add('is-stamped'); // スタンプ状態にする
btn.setAttribute('aria-pressed', 'true'); // アクセシビリティ対応
btn.disabled = true; // ボタンを無効化
}); クリック時にis-stampedクラスを追加してスタンプ状態に変化させ、disabled属性で再押下を防止します。
まとめ
- SVGフィルター
feTurbulenceとfeDisplacementMapで印鑑のかすれとにじみを再現 - 疑似要素の活用
::afterで印鑑の外枠を作り、クリック時に表示 - 状態管理
is-stampedクラスで視覚的な変化を制御 - 再押下防止
disabled属性で誤操作を防止 - アクセシビリティ
aria-pressed属性でスクリーンリーダーに状態を伝達
承認フローやワークフローUIに最適なインタラクティブボタンです。SVGフィルターを使った高度な視覚効果と、適切な状態管理を学びました。