Shadow (sombra) — um efeito visual em interfaces móveis que cria a ilusão de profundidade e hierarquia entre elementos. As sombras mostram qual elemento está mais acima no plano z e, portanto, é mais importante ou interativo. De acordo com as Material Design Guidelines (Google, 2026), as sombras do sistema usam cinco níveis-chave de elevation: 0 dp (plano), 1–4 dp (botões), 6–12 dp (cartões), 16–24 dp (diálogos), 24+ dp (janelas modais). Saiba mais sobre a altura dos elementos no artigo sobre Elevation.
Principais pontos
Sombra (shadow) em interfaces de utilizador é um efeito visual que simula iluminação e profundidade. A sombra é criada desenhando uma cópia escura e desfocada de um elemento, deslocada em relação ao original. No design móvel, as sombras têm três funções: mostram hierarquia (quanto mais alto o elemento, mais longa a sombra), sinalizam interatividade (botões com sombra parecem pressionáveis), separam o conteúdo do fundo (cartões com sombra leem-se como blocos separados).
No Material Design da Google, as sombras estão inextricavelmente ligadas ao conceito de elevation. Cada elemento ocupa uma certa altura na coordenada z, e a sombra é uma projeção da iluminação superior. As Human Interface Guidelines da Apple não prescrevem um sistema rigoroso de alturas, mas recomendam usar sombras para criar hierarquia visual e profundidade nas interfaces.
De acordo com um estudo do Nielsen Norman Group (2024), sombras colocadas corretamente reduzem o tempo para encontrar um elemento interativo em 24%. As sombras também ajudam utilizadores com deficiência visual a distinguir os limites dos elementos. No entanto, o uso excessivo de sombras (3+ níveis num ecrã) aumenta a carga cognitiva e prejudica a perceção.
No iOS, as sombras são implementadas através das propriedades de CALayer: shadowColor define a cor da sombra, shadowOffset — deslocamento em CGSize (x, y), shadowRadius — raio de desfoque, shadowOpacity — opacidade de 0 a 1. Para desempenho, também é recomendado definir shadowPath — um UIBezierPath que descreve a forma da sombra, para que a Core Animation não a calcule automaticamente.
// UIKit: configuração de sombra via CALayer
import UIKit
let cardView = UIView()
cardView.backgroundColor = .systemBackground
cardView.layer.cornerRadius = 12
// Configuração de sombra
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.15
cardView.layer.shadowOffset = CGSize(width: 0, height: 4)
cardView.layer.shadowRadius = 8
"> Otimização: shadowPath explícito
cardView.layer.shadowPath = UIBezierPath(
roundedRect: cardView.bounds,
cornerRadius: 12
).cgPath
No SwiftUI, as sombras são definidas através do modificador .shadow() com parâmetros color, radius, x, y. O SwiftUI aplica automaticamente shadowPath e gere o desempenho de renderização. Para sombras avançadas (sombras internas, múltiplas sombras), use overlay() com LinearGradient.
// SwiftUI: sombra via modificador shadow
import SwiftUI
VStack {
Text("Cartão com sombra")
.padding()
.background(Color.white)
.cornerRadius(16)
.shadow(
color: .black.opacity(0.15),
radius: 10,
x: 0,
y: 4
)
}
Desempenho de sombras no iOS: se shadowPath não for definido, a Core Animation calcula a sombra com base na forma da camada a cada fotograma, o que pode causar lentidão durante a animação. Para elementos estáticos, defina sempre shadowPath. Para elementos animados, use shouldRasterize = true na CALayer para armazenar em cache a sombra numa camada separada. No SwiftUI, a rasterização é gerida através de .drawingGroup().
No Android, as sombras no Material Design são implementadas através de elevation — uma propriedade View que define a altura do elemento na coordenada z. O sistema renderiza automaticamente uma sombra com base em elevation e outlineProvider (contorno do elemento). Quanto maior a elevation, maior e mais desfocada é a sombra. Para Views que não herdam do Material Design (ex.: AppCompat), as sombras só funcionam com aceleração de hardware ativada.
<!-- XML: elevation através de atributos -->
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp"
app:cardElevation="6dp">
<!-- Conteúdo do cartão -->
</androidx.cardview.widget.CardView>
Para sombras personalizadas no sistema de Views do Android, use OutlineProvider. ViewOutlineProvider permite definir uma forma arbitrária através de outline.setRoundRect() ou outline.setPath(). Sem OutlineProvider, a sombra é renderizada com base na forma retangular da View, não considerando o arredondamento dos cantos.
// Kotlin: OutlineProvider personalizado para sombra
import android.graphics.Outline
import android.view.View
import android.view.ViewOutlineProvider
val myView: View = findViewById(R.id.myView)
myView.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(
0, 0, view.width, view.height,
12f // raio do canto
)
}
}
myView.elevation = 8f // altura da sombra em px
myView.translationZ = 4f // altura adicional ao pressionar
No Jetpack Compose, as sombras são geridas através de Modifier.shadow() e elevation nos componentes Card e Surface. Modifier.shadow() aceita elevation e shape. Ao contrário do sistema de Views, o Compose renderiza sombras no seu próprio pipeline de renderização, proporcionando um comportamento mais previsível em todas as versões do Android.
// Jetpack Compose: sombra via Modifier.shadow
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Card(
modifier = Modifier.shadow(
elevation = 6.dp,
shape = RoundedCornerShape(12.dp),
clip = false
),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Text("Card com sombra personalizada")
}
O uso correto de sombras melhora a perceção da interface, enquanto o uso incorreto cria ruído visual e degrada o desempenho. O Material Design define cinco níveis de elevation: 0 dp (sem sombra), 1–4 dp (botões, chips), 6–12 dp (cartões, menus), 16–24 dp (diálogos, bottom sheets), 24+ dp (janelas modais, FAB).
| Nível | Elevation | Elementos | Característica da sombra |
|---|---|---|---|
| 0 | 0 dp | Texto, ícones, fundo | Sem sombra, camada plana |
| 1 | 1–4 dp | Botões, campos de entrada | Sombra leve, pequeno deslocamento |
| 2 | 6–12 dp | Cartões, Snackbar | Sombra moderada, desfoque notável |
| 3 | 16–24 dp | Diálogos, menus | Sombra profunda, grande desfoque |
| 4 | 24+ dp | Janelas modais | Sombra máxima, elemento flutua |
Boas práticas: (1) não use sombras para elementos que não devem atrair atenção (fundos, divisores), (2) a altura da sombra deve corresponder à importância do elemento — quanto mais importante, mais alta, (3) ao pressionar um botão, diminua a elevation com animação para feedback tátil, (4) evite sombras em fundos escuros — use overlay (clarear/escurecer) em vez de sombra. No Material You (Android 12+), as sombras adaptam-se ao tema: em fundos escuros, a elevation é substituída por uma camada de cor (surface tint).
No Flutter, as sombras são implementadas através de BoxShadow dentro de BoxDecoration. BoxShadow aceita color, offset, blurRadius e spreadRadius. O Flutter suporta múltiplas sombras: passar uma lista de BoxShadow permite criar efeitos complexos — por exemplo, uma sombra externa + destaque interno. PhysicalModel é uma alternativa que simula uma sombra física baseada na forma (BeveledRectangleBorder, CircleBorder).
// Flutter: sombra via BoxDecoration + BoxShadow
import 'package:flutter/material.dart';
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
offset: Offset(0, 4),
blurRadius: 8.0,
spreadRadius: 0,
),
],
),
child: Text('Contentor com sombra'),
)
// PhysicalModel para sombra física
PhysicalModel(
color: Colors.white,
elevation: 6.0,
shadowColor: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(12.0),
child: Text('Modelo físico com sombra'),
)
Desempenho: BoxShadow com múltiplas sombras pode causar repintura a cada alteração. Para elementos estáticos, use PhysicalModel — armazena em cache a sombra numa camada separada (RepaintBoundary). No Flutter 3.16+, é suportada elevation do Material 3 com sombras adaptativas, que mudam de cor e desfoque conforme o tema (claro/escuro).
Perguntas frequentes
Elevation é a altura numérica de um elemento na coordenada z, enquanto shadow (sombra) é o efeito visual criado por essa altura. No Android, elevation é uma propriedade View que gera automaticamente uma sombra. No design, elevation e shadow são frequentemente usados de forma intercambiável, mas tecnicamente elevation é a causa e shadow é o efeito.
Verifique: (1) a View tem elevation maior que 0, (2) outlineProvider está definido (se a View não for da biblioteca Material), (3) a aceleração de hardware está ativada (android:hardwareAccelerated="true" no manifesto). CardView gere automaticamente outlineProvider. Para Views personalizadas, chame view.outlineProvider = ViewOutlineProvider.BACKGROUND.
CALayer não suporta sombras internas diretamente. Use uma combinação: CAGradientLayer com cor preta e transparência dentro de uma máscara, ou sobreponha uma UIImageView com uma sombra interna rasterizada. No SwiftUI, a sombra interna é implementada através de overlay com LinearGradient e blendMode(.multiply).
No Android, use translationZ para animação: em repouso elevation = 2 dp, ao pressionar translationZ = 4 dp (altura total 6 dp). No iOS, anime shadowOffset e shadowRadius simultaneamente com a transformação do botão. No SwiftUI, use withAnimation com alteração de elevation através de Modifier.shadow(). No Flutter, use AnimatedContainer com alteração de BoxShadow.
O Material Design recomenda não mais de três níveis de elevation num ecrã. Se houver mais elementos com sombra, agrupe-os com a mesma altura. O número excessivo de sombras cria ruído visual e reduz o desempenho de renderização em dispositivos de gama média e baixa.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também