Botón de Acción Flotante
   Intermedio  
 Botón de acción flotante moderno con animaciones suaves, opciones de menú expandible y efectos de hover elegantes. Perfecto para aplicaciones mobile-first y acciones rápidas.
Vista Previa en Vivo
Implementación del Código
 HTML  
 <div class="fab-container">
  <!-- Botón FAB Principal -->
  <button class="fab-main" id="fabMain" aria-label="Menú de acciones principales">
    <span class="fab-icon main-icon">+</span>
    <span class="fab-icon close-icon">×</span>
  </button>
  
  <!-- Elementos del Menú FAB -->
  <div class="fab-menu" id="fabMenu">
    <button class="fab-item" data-action="message" aria-label="Enviar mensaje">
      <span class="fab-icon">💬</span>
      <span class="fab-tooltip">Mensaje</span>
    </button>
    
    <button class="fab-item" data-action="call" aria-label="Hacer llamada">
      <span class="fab-icon">📞</span>
      <span class="fab-tooltip">Llamar</span>
    </button>
    
    <button class="fab-item" data-action="email" aria-label="Enviar correo">
      <span class="fab-icon">✉️</span>
      <span class="fab-tooltip">Email</span>
    </button>
    
    <button class="fab-item" data-action="share" aria-label="Compartir contenido">
      <span class="fab-icon">🔗</span>
      <span class="fab-tooltip">Compartir</span>
    </button>
  </div>
  
  <!-- Overlay de Fondo -->
  <div class="fab-overlay" id="fabOverlay"></div>
</div>
 CSS  
 * {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.fab-container {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  z-index: 1000;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.fab-main {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  z-index: 1001;
  overflow: hidden;
}
.fab-main::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
  border-radius: 50%;
}
.fab-main:hover::before {
  opacity: 1;
}
.fab-main:hover {
  transform: scale(1.1);
  box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}
.fab-main:active {
  transform: scale(0.95);
}
.fab-icon {
  font-size: 1.5rem;
  color: white;
  transition: all 0.3s ease;
  position: relative;
  z-index: 1;
}
.main-icon {
  transform: rotate(0deg);
}
.close-icon {
  position: absolute;
  transform: rotate(45deg) scale(0);
  opacity: 0;
}
.fab-main.active .main-icon {
  transform: rotate(45deg) scale(0);
  opacity: 0;
}
.fab-main.active .close-icon {
  transform: rotate(0deg) scale(1);
  opacity: 1;
}
.fab-menu {
  position: absolute;
  bottom: 70px;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  opacity: 0;
  visibility: hidden;
  transform: translateY(20px);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.fab-menu.active {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.fab-item {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: white;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  transform: scale(0);
  animation-fill-mode: forwards;
}
.fab-menu.active .fab-item {
  animation: fabItemAppear 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.fab-menu.active .fab-item:nth-child(1) {
  animation-delay: 0.1s;
}
.fab-menu.active .fab-item:nth-child(2) {
  animation-delay: 0.15s;
}
.fab-menu.active .fab-item:nth-child(3) {
  animation-delay: 0.2s;
}
.fab-menu.active .fab-item:nth-child(4) {
  animation-delay: 0.25s;
}
@keyframes fabItemAppear {
  0% {
    transform: scale(0) rotate(-180deg);
    opacity: 0;
  }
  100% {
    transform: scale(1) rotate(0deg);
    opacity: 1;
  }
}
.fab-item:hover {
  transform: scale(1.1);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  background: #f8f9fa;
}
.fab-item:active {
  transform: scale(0.95);
}
.fab-item .fab-icon {
  font-size: 1.2rem;
  color: #333;
}
.fab-tooltip {
  position: absolute;
  right: 60px;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  font-size: 0.85rem;
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: all 0.3s ease;
  pointer-events: none;
}
.fab-tooltip::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 100%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-left-color: rgba(0, 0, 0, 0.8);
}
.fab-item:hover .fab-tooltip {
  opacity: 1;
  visibility: visible;
  transform: translateY(-50%) translateX(-5px);
}
.fab-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  opacity: 0;
  visibility: hidden;
  transition: all 0.3s ease;
  z-index: 999;
}
.fab-overlay.active {
  opacity: 1;
  visibility: visible;
}
/* Efecto Ripple */
.fab-main::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transform: translate(-50%, -50%);
  transition: width 0.6s, height 0.6s;
}
.fab-main:active::after {
  width: 120px;
  height: 120px;
}
/* Animación de Pulso */
@keyframes pulse {
  0% {
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 0 0 rgba(102, 126, 234, 0.7);
  }
  70% {
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 0 10px rgba(102, 126, 234, 0);
  }
  100% {
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 0 0 rgba(102, 126, 234, 0);
  }
}
.fab-main.pulse {
  animation: pulse 2s infinite;
}
/* Responsive Móvil */
@media (max-width: 768px) {
  .fab-container {
    bottom: 1.5rem;
    right: 1.5rem;
  }
  
  .fab-main {
    width: 52px;
    height: 52px;
  }
  
  .fab-item {
    width: 44px;
    height: 44px;
  }
  
  .fab-tooltip {
    font-size: 0.8rem;
    padding: 0.4rem 0.6rem;
  }
}
/* Soporte Modo Oscuro */
@media (prefers-color-scheme: dark) {
  .fab-item {
    background: #2d3748;
    color: white;
  }
  
  .fab-item .fab-icon {
    color: white;
  }
  
  .fab-item:hover {
    background: #4a5568;
  }
}
 JavaScript  
 class FloatingActionButton {
  constructor() {
    this.fabMain = document.getElementById('fabMain');
    this.fabMenu = document.getElementById('fabMenu');
    this.fabOverlay = document.getElementById('fabOverlay');
    this.fabItems = document.querySelectorAll('.fab-item');
    this.isOpen = false;
    
    this.init();
  }
  
  init() {
    this.setupEventListeners();
    this.setupKeyboardNavigation();
    this.addPulseEffect();
  }
  
  setupEventListeners() {
    // Clic en FAB principal
    this.fabMain.addEventListener('click', () => {
      this.toggle();
    });
    
    // Clic en overlay para cerrar
    this.fabOverlay.addEventListener('click', () => {
      this.close();
    });
    
    // Clics en elementos FAB
    this.fabItems.forEach(item => {
      item.addEventListener('click', (e) => {
        this.handleItemClick(e);
      });
    });
    
    // Cerrar con tecla escape
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && this.isOpen) {
        this.close();
      }
    });
    
    // Cerrar al hacer clic fuera
    document.addEventListener('click', (e) => {
      if (!e.target.closest('.fab-container') && this.isOpen) {
        this.close();
      }
    });
  }
  
  setupKeyboardNavigation() {
    // Hacer elementos FAB enfocables
    this.fabItems.forEach((item, index) => {
      item.setAttribute('tabindex', '-1');
      
      item.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          this.handleItemClick(e);
        } else if (e.key === 'ArrowUp') {
          e.preventDefault();
          this.focusPreviousItem(index);
        } else if (e.key === 'ArrowDown') {
          e.preventDefault();
          this.focusNextItem(index);
        }
      });
    });
  }
  
  addPulseEffect() {
    // Agregar efecto de pulso en la primera carga
    setTimeout(() => {
      this.fabMain.classList.add('pulse');
      setTimeout(() => {
        this.fabMain.classList.remove('pulse');
      }, 4000);
    }, 1000);
  }
  
  toggle() {
    if (this.isOpen) {
      this.close();
    } else {
      this.open();
    }
  }
  
  open() {
    this.isOpen = true;
    this.fabMain.classList.add('active');
    this.fabMenu.classList.add('active');
    this.fabOverlay.classList.add('active');
    
    // Enfocar primer elemento del menú
    setTimeout(() => {
      this.fabItems[0].setAttribute('tabindex', '0');
      this.fabItems[0].focus();
    }, 100);
    
    // Anunciar a lectores de pantalla
    this.announceToScreenReader('Menú abierto');
  }
  
  close() {
    this.isOpen = false;
    this.fabMain.classList.remove('active');
    this.fabMenu.classList.remove('active');
    this.fabOverlay.classList.remove('active');
    
    // Quitar enfoque de elementos del menú
    this.fabItems.forEach(item => {
      item.setAttribute('tabindex', '-1');
    });
    
    // Devolver enfoque al botón principal
    this.fabMain.focus();
    
    // Anunciar a lectores de pantalla
    this.announceToScreenReader('Menú cerrado');
  }
  
  handleItemClick(e) {
    const action = e.currentTarget.getAttribute('data-action');
    const actionName = e.currentTarget.getAttribute('aria-label');
    
    // Agregar animación de clic
    e.currentTarget.style.transform = 'scale(0.9)';
    setTimeout(() => {
      e.currentTarget.style.transform = '';
    }, 150);
    
    // Manejar diferentes acciones
    switch (action) {
      case 'message':
        this.handleMessage();
        break;
      case 'call':
        this.handleCall();
        break;
      case 'email':
        this.handleEmail();
        break;
      case 'share':
        this.handleShare();
        break;
      default:
        console.log(`Acción: ${action}`);
    }
    
    // Anunciar acción a lectores de pantalla
    this.announceToScreenReader(`${actionName} seleccionado`);
    
    // Cerrar menú después de la acción
    setTimeout(() => {
      this.close();
    }, 200);
  }
  
  handleMessage() {
    // Simular apertura de interfaz de mensajes
    console.log('Abriendo interfaz de mensajes...');
    this.showNotification('Interfaz de mensajes abierta', '💬');
  }
  
  handleCall() {
    // Simular hacer una llamada
    console.log('Iniciando llamada...');
    this.showNotification('Llamada iniciada', '📞');
  }
  
  handleEmail() {
    // Simular apertura de email
    console.log('Abriendo cliente de correo...');
    this.showNotification('Cliente de correo abierto', '✉️');
  }
  
  handleShare() {
    // Simular compartir
    if (navigator.share) {
      navigator.share({
        title: 'Demo de Botón de Acción Flotante',
        text: '¡Mira este increíble componente FAB!',
        url: window.location.href
      }).catch(console.error);
    } else {
      // Fallback para navegadores sin Web Share API
      this.copyToClipboard(window.location.href);
      this.showNotification('Enlace copiado al portapapeles', '🔗');
    }
  }
  
  copyToClipboard(text) {
    if (navigator.clipboard) {
      navigator.clipboard.writeText(text);
    } else {
      // Fallback para navegadores antiguos
      const textArea = document.createElement('textarea');
      textArea.value = text;
      document.body.appendChild(textArea);
      textArea.select();
      document.execCommand('copy');
      document.body.removeChild(textArea);
    }
  }
  
  showNotification(message, icon) {
    // Crear y mostrar notificación temporal
    const notification = document.createElement('div');
    notification.style.cssText = `
      position: fixed;
      top: 2rem;
      right: 2rem;
      background: rgba(0, 0, 0, 0.8);
      color: white;
      padding: 1rem 1.5rem;
      border-radius: 8px;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      z-index: 1002;
      animation: slideInRight 0.3s ease;
    `;
    
    notification.innerHTML = `
      <span style="font-size: 1.2rem;">${icon}</span>
      <span>${message}</span>
    `;
    
    document.body.appendChild(notification);
    
    setTimeout(() => {
      notification.style.animation = 'slideOutRight 0.3s ease forwards';
      setTimeout(() => {
        document.body.removeChild(notification);
      }, 300);
    }, 3000);
  }
  
  focusNextItem(currentIndex) {
    const nextIndex = (currentIndex + 1) % this.fabItems.length;
    this.fabItems[currentIndex].setAttribute('tabindex', '-1');
    this.fabItems[nextIndex].setAttribute('tabindex', '0');
    this.fabItems[nextIndex].focus();
  }
  
  focusPreviousItem(currentIndex) {
    const prevIndex = currentIndex === 0 ? this.fabItems.length - 1 : currentIndex - 1;
    this.fabItems[currentIndex].setAttribute('tabindex', '-1');
    this.fabItems[prevIndex].setAttribute('tabindex', '0');
    this.fabItems[prevIndex].focus();
  }
  
  announceToScreenReader(message) {
    const announcement = document.createElement('div');
    announcement.setAttribute('aria-live', 'polite');
    announcement.setAttribute('aria-atomic', 'true');
    announcement.style.cssText = `
      position: absolute;
      left: -10000px;
      width: 1px;
      height: 1px;
      overflow: hidden;
    `;
    announcement.textContent = message;
    
    document.body.appendChild(announcement);
    setTimeout(() => {
      document.body.removeChild(announcement);
    }, 1000);
  }
}
// Agregar animaciones CSS para notificaciones
const style = document.createElement('style');
style.textContent = `
  @keyframes slideInRight {
    from {
      transform: translateX(100%);
      opacity: 0;
    }
    to {
      transform: translateX(0);
      opacity: 1;
    }
  }
  
  @keyframes slideOutRight {
    from {
      transform: translateX(0);
      opacity: 1;
    }
    to {
      transform: translateX(100%);
      opacity: 0;
    }
  }
`;
document.head.appendChild(style);
// Inicializar el FAB
document.addEventListener('DOMContentLoaded', () => {
  new FloatingActionButton();
});