Aprenda a adicionar movimento e vida aos seus sites com transformações CSS e transições suaves. Domine efeitos visuais dinâmicos que melhoram a experiência do usuário sem comprometer a performance.
Compreender e aplicar transformações 2D e 3D para manipular elementos visualmente.
Implementar transições entre estados para criar experiências de usuário fluidas e agradáveis.
Aprender a unir transformações e transições para criar interações complexas e atraentes.
As transformações CSS permitem que você modifique a forma, posição e tamanho de elementos HTML sem alterar o fluxo do documento. É uma ferramenta poderosa para criar efeitos visuais interessantes e interfaces dinâmicas.
Transformações 2D operam nos eixos X (horizontal) e Y (vertical), permitindo rotações, escalonamentos, translações e distorções em um plano bidimensional.
Função | Descrição | Exemplo |
---|---|---|
translate(x, y) | Move um elemento nos eixos X e Y | transform: translate(20px, 10px); |
translateX(x) | Move um elemento horizontalmente | transform: translateX(20px); |
translateY(y) | Move um elemento verticalmente | transform: translateY(10px); |
scale(x, y) | Redimensiona um elemento nos eixos X e Y | transform: scale(1.5, 0.8); |
scaleX(x) | Redimensiona um elemento horizontalmente | transform: scaleX(1.5); |
scaleY(y) | Redimensiona um elemento verticalmente | transform: scaleY(0.8); |
rotate(angle) | Gira um elemento | transform: rotate(45deg); |
skew(x-angle, y-angle) | Distorce um elemento | transform: skew(10deg, 5deg); |
/* Botão que cresce ligeiramente ao hover */
.button {
background: blue;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
}
.button:hover {
transform: scale(1.1); /* Cresce 10% */
}
/* Card que eleva ao hover */
.card {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.card:hover {
transform: translateY(-10px); /* Move 10px para cima */
}
/* Ícone que gira ao hover */
.icon {
width: 24px;
height: 24px;
}
.icon:hover {
transform: rotate(180deg); /* Gira 180 graus */
}
A propriedade transform-origin
permite alterar o ponto de origem da transformação, que por padrão é o centro do elemento.
/* Por padrão, a origem é o centro (50% 50%) */
.element {
transform: rotate(45deg);
transform-origin: 50% 50%;
}
/* Rotação a partir do canto superior esquerdo */
.element-corner {
transform: rotate(45deg);
transform-origin: 0 0;
}
/* Rotação a partir do ponto inferior direito */
.element-bottom-right {
transform: rotate(45deg);
transform-origin: 100% 100%;
}
Transformações 3D introduzem o eixo Z (profundidade), permitindo manipular elementos no espaço tridimensional.
Função | Descrição | Exemplo |
---|---|---|
translate3d(x, y, z) | Move um elemento nos eixos X, Y e Z | transform: translate3d(20px, 10px, 30px); |
translateZ(z) | Move um elemento no eixo Z | transform: translateZ(30px); |
scale3d(x, y, z) | Redimensiona em 3D | transform: scale3d(1.5, 0.8, 2); |
rotateX(angle) | Gira em torno do eixo X | transform: rotateX(45deg); |
rotateY(angle) | Gira em torno do eixo Y | transform: rotateY(45deg); |
rotateZ(angle) | Gira em torno do eixo Z (equivalente ao rotate()) | transform: rotateZ(45deg); |
perspective(length) | Define a perspectiva | transform: perspective(1000px); |
Para que transformações 3D tenham o efeito de profundidade desejado, é necessário definir uma perspectiva. Isso pode ser feito de duas maneiras:
perspective
no elemento paiperspective()
dentro da propriedade transform/* Método 1: No elemento pai */
.container {
perspective: 1000px;
}
.child {
transform: rotateY(45deg);
}
/* Método 2: Na própria transformação */
.element {
transform: perspective(1000px) rotateY(45deg);
}
Quanto menor o valor da perspectiva, mais dramático é o efeito 3D.
<div class="flip-card">
<div class="flip-card-inner">
<div class="flip-card-front">
<h3>Frente do Card</h3>
<p>Passe o mouse para virar</p>
</div>
<div class="flip-card-back">
<h3>Verso do Card</h3>
<p>Conteúdo adicional aqui!</p>
</div>
</div>
</div>
.flip-card {
width: 300px;
height: 200px;
perspective: 1000px; /* Importante para o efeito 3D */
}
.flip-card-inner {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d; /* Preserva o 3D para elementos filhos */
transition: transform 0.8s;
}
.flip-card:hover .flip-card-inner {
transform: rotateY(180deg);
}
.flip-card-front, .flip-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden; /* Oculta o verso do elemento */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 8px;
padding: 20px;
}
.flip-card-front {
background-color: #bde0fe;
color: #333;
}
.flip-card-back {
background-color: #3a86ff;
color: white;
transform: rotateY(180deg);
}
transform-style: preserve-3d;
é crucial para manter o espaço 3D entre elementos aninhados.backface-visibility: hidden;
impede que o verso de um elemento seja visível quando girado.É possível combinar várias transformações em uma única regra, aplicando-as da direita para a esquerda.
/* Primeiro rotaciona, depois dimensiona, por fim move */
.element {
transform: translate(20px, 10px) scale(1.5) rotate(45deg);
}
As transições CSS permitem animar a mudança de um valor de propriedade para outro de maneira suave e controlada. Em vez de alterações instantâneas, transições criam uma animação gradual entre dois estados.
Propriedade | Descrição | Exemplo |
---|---|---|
transition-property | Especifica quais propriedades serão animadas | transition-property: opacity, transform; |
transition-duration | Define quanto tempo a transição leva | transition-duration: 0.3s; |
transition-timing-function | Define como a transição progride ao longo do tempo | transition-timing-function: ease-in-out; |
transition-delay | Atraso antes do início da transição | transition-delay: 0.1s; |
transition | Atalho para as quatro propriedades acima | transition: transform 0.3s ease-in-out 0.1s; |
/* Formato: property duration timing-function delay */
transition: all 0.3s ease 0s;
/* Transição para múltiplas propriedades */
transition:
transform 0.3s ease-out,
color 0.2s linear,
background-color 0.5s ease-in;
As funções de temporização controlam a progressão da transição, definindo como os valores intermediários são calculados.
Função | Descrição |
---|---|
ease | Inicia devagar, acelera no meio e termina devagar (padrão) |
linear | Velocidade constante do início ao fim |
ease-in | Inicia devagar e termina em velocidade máxima |
ease-out | Inicia rápido e desacelera até parar |
ease-in-out | Inicia e termina devagar, com aceleração no meio |
cubic-bezier(n,n,n,n) | Define uma curva bezier personalizada |
steps(n, start|end) | Cria uma transição em etapas discretas |
/* Transição de hover básica */
.button {
background-color: #3a86ff;
color: white;
padding: 10px 20px;
transition: all 0.3s ease;
}
.button:hover {
background-color: #1d4ed8;
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
/* Transições com diferentes timing functions */
.card {
opacity: 0.7;
transform: scale(0.95);
}
.card.zoom-linear {
transition: all 0.5s linear;
}
.card.zoom-ease-in {
transition: all 0.5s ease-in;
}
.card.zoom-ease-out {
transition: all 0.5s ease-out;
}
.card.zoom-bounce {
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.card:hover {
opacity: 1;
transform: scale(1);
}
Criar funções cubic-bezier personalizadas pode ser complicado. Estas ferramentas online podem ajudar:
Nem todas as propriedades CSS podem ser animadas. As mais comuns que suportam transições são:
Algumas propriedades não podem ser animadas, como:
display
(use opacity
e visibility
em conjunto)position
(o valor em si, não as coordenadas)font-family
A combinação de transformações e transições é onde a magia realmente acontece. Você pode criar efeitos complexos e interações ricas que melhoram significativamente a experiência do usuário.
.hover-card {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.hover-card:hover {
transform: translateY(-10px) scale(1.02);
box-shadow: 0 15px 30px rgba(0,0,0,0.2);
}
<button class="hamburger" id="menu-toggle">
<span class="line line-1"></span>
<span class="line line-2"></span>
<span class="line line-3"></span>
</button>
.hamburger {
display: block;
background: none;
border: none;
cursor: pointer;
padding: 10px;
width: 50px;
height: 50px;
}
.line {
display: block;
width: 30px;
height: 3px;
margin: 6px 0;
background: #333;
border-radius: 3px;
transition: all 0.3s ease-in-out;
}
.hamburger.active .line-1 {
transform: translateY(9px) rotate(45deg);
}
.hamburger.active .line-2 {
opacity: 0;
transform: translateX(-20px);
}
.hamburger.active .line-3 {
transform: translateY(-9px) rotate(-45deg);
}
document.getElementById('menu-toggle').addEventListener('click', function() {
this.classList.toggle('active');
});
<div class="gallery">
<div class="gallery-item">
<img src="imagem1.jpg" alt="Descrição">
<div class="overlay">
<h3>Título da Imagem</h3>
<p>Descrição adicional</p>
</div>
</div>
<!-- Mais itens aqui -->
</div>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 8px;
height: 250px;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
color: white;
padding: 20px;
transform: translateY(100px);
opacity: 0;
transition: all 0.3s ease;
}
.gallery-item:hover img {
transform: scale(1.1);
}
.gallery-item:hover .overlay {
transform: translateY(0);
opacity: 1;
}
<button class="fill-button">
Clique Aqui
</button>
.fill-button {
position: relative;
padding: 12px 24px;
border: 2px solid #3a86ff;
color: #3a86ff;
background: transparent;
font-weight: bold;
overflow: hidden;
z-index: 1;
cursor: pointer;
transition: color 0.3s ease;
}
.fill-button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #3a86ff;
z-index: -1;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s ease;
}
.fill-button:hover {
color: white;
}
.fill-button:hover::before {
transform: scaleX(1);
}
Para garantir transições suaves e alto desempenho:
/* Otimizando animações */
.optimized-element {
will-change: transform, opacity;
transition: transform 0.3s ease, opacity 0.3s ease;
}
<nav class="navbar">
<ul>
<li class="dropdown">
<a href="#">Produtos <span>▼</span></a>
<ul class="dropdown-menu">
<li><a href="#">Categoria 1</a></li>
<li><a href="#">Categoria 2</a></li>
<li><a href="#">Categoria 3</a></li>
</ul>
</li>
<!-- Mais itens de menu -->
</ul>
</nav>
.navbar ul {
list-style: none;
display: flex;
}
.navbar li {
position: relative;
}
.navbar a {
display: block;
padding: 15px 20px;
color: #333;
text-decoration: none;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
background: white;
width: 200px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
opacity: 0;
visibility: hidden;
transform: translateY(10px);
transition: all 0.3s ease;
}
.dropdown:hover .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
/* Animação da seta */
.dropdown span {
display: inline-block;
font-size: 10px;
margin-left: 5px;
transition: transform 0.3s ease;
}
.dropdown:hover span {
transform: rotate(180deg);
}
<div class="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="slide1.jpg" alt="Slide 1">
</div>
<div class="carousel-item">
<img src="slide2.jpg" alt="Slide 2">
</div>
<div class="carousel-item">
<img src="slide3.jpg" alt="Slide 3">
</div>
</div>
<button class="carousel-control prev"><<</button>
<button class="carousel-control next">>></button>
</div>
.carousel {
position: relative;
width: 100%;
height: 400px;
overflow: hidden;
}
.carousel-inner {
height: 100%;
width: 100%;
}
.carousel-item {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 0.6s ease-in-out;
}
.carousel-item.active {
opacity: 1;
}
.carousel-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
.carousel-control {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba(255,255,255,0.5);
border: none;
width: 40px;
height: 40px;
border-radius: 50%;
font-weight: bold;
cursor: pointer;
z-index: 10;
transition: all 0.3s ease;
}
.carousel-control:hover {
background: rgba(255,255,255,0.8);
}
.prev {
left: 20px;
}
.next {
right: 20px;
}
document.addEventListener('DOMContentLoaded', () => {
const items = document.querySelectorAll('.carousel-item');
const next = document.querySelector('.next');
const prev = document.querySelector('.prev');
let currentIndex = 0;
function showSlide(index) {
// Removendo classe active de todos os slides
items.forEach(item => item.classList.remove('active'));
// Adicionando classe active ao slide atual
items[index].classList.add('active');
currentIndex = index;
}
next.addEventListener('click', () => {
let nextIndex = currentIndex + 1;
if (nextIndex >= items.length) {
nextIndex = 0;
}
showSlide(nextIndex);
});
prev.addEventListener('click', () => {
let prevIndex = currentIndex - 1;
if (prevIndex < 0) {
prevIndex = items.length - 1;
}
showSlide(prevIndex);
});
});
<button id="open-modal" class="modal-button">Abrir Modal</button>
<div class="modal" id="modal">
<div class="modal-content">
<span class="close">×</span>
<h2>Título do Modal</h2>
<p>Conteúdo do modal aqui...</p>
<button class="modal-button">Confirmar</button>
</div>
</div>
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.modal.show {
opacity: 1;
visibility: visible;
}
.modal-content {
background: white;
padding: 30px;
border-radius: 8px;
max-width: 500px;
width: 90%;
transform: scale(0.7);
transition: transform 0.3s ease;
}
.modal.show .modal-content {
transform: scale(1);
}
.close {
float: right;
font-size: 24px;
cursor: pointer;
}
.modal-button {
background: #3a86ff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s ease;
}
.modal-button:hover {
background: #1d4ed8;
}
document.addEventListener('DOMContentLoaded', () => {
const modal = document.getElementById('modal');
const openBtn = document.getElementById('open-modal');
const closeBtn = document.querySelector('.close');
openBtn.addEventListener('click', () => {
modal.classList.add('show');
});
closeBtn.addEventListener('click', () => {
modal.classList.remove('show');
});
// Fechando o modal clicando fora
window.addEventListener('click', (e) => {
if (e.target === modal) {
modal.classList.remove('show');
}
});
});
Crie um menu de navegação responsivo que use transformações e transições para os seguintes efeitos:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Menu Responsivo</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
</head>
<body>
<header class="header">
<div class="container">
<div class="logo">
<a href="#">BrandLogo</a>
</div>
<button class="hamburger" id="menu-toggle">
<span></span>
<span></span>
<span></span>
</button>
<nav class="nav-menu">
<ul class="main-menu">
<li><a href="#" class="menu-item">Home</a></li>
<li class="dropdown">
<a href="#" class="menu-item">Produtos <i class="fas fa-chevron-down"></i></a>
<ul class="dropdown-menu">
<li><a href="#">Categoria 1</a></li>
<li><a href="#">Categoria 2</a></li>
<li><a href="#">Categoria 3</a></li>
</ul>
</li>
<li><a href="#" class="menu-item">Serviços</a></li>
<li><a href="#" class="menu-item">Blog</a></li>
<li><a href="#" class="menu-item">Contato</a></li>
</ul>
<div class="social-icons">
<a href="#" class="social-icon"><i class="fab fa-facebook-f"></i></a>
<a href="#" class="social-icon"><i class="fab fa-twitter"></i></a>
<a href="#" class="social-icon"><i class="fab fa-instagram"></i></a>
<a href="#" class="social-icon"><i class="fab fa-linkedin-in"></i></a>
</div>
</nav>
</div>
</header>
<main class="main">
<div class="container">
<h1>Menu Responsivo com Transformações e Transições</h1>
<p>Redimensione a janela para ver o comportamento responsivo.</p>
</div>
</main>
<script src="script.js"></script>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #3a86ff;
--text-color: #333;
--background-color: #fff;
--transition-speed: 0.3s;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: var(--text-color);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Header e Navegação */
.header {
background: var(--background-color);
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
position: sticky;
top: 0;
z-index: 1000;
}
.header .container {
display: flex;
justify-content: space-between;
align-items: center;
height: 70px;
}
.logo a {
color: var(--primary-color);
font-size: 24px;
font-weight: bold;
text-decoration: none;
letter-spacing: 1px;
}
/* Menu Hamburger */
.hamburger {
display: none;
background: transparent;
border: none;
cursor: pointer;
padding: 10px;
z-index: 100;
}
.hamburger span {
display: block;
width: 30px;
height: 3px;
margin: 6px 0;
background: var(--text-color);
border-radius: 3px;
transition: all var(--transition-speed) ease-in-out;
}
/* Navegação Principal */
.nav-menu {
display: flex;
align-items: center;
}
.main-menu {
display: flex;
list-style: none;
}
.main-menu li {
position: relative;
margin: 0 5px;
}
.menu-item {
color: var(--text-color);
text-decoration: none;
padding: 10px 15px;
display: block;
position: relative;
font-weight: 500;
transition: color var(--transition-speed) ease;
}
/* Efeito hover com borda deslizante */
.menu-item::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
background: var(--primary-color);
transform: scaleX(0);
transform-origin: right;
transition: transform var(--transition-speed) ease-in-out;
}
.menu-item:hover {
color: var(--primary-color);
}
.menu-item:hover::after {
transform: scaleX(1);
transform-origin: left;
}
/* Dropdown */
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
width: 200px;
background: var(--background-color);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
opacity: 0;
visibility: hidden;
transform: translateY(10px);
transition: all var(--transition-speed) ease;
list-style: none;
border-radius: 4px;
overflow: hidden;
}
.dropdown:hover .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.dropdown-menu a {
color: var(--text-color);
padding: 10px 15px;
display: block;
text-decoration: none;
transition: background var(--transition-speed) ease;
}
.dropdown-menu a:hover {
background: rgba(58, 134, 255, 0.1);
}
.dropdown .fa-chevron-down {
font-size: 12px;
margin-left: 5px;
transition: transform var(--transition-speed) ease;
}
.dropdown:hover .fa-chevron-down {
transform: rotate(180deg);
}
/* Ícones Sociais */
.social-icons {
display: flex;
margin-left: 30px;
}
.social-icon {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
color: var(--text-color);
background: rgba(0,0,0,0.05);
border-radius: 50%;
margin: 0 5px;
transition: all var(--transition-speed) ease;
}
.social-icon:hover {
background: var(--primary-color);
color: white;
transform: rotate(360deg);
}
/* Main Content */
.main {
padding: 60px 0;
min-height: calc(100vh - 70px);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.main h1 {
margin-bottom: 20px;
color: var(--primary-color);
}
/* Media Query para Responsividade */
@media (max-width: 992px) {
.hamburger {
display: block;
}
/* Transformação do hamburger em X */
.hamburger.active span:nth-child(1) {
transform: translateY(9px) rotate(45deg);
}
.hamburger.active span:nth-child(2) {
opacity: 0;
}
.hamburger.active span:nth-child(3) {
transform: translateY(-9px) rotate(-45deg);
}
.nav-menu {
position: fixed;
top: 0;
right: -300px;
width: 300px;
height: 100%;
background: var(--background-color);
flex-direction: column;
padding: 70px 20px 20px;
box-shadow: -5px 0 15px rgba(0,0,0,0.1);
transition: right var(--transition-speed) ease;
overflow-y: auto;
}
.nav-menu.active {
right: 0;
}
.main-menu {
flex-direction: column;
width: 100%;
}
.main-menu li {
margin: 0;
}
.menu-item {
padding: 15px 0;
}
.dropdown-menu {
position: static;
width: 100%;
box-shadow: none;
max-height: 0;
opacity: 1;
visibility: visible;
transform: none;
transition: max-height var(--transition-speed) ease;
}
.dropdown.active .dropdown-menu {
max-height: 300px;
}
.dropdown-menu a {
padding-left: 20px;
}
.social-icons {
margin: 30px 0 0;
justify-content: center;
}
}
document.addEventListener('DOMContentLoaded', function() {
const menuToggle = document.getElementById('menu-toggle');
const navMenu = document.querySelector('.nav-menu');
const dropdowns = document.querySelectorAll('.dropdown');
// Toggle menu hamburger e navegação mobile
menuToggle.addEventListener('click', function() {
this.classList.toggle('active');
navMenu.classList.toggle('active');
});
// Manipulação dos dropdowns em mobile
if (window.innerWidth <= 992) {
dropdowns.forEach(dropdown => {
const menuItem = dropdown.querySelector('.menu-item');
menuItem.addEventListener('click', function(e) {
e.preventDefault();
dropdown.classList.toggle('active');
});
});
}
// Fecha o menu ao clicar fora dele
document.addEventListener('click', function(e) {
if (!navMenu.contains(e.target) && !menuToggle.contains(e.target) && navMenu.classList.contains('active')) {
navMenu.classList.remove('active');
menuToggle.classList.remove('active');
}
});
// Ajusta comportamento em resize da janela
window.addEventListener('resize', function() {
if (window.innerWidth > 992) {
navMenu.classList.remove('active');
menuToggle.classList.remove('active');
dropdowns.forEach(dropdown => dropdown.classList.remove('active'));
}
});
});
Documentação oficial sobre transformações CSS com exemplos detalhados.
Acessar →Explicações detalhadas sobre todas as propriedades de transição.
Acessar →Guia visual completo com todos os tipos de transformações e seus efeitos.
Acessar →Verifique o suporte de navegadores para transformações e transições CSS.
Acessar →