Floating Card Cookie Consent Banner
An elegant floating card-style cookie consent banner with smooth animations, hover effects, and modern card design patterns
Responsive Design
Yes
Dark Mode Support
No
lines
1125
Browser Compatibility
No
Live Preview
Interact with the component without leaving the page.
Floating Card Cookie Consent Banner
A beautifully designed floating card-style cookie consent banner that appears with smooth animations and elegant hover effects. Features a modern card design with subtle shadows, rounded corners, and interactive elements that enhance user engagement.
Features
- Floating Card Design: Elegant card-style layout with subtle shadows and rounded corners
- Smooth Animations: Fluid entrance animations and micro-interactions
- Hover Effects: Interactive hover states with scale and shadow transitions
- Modern Typography: Clean, readable fonts with proper hierarchy
- GDPR Compliant: Complete consent management with granular controls
- Accessibility First: Full keyboard navigation and screen reader support
- Responsive Design: Adapts beautifully to all screen sizes and orientations
- Customizable Styling: Easy theme customization with CSS variables
- Performance Optimized: Lightweight and fast-loading implementation
Preview
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Floating Card Cookie Banner</title>
<style>
:root {
--primary-color: #3b82f6;
--primary-hover: #2563eb;
--secondary-color: #6b7280;
--success-color: #10b981;
--success-hover: #059669;
--danger-color: #ef4444;
--danger-hover: #dc2626;
--background: #ffffff;
--surface: #f8fafc;
--text-primary: #1f2937;
--text-secondary: #6b7280;
--text-muted: #9ca3af;
--border-color: #e5e7eb;
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--border-radius: 12px;
--border-radius-lg: 16px;
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: var(--text-primary);
line-height: 1.6;
padding: 2rem;
}
.demo-container {
max-width: 1200px;
margin: 0 auto;
text-align: center;
color: white;
}
.demo-container h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.demo-container p {
font-size: 1.2rem;
opacity: 0.9;
margin-bottom: 2rem;
}
.demo-btn {
padding: 1rem 2rem;
border: none;
border-radius: var(--border-radius);
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
color: white;
font-family: inherit;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.demo-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}.floating-cookie-banner {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 420px;
max-width: calc(100vw - 4rem);
background: var(--background);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-xl);
border: 1px solid var(--border-color);
overflow: hidden;
transform: translateY(120%) scale(0.8);
opacity: 0;
transition: var(--transition);
z-index: 10000;
backdrop-filter: blur(20px);
}
.floating-cookie-banner.show {
transform: translateY(0) scale(1);
opacity: 1;
}
.floating-cookie-banner:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
.banner-header {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
padding: 1.5rem;
color: white;
position: relative;
overflow: hidden;
}
.banner-header::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
.banner-icon {
width: 48px;
height: 48px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
margin-bottom: 1rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.banner-title {
font-size: 1.25rem;
font-weight: 700;
margin-bottom: 0.5rem;
position: relative;
z-index: 1;
}
.banner-subtitle {
font-size: 0.9rem;
opacity: 0.9;
position: relative;
z-index: 1;
}
.banner-content {
padding: 1.5rem;
}
.cookie-description {
color: var(--text-secondary);
font-size: 0.95rem;
line-height: 1.6;
margin-bottom: 1.5rem;
}
.cookie-link {
color: var(--primary-color);
text-decoration: none;
font-weight: 600;
transition: var(--transition-fast);
position: relative;
}
.cookie-link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: var(--primary-color);
transition: width 0.3s ease;
}
.cookie-link:hover {
color: var(--primary-hover);
}
.cookie-link:hover::after {
width: 100%;
}
.cookie-actions {
display: flex;
gap: 0.75rem;
margin-top: 1.5rem;
}.card-btn {
flex: 1;
padding: 0.75rem 1rem;
border: none;
border-radius: var(--border-radius);
font-family: inherit;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
position: relative;
overflow: hidden;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.card-btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s ease, height 0.6s ease;
}
.card-btn:hover::before {
width: 300px;
height: 300px;
}
.btn-accept {
background: var(--success-color);
color: white;
box-shadow: var(--shadow-md);
}
.btn-accept:hover {
background: var(--success-hover);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.btn-decline {
background: var(--danger-color);
color: white;
box-shadow: var(--shadow-md);
}
.btn-decline:hover {
background: var(--danger-hover);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.btn-settings {
background: var(--surface);
color: var(--text-primary);
border: 1px solid var(--border-color);
box-shadow: var(--shadow-sm);
}
.btn-settings:hover {
background: var(--border-color);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.card-btn:active {
transform: translateY(0);
}.cookie-settings-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
z-index: 10001;
opacity: 0;
visibility: hidden;
transition: var(--transition);
}
.cookie-settings-modal.show {
opacity: 1;
visibility: visible;
}
.settings-card {
background: var(--background);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-xl);
border: 1px solid var(--border-color);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow: hidden;
transform: scale(0.9) translateY(20px);
transition: var(--transition);
}
.cookie-settings-modal.show .settings-card {
transform: scale(1) translateY(0);
}
.settings-header {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
padding: 2rem;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.settings-title {
font-size: 1.5rem;
font-weight: 700;
}
.close-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
color: white;
font-size: 1.25rem;
cursor: pointer;
transition: var(--transition-fast);
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
}
.close-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.1) rotate(90deg);
}
.settings-body {
padding: 2rem;
max-height: 60vh;
overflow-y: auto;
}
.cookie-category {
margin-bottom: 2rem;
padding: 1.5rem;
background: var(--surface);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
transition: var(--transition-fast);
}
.cookie-category:hover {
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.category-title {
font-weight: 700;
font-size: 1.1rem;
color: var(--text-primary);
}
.category-description {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.6;
}.card-toggle {
position: relative;
width: 56px;
height: 28px;
background: var(--border-color);
border-radius: 14px;
cursor: pointer;
transition: var(--transition);
border: 2px solid transparent;
}
.card-toggle.active {
background: var(--success-color);
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
}
.card-toggle::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
transition: var(--transition);
box-shadow: var(--shadow-sm);
}
.card-toggle.active::before {
transform: translateX(28px);
box-shadow: var(--shadow-md);
}
.card-toggle:hover {
transform: scale(1.05);
}
.settings-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
padding: 1.5rem 2rem;
background: var(--surface);
border-top: 1px solid var(--border-color);
}@media (max-width: 768px) {
.floating-cookie-banner {
bottom: 1rem;
right: 1rem;
left: 1rem;
width: auto;
max-width: none;
}
.floating-cookie-banner:hover {
transform: translateY(-2px) scale(1.01);
}
.cookie-actions {
flex-direction: column;
}
.card-btn {
flex: none;
}
.settings-card {
margin: 1rem;
width: calc(100% - 2rem);
}
.settings-header {
padding: 1.5rem;
}
.settings-body {
padding: 1.5rem;
}
.settings-actions {
padding: 1rem 1.5rem;
flex-direction: column;
}
}
@media (max-width: 480px) {
body {
padding: 1rem;
}
.demo-container h1 {
font-size: 2rem;
}
.floating-cookie-banner {
bottom: 0.5rem;
right: 0.5rem;
left: 0.5rem;
}
.banner-header {
padding: 1rem;
}
.banner-content {
padding: 1rem;
}
}.loading-dots {
display: inline-flex;
gap: 4px;
}
.loading-dots span {
width: 6px;
height: 6px;
background: currentColor;
border-radius: 50%;
animation: loading 1.4s infinite ease-in-out;
}
.loading-dots span:nth-child(1) { animation-delay: -0.32s; }
.loading-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes loading {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}.success-checkmark {
width: 20px;
height: 20px;
border-radius: 50%;
display: inline-block;
stroke-width: 2;
stroke: currentColor;
stroke-miterlimit: 10;
box-shadow: inset 0px 0px 0px currentColor;
animation: fill 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both;
}
.success-checkmark-circle {
stroke-dasharray: 166;
stroke-dashoffset: 166;
stroke-width: 2;
stroke-miterlimit: 10;
stroke: currentColor;
fill: none;
animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
}
.success-checkmark-check {
transform-origin: 50% 50%;
stroke-dasharray: 48;
stroke-dashoffset: 48;
animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
}
@keyframes stroke {
100% {
stroke-dashoffset: 0;
}
}
@keyframes scale {
0%, 100% {
transform: none;
}
50% {
transform: scale3d(1.1, 1.1, 1);
}
}
@keyframes fill {
100% {
box-shadow: inset 0px 0px 0px 30px currentColor;
}
}
</style>
</head>
<body>
<div class="demo-container">
<h1>Floating Card Design</h1>
<p>Experience the elegance of floating card design with smooth animations and modern interactions</p>
<button class="demo-btn" onclick="showCookieBanner()">Show Cookie Banner</button>
</div>
<div id="floatingCookieBanner" class="floating-cookie-banner">
<div class="banner-header">
<div class="banner-icon">🍪</div>
<div class="banner-title">Cookie Preferences</div>
<div class="banner-subtitle">We value your privacy</div>
</div>
<div class="banner-content">
<div class="cookie-description">
We use cookies to enhance your browsing experience and provide personalized content.
<a href="#" class="cookie-link">Privacy Policy</a> |
<a href="#" class="cookie-link">Cookie Policy</a>
</div>
<div class="cookie-actions">
<button class="card-btn btn-accept" onclick="acceptCookies()">Accept All</button>
<button class="card-btn btn-decline" onclick="declineCookies()">Decline</button>
<button class="card-btn btn-settings" onclick="openSettings()">Customize</button>
</div>
</div>
</div>
<div id="cookieSettingsModal" class="cookie-settings-modal">
<div class="settings-card">
<div class="settings-header">
<h3 class="settings-title">Cookie Settings</h3>
<button class="close-btn" onclick="closeSettings()">×</button>
</div>
<div class="settings-body">
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Essential Cookies</span>
<div class="card-toggle active" data-category="essential"></div>
</div>
<div class="category-description">
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Analytics Cookies</span>
<div class="card-toggle" data-category="analytics"></div>
</div>
<div class="category-description">
These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Marketing Cookies</span>
<div class="card-toggle" data-category="marketing"></div>
</div>
<div class="category-description">
These cookies are used to deliver advertisements more relevant to you and your interests based on your browsing behavior.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Functional Cookies</span>
<div class="card-toggle" data-category="functional"></div>
</div>
<div class="category-description">
These cookies enable enhanced functionality and personalization, such as remembering your preferences and settings.
</div>
</div>
</div>
<div class="settings-actions">
<button class="card-btn btn-decline" onclick="saveSettings(false)">Save Preferences</button>
<button class="card-btn btn-accept" onclick="saveSettings(true)">Accept All</button>
</div>
</div>
</div>
<script>
class FloatingCardCookieBanner {
constructor(options = {}) {
this.options = {
autoShow: true,
showDelay: 1500,
storageKey: 'floating_card_cookie_consent',
expiryDays: 365,
enableAnimations: true,
position: 'bottom-right',
onAccept: null,
onDecline: null,
onSettingsSave: null,
...options
};
this.banner = document.getElementById('floatingCookieBanner');
this.modal = document.getElementById('cookieSettingsModal');
this.consent = this.getStoredConsent();
this.isVisible = false;
this.init();
}
init() {
if (this.options.autoShow && !this.consent) {
setTimeout(() => this.show(), this.options.showDelay);
}
this.setupEventListeners();
this.loadSettings();
this.setupPosition();
}
setupEventListeners() {
document.querySelectorAll('.card-toggle').forEach(toggle => {
toggle.addEventListener('click', () => {
if (toggle.dataset.category !== 'essential') {
toggle.classList.toggle('active');
this.animateToggle(toggle);
}
});
});
this.modal.addEventListener('click', (e) => {
if (e.target === this.modal) {
this.closeSettings();
}
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.closeSettings();
}
});
document.querySelectorAll('.card-btn').forEach(btn => {
btn.addEventListener('mouseenter', () => {
this.createRipple(btn);
});
});
this.banner.addEventListener('mouseenter', () => {
if (this.isVisible) {
this.enhanceHoverEffect();
}
});
this.banner.addEventListener('mouseleave', () => {
if (this.isVisible) {
this.resetHoverEffect();
}
});
}
setupPosition() {
const positions = {
'bottom-right': { bottom: '2rem', right: '2rem', left: 'auto', top: 'auto' },
'bottom-left': { bottom: '2rem', left: '2rem', right: 'auto', top: 'auto' },
'top-right': { top: '2rem', right: '2rem', left: 'auto', bottom: 'auto' },
'top-left': { top: '2rem', left: '2rem', right: 'auto', bottom: 'auto' }
};
const pos = positions[this.options.position] || positions['bottom-right'];
Object.assign(this.banner.style, pos);
}
animateToggle(toggle) {
if (!this.options.enableAnimations) return;
toggle.style.transform = 'scale(0.9)';
setTimeout(() => {
toggle.style.transform = 'scale(1)';
}, 150);
toggle.style.boxShadow = '0 0 0 8px rgba(16, 185, 129, 0.2)';
setTimeout(() => {
toggle.style.boxShadow = '';
}, 300);
}
createRipple(button) {
if (!this.options.enableAnimations) return;
const ripple = document.createElement('span');
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = '50%';
ripple.style.top = '50%';
ripple.style.transform = 'translate(-50%, -50%) scale(0)';
ripple.style.position = 'absolute';
ripple.style.borderRadius = '50%';
ripple.style.background = 'rgba(255, 255, 255, 0.3)';
ripple.style.pointerEvents = 'none';
ripple.style.animation = 'ripple 0.6s ease-out';
button.style.position = 'relative';
button.style.overflow = 'hidden';
button.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
}
enhanceHoverEffect() {
if (!this.options.enableAnimations) return;
const icon = this.banner.querySelector('.banner-icon');
if (icon) {
icon.style.transform = 'scale(1.1) rotate(5deg)';
}
}
resetHoverEffect() {
if (!this.options.enableAnimations) return;
const icon = this.banner.querySelector('.banner-icon');
if (icon) {
icon.style.transform = '';
}
}
show() {
this.banner.classList.add('show');
this.isVisible = true;
if (this.options.enableAnimations) {
this.animateEntrance();
}
}
hide() {
this.banner.classList.remove('show');
this.isVisible = false;
}
animateEntrance() {
const elements = [
this.banner.querySelector('.banner-icon'),
this.banner.querySelector('.banner-title'),
this.banner.querySelector('.banner-subtitle'),
this.banner.querySelector('.cookie-description'),
this.banner.querySelector('.cookie-actions')
];
elements.forEach((el, index) => {
if (el) {
el.style.opacity = '0';
el.style.transform = 'translateY(20px)';
setTimeout(() => {
el.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
}, index * 100);
}
});
}
accept() {
const consent = {
essential: true,
analytics: true,
marketing: true,
functional: true,
timestamp: Date.now()
};
this.saveConsent(consent);
this.showSuccessAnimation();
setTimeout(() => {
this.hide();
}, 1500);
if (this.options.onAccept) {
this.options.onAccept(consent);
}
}
decline() {
const consent = {
essential: true,
analytics: false,
marketing: false,
functional: false,
timestamp: Date.now()
};
this.saveConsent(consent);
this.hide();
if (this.options.onDecline) {
this.options.onDecline(consent);
}
}
showSuccessAnimation() {
if (!this.options.enableAnimations) return;
const acceptBtn = this.banner.querySelector('.btn-accept');
if (acceptBtn) {
acceptBtn.innerHTML = `
<svg class="success-checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
<circle class="success-checkmark-circle" cx="26" cy="26" r="25" fill="none"/>
<path class="success-checkmark-check" fill="none" d="m14.1 27.2l7.1 7.2 16.7-16.8"/>
</svg>
Accepted
`;
acceptBtn.style.background = 'var(--success-color)';
}
}
openSettings() {
this.modal.classList.add('show');
document.body.style.overflow = 'hidden';
if (this.options.enableAnimations) {
this.animateModalEntrance();
}
}
closeSettings() {
this.modal.classList.remove('show');
document.body.style.overflow = '';
}
animateModalEntrance() {
const categories = this.modal.querySelectorAll('.cookie-category');
categories.forEach((category, index) => {
category.style.opacity = '0';
category.style.transform = 'translateX(-20px)';
setTimeout(() => {
category.style.transition = 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)';
category.style.opacity = '1';
category.style.transform = 'translateX(0)';
}, index * 100);
});
}
saveSettings(acceptAll = false) {
const toggles = document.querySelectorAll('.card-toggle');
const consent = { timestamp: Date.now() };
toggles.forEach(toggle => {
const category = toggle.dataset.category;
if (acceptAll) {
consent[category] = true;
toggle.classList.add('active');
} else {
consent[category] = toggle.classList.contains('active');
}
});
this.saveConsent(consent);
this.closeSettings();
this.hide();
if (this.options.onSettingsSave) {
this.options.onSettingsSave(consent);
}
}
loadSettings() {
if (this.consent) {
document.querySelectorAll('.card-toggle').forEach(toggle => {
const category = toggle.dataset.category;
if (this.consent[category]) {
toggle.classList.add('active');
} else {
toggle.classList.remove('active');
}
});
}
}
saveConsent(consent) {
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + this.options.expiryDays);
const consentData = {
...consent,
expiry: expiryDate.getTime()
};
localStorage.setItem(this.options.storageKey, JSON.stringify(consentData));
this.consent = consent;
}
getStoredConsent() {
try {
const stored = localStorage.getItem(this.options.storageKey);
if (stored) {
const data = JSON.parse(stored);
if (data.expiry && Date.now() < data.expiry) {
return data;
} else {
localStorage.removeItem(this.options.storageKey);
}
}
} catch (e) {
console.error('Error reading cookie consent:', e);
}
return null;
}
reset() {
localStorage.removeItem(this.options.storageKey);
this.consent = null;
this.show();
}
getConsent() {
return this.consent;
}
setPosition(position) {
this.options.position = position;
this.setupPosition();
}
enableAnimations(enabled) {
this.options.enableAnimations = enabled;
}
updateTheme(theme) {
const themes = {
light: {
'--background': '#ffffff',
'--surface': '#f8fafc',
'--text-primary': '#1f2937',
'--text-secondary': '#6b7280'
},
dark: {
'--background': '#1f2937',
'--surface': '#374151',
'--text-primary': '#f9fafb',
'--text-secondary': '#d1d5db'
}
};
if (themes[theme]) {
Object.entries(themes[theme]).forEach(([property, value]) => {
document.documentElement.style.setProperty(property, value);
});
}
}
}
const style = document.createElement('style');
style.textContent = `
@keyframes ripple {
to {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}
`;
document.head.appendChild(style);
const cookieBanner = new FloatingCardCookieBanner({
position: 'bottom-right',
enableAnimations: true,
onAccept: (consent) => {
console.log('Cookies accepted:', consent);
},
onDecline: (consent) => {
console.log('Cookies declined:', consent);
},
onSettingsSave: (consent) => {
console.log('Settings saved:', consent);
}
});
function showCookieBanner() {
cookieBanner.reset();
}
function acceptCookies() {
cookieBanner.accept();
}
function declineCookies() {
cookieBanner.decline();
}
function openSettings() {
cookieBanner.openSettings();
}
function closeSettings() {
cookieBanner.closeSettings();
}
function saveSettings(acceptAll) {
cookieBanner.saveSettings(acceptAll);
}
</script>
</body>
</html>
Usage
Basic Implementation
const cookieBanner = new FloatingCardCookieBanner();
const cookieBanner = new FloatingCardCookieBanner({
autoShow: true,
showDelay: 2000,
storageKey: 'my_cookie_consent',
expiryDays: 180,
enableAnimations: true,
position: 'bottom-left',
onAccept: (consent) => {
console.log('User accepted cookies:', consent);
if (consent.analytics) {
loadGoogleAnalytics();
}
if (consent.marketing) {
loadMarketingPixels();
}
},
onDecline: (consent) => {
console.log('User declined cookies:', consent);
},
onSettingsSave: (consent) => {
console.log('User saved custom settings:', consent);
}
});
Advanced Configuration
const advancedBanner = new FloatingCardCookieBanner({
autoShow: false, // Manual control
showDelay: 0,
storageKey: 'advanced_consent',
expiryDays: 90,
enableAnimations: true,
position: 'top-right',
onAccept: (consent) => {
initializeAdvancedTracking(consent);
},
onDecline: (consent) => {
initializeEssentialOnly();
},
onSettingsSave: (consent) => {
loadScriptsBasedOnConsent(consent);
}
});
function changePosition(position) {
advancedBanner.setPosition(position);
}
function toggleAnimations(enabled) {
advancedBanner.enableAnimations(enabled);
}
function switchTheme(theme) {
advancedBanner.updateTheme(theme);
}
function showConsentBanner() {
advancedBanner.show();
}
function checkConsentStatus() {
const consent = advancedBanner.getConsent();
if (consent) {
console.log('Current consent:', consent);
} else {
console.log('No consent given yet');
}
}
API Methods
Core Methods
show()- Display the cookie bannerhide()- Hide the cookie banneraccept()- Accept all cookies and hide bannerdecline()- Decline optional cookies and hide bannerreset()- Clear stored consent and show banner again
Settings Management
openSettings()- Open the settings modalcloseSettings()- Close the settings modalsaveSettings(acceptAll)- Save current settingsloadSettings()- Load and apply stored settings
Data Management
getConsent()- Get current consent objectsaveConsent(consent)- Save consent to storagegetStoredConsent()- Retrieve consent from storage
Customization
setPosition(position)- Change banner positionenableAnimations(enabled)- Enable/disable animationsupdateTheme(theme)- Switch between light/dark themescreateRipple(button)- Create ripple effects on buttons
Customization Options
Visual Customization
- Color Schemes: Modify CSS custom properties for different color themes
- Animation Speed: Adjust transition durations and animation timings
- Card Styling: Customize border radius, shadows, and spacing
- Typography: Change font families, sizes, and weights
Functional Configuration
- Auto Display: Control automatic banner appearance
- Storage Duration: Set cookie consent expiration period
- Delay Settings: Configure show/hide timing
- Callback Functions: Custom handlers for user actions
Accessibility Features
- Keyboard Navigation: Full keyboard support with focus indicators
- Screen Reader Support: Proper ARIA labels and descriptions
- High Contrast: Enhanced visibility for accessibility
- Focus Management: Proper focus trapping in modal
Browser Compatibility
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
- Mobile browsers (iOS Safari 12+, Chrome Mobile 60+)
License
MIT License - free to use in personal and commercial projects.
HTML
1095
lines
JavaScript
30
lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Floating Card Cookie Banner</title>
<style>
:root {
--primary-color: #3b82f6;
--primary-hover: #2563eb;
--secondary-color: #6b7280;
--success-color: #10b981;
--success-hover: #059669;
--danger-color: #ef4444;
--danger-hover: #dc2626;
--background: #ffffff;
--surface: #f8fafc;
--text-primary: #1f2937;
--text-secondary: #6b7280;
--text-muted: #9ca3af;
--border-color: #e5e7eb;
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--border-radius: 12px;
--border-radius-lg: 16px;
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: var(--text-primary);
line-height: 1.6;
padding: 2rem;
}
.demo-container {
max-width: 1200px;
margin: 0 auto;
text-align: center;
color: white;
}
.demo-container h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.demo-container p {
font-size: 1.2rem;
opacity: 0.9;
margin-bottom: 2rem;
}
.demo-btn {
padding: 1rem 2rem;
border: none;
border-radius: var(--border-radius);
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
color: white;
font-family: inherit;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.demo-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}.floating-cookie-banner {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 420px;
max-width: calc(100vw - 4rem);
background: var(--background);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-xl);
border: 1px solid var(--border-color);
overflow: hidden;
transform: translateY(120%) scale(0.8);
opacity: 0;
transition: var(--transition);
z-index: 10000;
backdrop-filter: blur(20px);
}
.floating-cookie-banner.show {
transform: translateY(0) scale(1);
opacity: 1;
}
.floating-cookie-banner:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
.banner-header {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
padding: 1.5rem;
color: white;
position: relative;
overflow: hidden;
}
.banner-header::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
.banner-icon {
width: 48px;
height: 48px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
margin-bottom: 1rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.banner-title {
font-size: 1.25rem;
font-weight: 700;
margin-bottom: 0.5rem;
position: relative;
z-index: 1;
}
.banner-subtitle {
font-size: 0.9rem;
opacity: 0.9;
position: relative;
z-index: 1;
}
.banner-content {
padding: 1.5rem;
}
.cookie-description {
color: var(--text-secondary);
font-size: 0.95rem;
line-height: 1.6;
margin-bottom: 1.5rem;
}
.cookie-link {
color: var(--primary-color);
text-decoration: none;
font-weight: 600;
transition: var(--transition-fast);
position: relative;
}
.cookie-link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: var(--primary-color);
transition: width 0.3s ease;
}
.cookie-link:hover {
color: var(--primary-hover);
}
.cookie-link:hover::after {
width: 100%;
}
.cookie-actions {
display: flex;
gap: 0.75rem;
margin-top: 1.5rem;
}.card-btn {
flex: 1;
padding: 0.75rem 1rem;
border: none;
border-radius: var(--border-radius);
font-family: inherit;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
position: relative;
overflow: hidden;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.card-btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s ease, height 0.6s ease;
}
.card-btn:hover::before {
width: 300px;
height: 300px;
}
.btn-accept {
background: var(--success-color);
color: white;
box-shadow: var(--shadow-md);
}
.btn-accept:hover {
background: var(--success-hover);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.btn-decline {
background: var(--danger-color);
color: white;
box-shadow: var(--shadow-md);
}
.btn-decline:hover {
background: var(--danger-hover);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.btn-settings {
background: var(--surface);
color: var(--text-primary);
border: 1px solid var(--border-color);
box-shadow: var(--shadow-sm);
}
.btn-settings:hover {
background: var(--border-color);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.card-btn:active {
transform: translateY(0);
}.cookie-settings-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
z-index: 10001;
opacity: 0;
visibility: hidden;
transition: var(--transition);
}
.cookie-settings-modal.show {
opacity: 1;
visibility: visible;
}
.settings-card {
background: var(--background);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-xl);
border: 1px solid var(--border-color);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow: hidden;
transform: scale(0.9) translateY(20px);
transition: var(--transition);
}
.cookie-settings-modal.show .settings-card {
transform: scale(1) translateY(0);
}
.settings-header {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
padding: 2rem;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.settings-title {
font-size: 1.5rem;
font-weight: 700;
}
.close-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
color: white;
font-size: 1.25rem;
cursor: pointer;
transition: var(--transition-fast);
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
}
.close-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.1) rotate(90deg);
}
.settings-body {
padding: 2rem;
max-height: 60vh;
overflow-y: auto;
}
.cookie-category {
margin-bottom: 2rem;
padding: 1.5rem;
background: var(--surface);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
transition: var(--transition-fast);
}
.cookie-category:hover {
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.category-title {
font-weight: 700;
font-size: 1.1rem;
color: var(--text-primary);
}
.category-description {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.6;
}.card-toggle {
position: relative;
width: 56px;
height: 28px;
background: var(--border-color);
border-radius: 14px;
cursor: pointer;
transition: var(--transition);
border: 2px solid transparent;
}
.card-toggle.active {
background: var(--success-color);
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
}
.card-toggle::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
transition: var(--transition);
box-shadow: var(--shadow-sm);
}
.card-toggle.active::before {
transform: translateX(28px);
box-shadow: var(--shadow-md);
}
.card-toggle:hover {
transform: scale(1.05);
}
.settings-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
padding: 1.5rem 2rem;
background: var(--surface);
border-top: 1px solid var(--border-color);
}@media (max-width: 768px) {
.floating-cookie-banner {
bottom: 1rem;
right: 1rem;
left: 1rem;
width: auto;
max-width: none;
}
.floating-cookie-banner:hover {
transform: translateY(-2px) scale(1.01);
}
.cookie-actions {
flex-direction: column;
}
.card-btn {
flex: none;
}
.settings-card {
margin: 1rem;
width: calc(100% - 2rem);
}
.settings-header {
padding: 1.5rem;
}
.settings-body {
padding: 1.5rem;
}
.settings-actions {
padding: 1rem 1.5rem;
flex-direction: column;
}
}
@media (max-width: 480px) {
body {
padding: 1rem;
}
.demo-container h1 {
font-size: 2rem;
}
.floating-cookie-banner {
bottom: 0.5rem;
right: 0.5rem;
left: 0.5rem;
}
.banner-header {
padding: 1rem;
}
.banner-content {
padding: 1rem;
}
}.loading-dots {
display: inline-flex;
gap: 4px;
}
.loading-dots span {
width: 6px;
height: 6px;
background: currentColor;
border-radius: 50%;
animation: loading 1.4s infinite ease-in-out;
}
.loading-dots span:nth-child(1) { animation-delay: -0.32s; }
.loading-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes loading {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}.success-checkmark {
width: 20px;
height: 20px;
border-radius: 50%;
display: inline-block;
stroke-width: 2;
stroke: currentColor;
stroke-miterlimit: 10;
box-shadow: inset 0px 0px 0px currentColor;
animation: fill 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both;
}
.success-checkmark-circle {
stroke-dasharray: 166;
stroke-dashoffset: 166;
stroke-width: 2;
stroke-miterlimit: 10;
stroke: currentColor;
fill: none;
animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
}
.success-checkmark-check {
transform-origin: 50% 50%;
stroke-dasharray: 48;
stroke-dashoffset: 48;
animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
}
@keyframes stroke {
100% {
stroke-dashoffset: 0;
}
}
@keyframes scale {
0%, 100% {
transform: none;
}
50% {
transform: scale3d(1.1, 1.1, 1);
}
}
@keyframes fill {
100% {
box-shadow: inset 0px 0px 0px 30px currentColor;
}
}
</style>
</head>
<body>
<div class="demo-container">
<h1>Floating Card Design</h1>
<p>Experience the elegance of floating card design with smooth animations and modern interactions</p>
<button class="demo-btn" onclick="showCookieBanner()">Show Cookie Banner</button>
</div>
<div id="floatingCookieBanner" class="floating-cookie-banner">
<div class="banner-header">
<div class="banner-icon">🍪</div>
<div class="banner-title">Cookie Preferences</div>
<div class="banner-subtitle">We value your privacy</div>
</div>
<div class="banner-content">
<div class="cookie-description">
We use cookies to enhance your browsing experience and provide personalized content.
<a href="#" class="cookie-link">Privacy Policy</a> |
<a href="#" class="cookie-link">Cookie Policy</a>
</div>
<div class="cookie-actions">
<button class="card-btn btn-accept" onclick="acceptCookies()">Accept All</button>
<button class="card-btn btn-decline" onclick="declineCookies()">Decline</button>
<button class="card-btn btn-settings" onclick="openSettings()">Customize</button>
</div>
</div>
</div>
<div id="cookieSettingsModal" class="cookie-settings-modal">
<div class="settings-card">
<div class="settings-header">
<h3 class="settings-title">Cookie Settings</h3>
<button class="close-btn" onclick="closeSettings()">×</button>
</div>
<div class="settings-body">
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Essential Cookies</span>
<div class="card-toggle active" data-category="essential"></div>
</div>
<div class="category-description">
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Analytics Cookies</span>
<div class="card-toggle" data-category="analytics"></div>
</div>
<div class="category-description">
These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Marketing Cookies</span>
<div class="card-toggle" data-category="marketing"></div>
</div>
<div class="category-description">
These cookies are used to deliver advertisements more relevant to you and your interests based on your browsing behavior.
</div>
</div>
<div class="cookie-category">
<div class="category-header">
<span class="category-title">Functional Cookies</span>
<div class="card-toggle" data-category="functional"></div>
</div>
<div class="category-description">
These cookies enable enhanced functionality and personalization, such as remembering your preferences and settings.
</div>
</div>
</div>
<div class="settings-actions">
<button class="card-btn btn-decline" onclick="saveSettings(false)">Save Preferences</button>
<button class="card-btn btn-accept" onclick="saveSettings(true)">Accept All</button>
</div>
</div>
</div>
<script>
class FloatingCardCookieBanner {
constructor(options = {}) {
this.options = {
autoShow: true,
showDelay: 1500,
storageKey: 'floating_card_cookie_consent',
expiryDays: 365,
enableAnimations: true,
position: 'bottom-right',
onAccept: null,
onDecline: null,
onSettingsSave: null,
...options
};
this.banner = document.getElementById('floatingCookieBanner');
this.modal = document.getElementById('cookieSettingsModal');
this.consent = this.getStoredConsent();
this.isVisible = false;
this.init();
}
init() {
if (this.options.autoShow && !this.consent) {
setTimeout(() => this.show(), this.options.showDelay);
}
this.setupEventListeners();
this.loadSettings();
this.setupPosition();
}
setupEventListeners() {
document.querySelectorAll('.card-toggle').forEach(toggle => {
toggle.addEventListener('click', () => {
if (toggle.dataset.category !== 'essential') {
toggle.classList.toggle('active');
this.animateToggle(toggle);
}
});
});
this.modal.addEventListener('click', (e) => {
if (e.target === this.modal) {
this.closeSettings();
}
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.closeSettings();
}
});
document.querySelectorAll('.card-btn').forEach(btn => {
btn.addEventListener('mouseenter', () => {
this.createRipple(btn);
});
});
this.banner.addEventListener('mouseenter', () => {
if (this.isVisible) {
this.enhanceHoverEffect();
}
});
this.banner.addEventListener('mouseleave', () => {
if (this.isVisible) {
this.resetHoverEffect();
}
});
}
setupPosition() {
const positions = {
'bottom-right': { bottom: '2rem', right: '2rem', left: 'auto', top: 'auto' },
'bottom-left': { bottom: '2rem', left: '2rem', right: 'auto', top: 'auto' },
'top-right': { top: '2rem', right: '2rem', left: 'auto', bottom: 'auto' },
'top-left': { top: '2rem', left: '2rem', right: 'auto', bottom: 'auto' }
};
const pos = positions[this.options.position] || positions['bottom-right'];
Object.assign(this.banner.style, pos);
}
animateToggle(toggle) {
if (!this.options.enableAnimations) return;
toggle.style.transform = 'scale(0.9)';
setTimeout(() => {
toggle.style.transform = 'scale(1)';
}, 150);
toggle.style.boxShadow = '0 0 0 8px rgba(16, 185, 129, 0.2)';
setTimeout(() => {
toggle.style.boxShadow = '';
}, 300);
}
createRipple(button) {
if (!this.options.enableAnimations) return;
const ripple = document.createElement('span');
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = '50%';
ripple.style.top = '50%';
ripple.style.transform = 'translate(-50%, -50%) scale(0)';
ripple.style.position = 'absolute';
ripple.style.borderRadius = '50%';
ripple.style.background = 'rgba(255, 255, 255, 0.3)';
ripple.style.pointerEvents = 'none';
ripple.style.animation = 'ripple 0.6s ease-out';
button.style.position = 'relative';
button.style.overflow = 'hidden';
button.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
}
enhanceHoverEffect() {
if (!this.options.enableAnimations) return;
const icon = this.banner.querySelector('.banner-icon');
if (icon) {
icon.style.transform = 'scale(1.1) rotate(5deg)';
}
}
resetHoverEffect() {
if (!this.options.enableAnimations) return;
const icon = this.banner.querySelector('.banner-icon');
if (icon) {
icon.style.transform = '';
}
}
show() {
this.banner.classList.add('show');
this.isVisible = true;
if (this.options.enableAnimations) {
this.animateEntrance();
}
}
hide() {
this.banner.classList.remove('show');
this.isVisible = false;
}
animateEntrance() {
const elements = [
this.banner.querySelector('.banner-icon'),
this.banner.querySelector('.banner-title'),
this.banner.querySelector('.banner-subtitle'),
this.banner.querySelector('.cookie-description'),
this.banner.querySelector('.cookie-actions')
];
elements.forEach((el, index) => {
if (el) {
el.style.opacity = '0';
el.style.transform = 'translateY(20px)';
setTimeout(() => {
el.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
}, index * 100);
}
});
}
accept() {
const consent = {
essential: true,
analytics: true,
marketing: true,
functional: true,
timestamp: Date.now()
};
this.saveConsent(consent);
this.showSuccessAnimation();
setTimeout(() => {
this.hide();
}, 1500);
if (this.options.onAccept) {
this.options.onAccept(consent);
}
}
decline() {
const consent = {
essential: true,
analytics: false,
marketing: false,
functional: false,
timestamp: Date.now()
};
this.saveConsent(consent);
this.hide();
if (this.options.onDecline) {
this.options.onDecline(consent);
}
}
showSuccessAnimation() {
if (!this.options.enableAnimations) return;
const acceptBtn = this.banner.querySelector('.btn-accept');
if (acceptBtn) {
acceptBtn.innerHTML = `
<svg class="success-checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
<circle class="success-checkmark-circle" cx="26" cy="26" r="25" fill="none"/>
<path class="success-checkmark-check" fill="none" d="m14.1 27.2l7.1 7.2 16.7-16.8"/>
</svg>
Accepted
`;
acceptBtn.style.background = 'var(--success-color)';
}
}
openSettings() {
this.modal.classList.add('show');
document.body.style.overflow = 'hidden';
if (this.options.enableAnimations) {
this.animateModalEntrance();
}
}
closeSettings() {
this.modal.classList.remove('show');
document.body.style.overflow = '';
}
animateModalEntrance() {
const categories = this.modal.querySelectorAll('.cookie-category');
categories.forEach((category, index) => {
category.style.opacity = '0';
category.style.transform = 'translateX(-20px)';
setTimeout(() => {
category.style.transition = 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)';
category.style.opacity = '1';
category.style.transform = 'translateX(0)';
}, index * 100);
});
}
saveSettings(acceptAll = false) {
const toggles = document.querySelectorAll('.card-toggle');
const consent = { timestamp: Date.now() };
toggles.forEach(toggle => {
const category = toggle.dataset.category;
if (acceptAll) {
consent[category] = true;
toggle.classList.add('active');
} else {
consent[category] = toggle.classList.contains('active');
}
});
this.saveConsent(consent);
this.closeSettings();
this.hide();
if (this.options.onSettingsSave) {
this.options.onSettingsSave(consent);
}
}
loadSettings() {
if (this.consent) {
document.querySelectorAll('.card-toggle').forEach(toggle => {
const category = toggle.dataset.category;
if (this.consent[category]) {
toggle.classList.add('active');
} else {
toggle.classList.remove('active');
}
});
}
}
saveConsent(consent) {
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + this.options.expiryDays);
const consentData = {
...consent,
expiry: expiryDate.getTime()
};
localStorage.setItem(this.options.storageKey, JSON.stringify(consentData));
this.consent = consent;
}
getStoredConsent() {
try {
const stored = localStorage.getItem(this.options.storageKey);
if (stored) {
const data = JSON.parse(stored);
if (data.expiry && Date.now() < data.expiry) {
return data;
} else {
localStorage.removeItem(this.options.storageKey);
}
}
} catch (e) {
console.error('Error reading cookie consent:', e);
}
return null;
}
reset() {
localStorage.removeItem(this.options.storageKey);
this.consent = null;
this.show();
}
getConsent() {
return this.consent;
}
setPosition(position) {
this.options.position = position;
this.setupPosition();
}
enableAnimations(enabled) {
this.options.enableAnimations = enabled;
}
updateTheme(theme) {
const themes = {
light: {
'--background': '#ffffff',
'--surface': '#f8fafc',
'--text-primary': '#1f2937',
'--text-secondary': '#6b7280'
},
dark: {
'--background': '#1f2937',
'--surface': '#374151',
'--text-primary': '#f9fafb',
'--text-secondary': '#d1d5db'
}
};
if (themes[theme]) {
Object.entries(themes[theme]).forEach(([property, value]) => {
document.documentElement.style.setProperty(property, value);
});
}
}
}
const style = document.createElement('style');
style.textContent = `
@keyframes ripple {
to {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}
`;
document.head.appendChild(style);
const cookieBanner = new FloatingCardCookieBanner({
position: 'bottom-right',
enableAnimations: true,
onAccept: (consent) => {
console.log('Cookies accepted:', consent);
},
onDecline: (consent) => {
console.log('Cookies declined:', consent);
},
onSettingsSave: (consent) => {
console.log('Settings saved:', consent);
}
});
function showCookieBanner() {
cookieBanner.reset();
}
function acceptCookies() {
cookieBanner.accept();
}
function declineCookies() {
cookieBanner.decline();
}
function openSettings() {
cookieBanner.openSettings();
}
function closeSettings() {
cookieBanner.closeSettings();
}
function saveSettings(acceptAll) {
cookieBanner.saveSettings(acceptAll);
}
</script>
</body>
</html>