Shadow (stín) — vizuální efekt v mobilních rozhraních, který vytváří iluzi hloubky a hierarchie mezi prvky. Stíny ukazují, který prvek je výše v Z-rovině, a je tedy důležitější nebo interaktivnější. Podle Material Design Guidelines (Google, 2026) systémové stíny používají pět klíčových výšek (elevation): 0 dp (plochý), 1–4 dp (tlačítka), 6–12 dp (karty), 16–24 dp (dialogy), 24+ dp (modální okna). Více o výšce prvků si přečtěte v článku o Elevation.
Hlavní body
Stín (shadow) v uživatelských rozhraních — vizuální efekt napodobující osvětlení a hloubku. Stín se vytváří kreslením tmavé rozmazané kopie prvku posunuté vůči originálu. V mobilním designu plní stíny tři funkce: ukazují hierarchii (vyšší prvek — delší stín), signalizují interaktivitu (tlačítka se stínem vypadají klikatelně), oddělují obsah od pozadí (karty se stínem jsou vnímány jako samostatné bloky).
V Material Design od Google jsou stíny neoddělitelně spojeny s konceptem elevation (výšky). Každý prvek zaujímá určitou výšku v Z-souřadnici a stín je projekce osvětlení shora. Human Interface Guidelines od Apple nepředepisují přísný systém výšek, ale doporučují používat stíny k vytvoření vizuální hierarchie a hloubky v rozhraních.
Podle výzkumu Nielsen Norman Group (2024) správně umístěné stíny zkracují dobu hledání interaktivního prvku o 24%. Stíny také pomáhají uživatelům s poruchami zraku rozlišovat hranice prvků. Nadměrné používání stínů (3+ úrovně na obrazovce) však zvyšuje kognitivní zátěž a zhoršuje vnímání.
Na iOS jsou stíny implementovány přes vlastnosti CALayer: shadowColor nastavuje barvu stínu, shadowOffset — posun v CGSize (x, y), shadowRadius — poloměr rozmazání, shadowOpacity — neprůhlednost od 0 do 1. Pro výkon se doporučuje také nastavit shadowPath — UIBezierPath, který popisuje tvar stínu, aby jej Core Animation nepočítala automaticky.
// UIKit: nastavení stínu přes CALayer
import UIKit
let cardView = UIView()
cardView.backgroundColor = .systemBackground
cardView.layer.cornerRadius = 12
// Nastavení stínu
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.15
cardView.layer.shadowOffset = CGSize(width: 0, height: 4)
cardView.layer.shadowRadius = 8
"> Optimalizace: explicitní shadowPath
cardView.layer.shadowPath = UIBezierPath(
roundedRect: cardView.bounds,
cornerRadius: 12
).cgPath
V SwiftUI se stíny nastavují přes modifikátor .shadow() s parametry color, radius, x, y. SwiftUI automaticky aplikuje shadowPath a spravuje výkon vykreslování. Pro pokročilé stíny (vnitřní stíny, vícenásobné stíny) použijte overlay() s LinearGradient.
// SwiftUI: stín přes modifikátor shadow
import SwiftUI
VStack {
Text("Karta se stínem")
.padding()
.background(Color.white)
.cornerRadius(16)
.shadow(
color: .black.opacity(0.15),
radius: 10,
x: 0,
y: 4
)
}
Výkon stínů na iOS: pokud shadowPath není nastaven, Core Animation počítá stín na základě tvaru vrstvy v každém snímku, což může způsobovat zpomalení během animace. U statických prvků vždy nastavujte shadowPath. U animovaných prvků použijte shouldRasterize = true na CALayer pro ukládání stínu do samostatné vrstvy. Ve SwiftUI je rasterizace spravována přes .drawingGroup().
V Androidu jsou stíny v Material Design implementovány přes elevation — vlastnost View, která nastavuje výšku prvku v Z-souřadnici. Systém automaticky kreslí stín na základě elevation a outlineProvider (obrysu prvku). Čím vyšší elevation, tím větší a rozmazanější stín. U View, která nedědí z Material Design (např. AppCompat), stíny fungují pouze s zapnutou hardwarovou akcelerací.
<!-- XML: elevation přes atributy -->
<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">
<!-- Obsah karty -->
</androidx.cardview.widget.CardView>
Pro vlastní stíny v Android View System se používá OutlineProvider. ViewOutlineProvider umožňuje nastavit libovolný tvar přes outline.setRoundRect() nebo outline.setPath(). Bez OutlineProvider se stín kreslí podle obdélníkového tvaru View, což nezohledňuje zaoblení rohů.
// Kotlin: vlastní OutlineProvider pro stín
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 // poloměr rohu
)
}
}
myView.elevation = 8f // výška stínu v px
myView.translationZ = 4f // další výška při stisknutí
V Jetpack Compose jsou stíny spravovány přes Modifier.shadow() a elevation v komponentách Card a Surface. Modifier.shadow() přijímá elevation a shape. Na rozdíl od View System, Compose kreslí stíny ve vlastním renderovacím pipeline, což poskytuje předvídatelnější chování na všech verzích Androidu.
// Jetpack Compose: stín přes 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 s vlastním stínem")
}
Správné použití stínů zlepšuje vnímání rozhraní, nesprávné — vytváří vizuální šum a zhoršuje výkon. Material Design definuje pět úrovní elevation: 0 dp (bez stínu), 1–4 dp (tlačítka, chipsy), 6–12 dp (karty, menu), 16–24 dp (dialogy, spodní panely), 24+ dp (modální okna, FAB).
| Úroveň | Elevation | Prvky | Charakteristika stínu |
|---|---|---|---|
| 0 | 0 dp | Text, ikony, pozadí | Bez stínu, plochá vrstva |
| 1 | 1–4 dp | Tlačítka, vstupní pole | Lehký stín, malý posun |
| 2 | 6–12 dp | Karty, Snackbar | Mírný stín, znatelné rozmazání |
| 3 | 16–24 dp | Dialogy, menu | Hluboký stín, velké rozmazání |
| 4 | 24+ dp | Modální okna | Maximální stín, prvek se vznáší |
Pravidla správné praxe: (1) nepoužívejte stíny pro prvky, které by neměly přitahovat pozornost (pozadí, oddělovače), (2) výška stínu by měla odpovídat důležitosti prvku — čím důležitější, tím vyšší, (3) při stisknutí tlačítka snižujte elevation animovaně pro hmatovou zpětnou vazbu, (4) vyhýbejte se stínům na tmavých pozadích — použijte overlay (zesvětlení/ztmavení) místo stínu. V Material You (Android 12+) se stíny přizpůsobují motivu: na tmavém pozadí je elevation nahrazena barevnou vrstvou (surface tint).
Ve Flutteru jsou stíny implementovány přes BoxShadow uvnitř BoxDecoration. BoxShadow přijímá color, offset, blurRadius a spreadRadius. Flutter podporuje vícenásobné stíny: předání seznamu BoxShadow umožňuje vytvářet komplexní efekty — například vnější stín + vnitřní osvětlení. PhysicalModel — alternativa, která simuluje fyzický stín na základě tvaru (BeveledRectangleBorder, CircleBorder).
// Flutter: stín přes 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('Kontejner se stínem'),
)
// PhysicalModel pro fyzický stín
PhysicalModel(
color: Colors.white,
elevation: 6.0,
shadowColor: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(12.0),
child: Text('Fyzický model se stínem'),
)
Výkon: BoxShadow s vícenásobnými stíny může způsobovat překreslování (repaint) při každé změně. U statických prvků použijte PhysicalModel — ukládá stín do samostatné vrstvy (RepaintBoundary). Ve Flutteru 3.16+ byla přidána podpora pro Material 3 elevation s adaptivními stíny, které mění barvu a rozmazání v závislosti na motivu (světlý/tmavý).
Často kladené otázky
Elevation — je číselná výška prvku v Z-souřadnici, zatímco shadow (stín) — vizuální efekt vytvořený touto výškou. V Androidu je elevation vlastnost View, která automaticky generuje stín. V designu se elevation a shadow často používají jako zaměnitelné termíny, ale technicky je elevation příčina a shadow následek.
Zkontrolujte: (1) má View elevation větší než 0, (2) je nastaven outlineProvider (pokud View není z Material knihovny), (3) je zapnutá hardwarová akcelerace (android:hardwareAccelerated="true" v manifestu). CardView automaticky spravuje outlineProvider. U vlastních View zavolejte view.outlineProvider = ViewOutlineProvider.BACKGROUND.
CALayer přímo nepodporuje vnitřní stíny. Použijte kombinaci: CAGradientLayer s černou barvou a průhledností uvnitř masky (mask), nebo vložte UIImageView s rastrovým vnitřním stínem. Ve SwiftUI je vnitřní stín implementován přes overlay s LinearGradient a blendMode(.multiply).
V Androidu použijte translationZ pro animaci: v klidu elevation = 2 dp, při stisknutí translationZ = 4 dp (celková výška 6 dp). Na iOS animujte shadowOffset a shadowRadius současně s transformací tlačítka. Ve SwiftUI použijte withAnimation se změnou elevation přes Modifier.shadow(). Ve Flutteru — AnimatedContainer se změnou BoxShadow.
Material Design doporučuje ne více než tři úrovně elevation na jedné obrazovce. Pokud je prvků se stínem více — sdružte je do skupin se stejnou výškou. Nadměrný počet stínů vytváří vizuální šum a snižuje výkon vykreslování na zařízeních střední a nízké třídy.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také