🌐 AULA 11

CSS e JavaScript

⏱️ Duração: 55 minutos 🎯 Nível: Avançado 👨‍💻 Prática: Sim

Seu progresso nesta aula
0%
⬅️ Aula anterior: Pré-processadores CSS Próxima aula: Metodologias CSS ➡️

🎯 Objetivos de Aprendizado

Ao final desta aula, você será capaz de:

🔄 CSS e JavaScript: O Poder da Integração

O CSS e o JavaScript, quando combinados, formam uma poderosa ferramenta para criar experiências de usuário dinâmicas, interativas e envolventes. Enquanto o CSS define a apresentação visual, o JavaScript permite manipular esses estilos em resposta às ações do usuário ou a eventos do sistema.

Nesta aula, exploraremos como:

💡 Lembre-se

A regra de ouro é: use CSS para estilização e animações simples, e JavaScript para lógica e interatividade complexa. Quando ambos trabalham juntos, você aproveita o melhor dos dois mundos.

🎮 Manipulando Estilos com JavaScript

Existem três maneiras principais de manipular estilos CSS através de JavaScript:

1. Manipulando Diretamente a Propriedade style

Você pode acessar e modificar diretamente as propriedades CSS de um elemento através do objeto style.

Clique aqui para mudar o estilo diretamente

// Manipulando o estilo diretamente
const element = document.getElementById('styleDemo');

element.addEventListener('click', () => {
    // Propriedades CSS são acessadas em camelCase
    element.style.backgroundColor = '#6d28d9';
    element.style.color = 'white';
    element.style.padding = '20px';
    element.style.borderRadius = '10px';
    element.style.transition = 'all 0.3s ease';
});

⚠️ Considerações

Manipular diretamente a propriedade style:

  • Adiciona estilos inline, que têm alta especificidade
  • Substitui apenas estilos individuais, não o conjunto completo
  • Requer o uso de camelCase (ex: backgroundColor em vez de background-color)
  • É adequado para alterações dinâmicas baseadas em cálculos ou posições

2. Manipulando Classes CSS

Uma abordagem mais flexível e organizada é adicionar, remover ou alternar classes CSS predefinidas.

Clique aqui para alternar classes CSS

// Manipulando classes
const element = document.getElementById('classDemo');

element.addEventListener('click', () => {
    // Alternar uma classe
    element.classList.toggle('active');
    
    // Adicionar uma classe
    // element.classList.add('highlight');
    
    // Remover uma classe
    // element.classList.remove('highlight');
    
    // Verificar se uma classe existe
    // if (element.classList.contains('active')) { ... }
});

💡 Prática Recomendada

Manipular classes CSS é geralmente a abordagem preferida porque:

  • Separa as preocupações: mantém os estilos no CSS e a lógica no JavaScript
  • Permite alternar facilmente entre estados visuais predefinidos
  • Aproveita o sistema de cascata e especificidade do CSS
  • É mais fácil de manter e estender

3. Definindo/Obtendo Propriedades Computadas

Você pode obter os estilos computados de um elemento, independentemente de como esses estilos foram definidos.

// Obtendo estilos computados
const element = document.getElementById('someElement');
const styles = window.getComputedStyle(element);

console.log(styles.backgroundColor); // rgb(255, 255, 255)
console.log(styles.fontSize); // 16px

// Você pode usar isso para tomar decisões com base no estilo atual
if (styles.display === 'none') {
    // O elemento está oculto
}

🎛️ CSS Variables e JavaScript

As variáveis CSS (Custom Properties) fornecem uma maneira poderosa de criar interfaces dinâmicas, pois podem ser manipuladas em tempo real com JavaScript.

Tema dinâmico com variáveis CSS

Este container usa variáveis CSS para definir cores e espaçamentos.

/* CSS com variáveis */
.theme-dark {
    --bg-color: #1f2937;
    --text-color: #f9fafb;
    --border-color: #374151;
    --highlight-color: #5b21b6;
}

.theme-light {
    --bg-color: #f9fafb;
    --text-color: #1f2937;
    --border-color: #e5e7eb;
    --highlight-color: #8b5cf6;
}

.theme-container {
    background-color: var(--bg-color);
    color: var(--text-color);
    border: 1px solid var(--border-color);
}

/* JavaScript para alternar o tema */
const themeContainer = document.getElementById('themeDemo');
const themeButton = document.getElementById('toggleTheme');

themeButton.addEventListener('click', () => {
    themeContainer.classList.toggle('theme-dark');
    themeContainer.classList.toggle('theme-light');
});

Manipulando Variáveis CSS Individualmente

Você também pode definir e obter variáveis CSS diretamente:

// Definindo uma variável CSS
document.documentElement.style.setProperty('--highlight-color', '#9333ea');

// Obtendo o valor de uma variável CSS
const highlightColor = getComputedStyle(document.documentElement)
    .getPropertyValue('--highlight-color');

✨ Casos de uso para variáveis CSS com JavaScript

  • Temas dinâmicos: Alternar entre modo claro/escuro ou temas personalizados
  • UI reativa: Ajustar estilos com base em ações do usuário
  • Visualizações de dados: Atualizar cores em gráficos ou mapas de calor
  • Animações: Controlar parâmetros de animação dinamicamente

✨ Animações CSS com JavaScript

As animações CSS são poderosas por si só, mas quando combinadas com JavaScript, oferecem controle granular e possibilidades criativas expandidas.

1. Adicionando/Removendo Classes de Animação

A forma mais simples de controlar animações é adicionar ou remover classes que contêm as definições de animação.

/* CSS com animações */
@keyframes bounce {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-20px); }
}

@keyframes slideIn {
    from { transform: translateX(-100%); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

.bounce { animation: bounce 1s infinite; }
.slide-in { animation: slideIn 0.5s forwards; }

/* JavaScript para controlar a animação */
document.getElementById('animBounce').addEventListener('click', () => {
    const target = document.getElementById('animTarget');
    target.classList.remove('slide-in');
    target.classList.add('bounce');
});

document.getElementById('animSlide').addEventListener('click', () => {
    const target = document.getElementById('animTarget');
    target.classList.remove('bounce');
    target.classList.add('slide-in');
});

document.getElementById('animStop').addEventListener('click', () => {
    const target = document.getElementById('animTarget');
    target.classList.remove('bounce', 'slide-in');
});

2. Controlando Animações com JavaScript

Você pode controlar detalhes de animação e sincronizar com eventos ou lógica de aplicativo.

// Eventos de animação
const element = document.querySelector('.animated-element');

element.addEventListener('animationstart', () => {
    console.log('Animação iniciada');
});

element.addEventListener('animationend', () => {
    console.log('Animação concluída');
    // Execute ações após o término da animação
    element.classList.add('post-animation-state');
});

element.addEventListener('animationiteration', () => {
    console.log('Ciclo de animação concluído');
});

3. Web Animation API

A API de Animação da Web oferece controle total sobre animações diretamente no JavaScript.

// Criando uma animação com Web Animation API
const element = document.querySelector('.animation-target');

// Definindo keyframes
const keyframes = [
    { transform: 'translateX(0) scale(1)', backgroundColor: '#6d28d9' },
    { transform: 'translateX(100px) scale(1.2)', backgroundColor: '#9333ea' },
    { transform: 'translateX(0) scale(1)', backgroundColor: '#6d28d9' }
];

// Definindo opções de tempo
const options = {
    duration: 2000,
    iterations: Infinity,
    easing: 'ease-in-out'
};

// Criando e iniciando a animação
const animation = element.animate(keyframes, options);

// Controlando a animação
document.getElementById('pauseBtn').addEventListener('click', () => animation.pause());
document.getElementById('playBtn').addEventListener('click', () => animation.play());
document.getElementById('reverseBtn').addEventListener('click', () => animation.reverse());

🔄 CSS vs JavaScript para Animações

Animações com CSS Animações com JavaScript
Melhor performance para animações simples Necessário para animações baseadas em lógica complexa
Declarativas e fáceis de implementar Maior controle e flexibilidade
Limitadas a keyframes predefinidos Podem reagir a eventos e dados em tempo real
Boas para transições de estado Boas para animações interativas ou baseadas em física

🖱️ Interações Avançadas

Combinando CSS e JavaScript, podemos criar interações complexas e responsivas.

Drag and Drop

Implementação de uma funcionalidade simples de arrastar e soltar:

Arraste os itens entre as áreas

Item 1
Item 2
Item 3
/* CSS para drag and drop */
.draggable {
    padding: 1rem;
    background-color: #6d28d9;
    color: white;
    cursor: move;
    transition: transform 0.2s;
}

.draggable.dragging {
    opacity: 0.5;
    transform: scale(1.05);
}

.drop-zone {
    min-height: 100px;
    border: 2px dashed #6d28d9;
    padding: 1rem;
}

.drop-zone.drag-over {
    background-color: rgba(109, 40, 217, 0.1);
}

/* JavaScript para drag and drop */
const draggables = document.querySelectorAll('.draggable');
const dropZones = document.querySelectorAll('.drop-zone');

draggables.forEach(draggable => {
    draggable.addEventListener('dragstart', () => {
        draggable.classList.add('dragging');
    });
    
    draggable.addEventListener('dragend', () => {
        draggable.classList.remove('dragging');
    });
});

dropZones.forEach(zone => {
    zone.addEventListener('dragover', e => {
        e.preventDefault();
        zone.classList.add('drag-over');
    });
    
    zone.addEventListener('dragleave', () => {
        zone.classList.remove('drag-over');
    });
    
    zone.addEventListener('drop', e => {
        e.preventDefault();
        zone.classList.remove('drag-over');
        
        const dragging = document.querySelector('.dragging');
        if (dragging) {
            zone.appendChild(dragging);
        }
    });
});

Scroll Animations

Use a Intersection Observer API para criar efeitos baseados na posição de rolagem:

Role para ver os itens aparecerem:

Scroll Item 1
Scroll Item 2
Scroll Item 3
Scroll Item 4
/* CSS para elementos que vão animar no scroll */
.scroll-item {
    padding: 2rem;
    margin: 2rem 0;
    background-color: #f3f4f6;
    transform: translateX(-100px);
    opacity: 0;
    transition: all 0.5s ease-out;
}

.scroll-item.visible {
    transform: translateX(0);
    opacity: 1;
}

/* JavaScript com IntersectionObserver */
const scrollItems = document.querySelectorAll('.scroll-item');

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.classList.add('visible');
        } else {
            // Opcional: remover a classe quando o item sair da visualização
            // entry.target.classList.remove('visible');
        }
    });
}, {
    threshold: 0.1 // Porcentagem do item visível necessária para disparar
});

scrollItems.forEach(item => {
    observer.observe(item);
});

🌟 APIs Modernas para CSS e JavaScript

Várias APIs modernas melhoram a integração entre CSS e JavaScript:

1. ResizeObserver

Monitora mudanças no tamanho de elementos, útil para ajustes de layout responsivos sem usar media queries.

// Monitorando o tamanho de um elemento
const element = document.querySelector('.resize-observe');

const resizeObserver = new ResizeObserver(entries => {
    for (let entry of entries) {
        const { width, height } = entry.contentRect;
        
        // Adaptar estilos com base no tamanho
        if (width < 500) {
            entry.target.classList.add('compact');
        } else {
            entry.target.classList.remove('compact');
        }
    }
});

resizeObserver.observe(element);

2. MutationObserver

Observa mudanças no DOM, incluindo atributos como classes CSS.

// Monitorando mudanças em classes CSS
const element = document.querySelector('.observe-changes');

const observer = new MutationObserver(mutations => {
    for (let mutation of mutations) {
        if (mutation.attributeName === 'class') {
            const currentClasses = mutation.target.className;
            console.log('Classes alteradas:', currentClasses);
            
            // Reagir a classes específicas
            if (currentClasses.includes('active')) {
                // Fazer algo quando a classe 'active' for adicionada
            }
        }
    }
});

// Configurar o que observar
observer.observe(element, { attributes: true });

3. CSS Typed Object Model

Parte das APIs Houdini, fornece uma interface orientada a objetos para trabalhar com valores CSS.

// Usando Typed OM para manipulações de estilo mais rápidas e tipadas
const elem = document.querySelector('.typed-om-example');

// Abordagem tradicional
elem.style.opacity = 0.5;

// Abordagem com Typed OM
elem.attributeStyleMap.set('opacity', 0.5);

// Trabalhar com unidades
elem.attributeStyleMap.set('font-size', CSS.px(16));
elem.attributeStyleMap.set('padding', CSS.px(20));

// Animações matemáticas - combinar valores
const paddingAnimation = elem.attributeStyleMap.get('padding').value + 10;
elem.attributeStyleMap.set('padding', CSS.px(paddingAnimation));

💡 Dica

Ao trabalhar com APIs modernas, sempre verifique o suporte do navegador e forneça fallbacks quando necessário.

// Verificando suporte a uma API antes de usá-la
if ('IntersectionObserver' in window) {
    // Usar IntersectionObserver
} else {
    // Fallback para scroll event listener
}

📚 Frameworks e Bibliotecas

Existem muitas bibliotecas que facilitam a integração entre CSS e JavaScript:

Biblioteca Descrição Casos de Uso
GSAP Biblioteca robusta de animação com amplo suporte de navegador Animações complexas, sequências, controle de linha do tempo
Animate.css Coleção de animações CSS prontas para usar Animações simples controladas por classes
Motion One API moderna para animação baseada na Web Animations API Alternativa leve ao GSAP com sintaxe moderna
Framer Motion Biblioteca de animação para React Animações em aplicativos React
AOS Animate On Scroll Efeitos de rolagem simples sem código JavaScript personalizado
Popmotion Biblioteca funcional de animação Animações baseadas em física, gestos
Sortable.js Biblioteca de drag-and-drop Listas ordenáveis e arrastar e soltar
// Exemplo com GSAP
import { gsap } from "gsap";

// Animação simples
gsap.to(".box", {
    duration: 1,
    x: 100,
    rotation: 360,
    ease: "bounce"
});

// Timeline para sequências
const tl = gsap.timeline();
tl.to(".box1", { duration: 0.5, x: 100 })
  .to(".box2", { duration: 0.5, y: 50 }, "-=0.25")
  .to(".box3", { duration: 0.5, scale: 1.2 });

👌 Melhores Práticas

💡 Dicas para Integração Eficiente de CSS e JavaScript

  1. Separação de Preocupações: Mantenha estilos no CSS sempre que possível, use JavaScript apenas para manipulação dinâmica e lógica.
  2. Priorize Classes sobre Estilos Inline: Adicionar/remover classes é mais limpo e eficiente do que manipular estilos individuais.
  3. Considere a Performance: Animações baseadas em CSS geralmente têm melhor desempenho, principalmente para propriedades que podem ser aceleradas por GPU (transform, opacity).
  4. Minimize Reflows: Agrupe modificações DOM e evite leituras/gravações alternadas para minimizar reflows.
  5. Use RequestAnimationFrame: Para animações baseadas em JavaScript, use requestAnimationFrame em vez de setInterval/setTimeout.
  6. Detecte Recursos: Sempre verifique o suporte do navegador antes de usar recursos modernos.
  7. Pré-carregue Recursos: Adicione classes como .preload durante o carregamento para evitar animações indesejadas.
  8. Respeite Preferências do Usuário: Verifique media queries como prefers-reduced-motion.
// Exemplo de minimização de reflows
// Ruim: Causa múltiplos reflows
element.style.width = '100px';
console.log(element.offsetWidth); // Força reflow
element.style.height = '100px';   // Outro reflow
element.style.margin = '10px';    // Mais um reflow

// Bom: Agrupa mudanças
// Leituras
const width = element.offsetWidth;
const height = element.offsetHeight;

// Então escritas (todas de uma vez)
element.style.cssText = 'width: 100px; height: 100px; margin: 10px;';

// Ou use classes
element.classList.add('new-dimensions');

⚠️ Armadilhas Comuns a Evitar

  • Sobrecomplexidade: Não use JavaScript quando CSS puro for suficiente
  • Excesso de animações: Animações demais podem afetar a performance e a experiência do usuário
  • Ignorar acessibilidade: Certifique-se de que suas interações funcionem com teclado e leitores de tela
  • Estourar o orçamento de performance: Monitore o impacto das suas animações e interações na CPU/GPU

✏️ Exercícios Práticos

Exercício 1: Toggle de Temas

Implemente um sistema de temas claro/escuro utilizando variáveis CSS e JavaScript:

  • Defina um conjunto de variáveis CSS para cores, fontes e espaçamentos
  • Crie dois temas (claro e escuro) com valores diferentes
  • Implemente um botão toggle que alterna entre os temas
  • Salve a preferência do usuário no localStorage
  • Bônus: Sincronize com a preferência do sistema (prefers-color-scheme)

Exercício 2: Animação de Menu Responsivo

Crie um menu responsivo (hambúrguer) com animações suaves:

  • Menu que se expande/colapsa em dispositivos móveis
  • Animação suave para o ícone do hambúrguer (transformando em X)
  • Transição para os itens de menu aparecendo em sequência
  • Efeito de sobreposição no resto da página quando o menu estiver aberto

Dica: Use CSS para as animações e JavaScript apenas para alternar classes.

Exercício 3: Galeria com Efeitos de Rolagem

Implemente uma galeria de imagens/cartões que reage à posição de rolagem:

  • Use IntersectionObserver para detectar quando os itens entram na viewport
  • Aplique diferentes efeitos de entrada (fade in, slide in, zoom)
  • Implemente um efeito parallax nas imagens de fundo
  • Adicione uma funcionalidade para filtrar/ordenar itens com animações de transição

Desafio: Interfaces Interativas Avançadas

Escolha e implemente uma das seguintes interfaces interativas:

  1. Carrossel Personalizado: Com efeitos de transição, navegação por toque e indicadores interativos
  2. Formulário Dinâmico: Com validações em tempo real, animações de feedback e progress steps
  3. Kanban Board: Com drag-and-drop entre colunas e animações suaves
  4. Visualizador de Dados: Com gráficos animados que respondem a interações do usuário

Dica: Combine todas as técnicas vistas nesta aula, mas priorize a experiência do usuário e a acessibilidade.

🔧 Ferramentas e Recursos

📝 Resumo

Pontos-chave desta aula

  • Existem três principais maneiras de manipular CSS com JavaScript: estilos diretos, classes e propriedades computadas
  • CSS Variables (Custom Properties) permitem criar interfaces dinâmicas e temas personalizáveis
  • As animações CSS podem ser controladas via JavaScript para timing preciso e interatividade
  • APIs modernas como IntersectionObserver, ResizeObserver e Web Animations API expandem as possibilidades de interação
  • Combinações de CSS e JavaScript permitem implementar interações avançadas como drag-and-drop e animações de rolagem
  • Priorize a manipulação de classes sobre estilos inline para código mais limpo e performático

🚀 Próximos Passos

Agora que você entende como CSS e JavaScript trabalham juntos, pode explorar:

Na próxima aula, exploraremos metodologias CSS que ajudam a organizar e escalar estilos em projetos grandes!

⬅️ Aula anterior: Pré-processadores CSS Próxima aula: Metodologias CSS ➡️