Shadow: podstata, vytváření stínů v mobilních aplikacích

Autor: IT Sectr Publikováno: 2026-02-28 Doba čtení: 9 min

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) — vizuální efekt vytvářející hloubku ztmavením oblasti pod prvkem s rozmazáním na okrajích.
  • Na iOS se stíny nastavují přes vlastnosti CALayer: shadowColor, shadowOffset, shadowRadius, shadowOpacity.
  • V Androidu jsou stíny spravovány přes elevation (Material Design) nebo vlastní vykreslování přes OutlineProvider.
  • Jetpack Compose podporuje stíny přes Modifier.shadow() a elevation v Card/Surface.
  • Ve Flutteru jsou stíny implementovány přes BoxShadow v BoxDecoration nebo přes PhysicalModel.

Co je stín v UI?

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í.

Stíny na iOS: CALayer a SwiftUI

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.

swift
// 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.

swift
// 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().

Stíny v Androidu: elevation a vlastní stíny

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
<!-- 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
// 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.

kotlin
// 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")
}

Doporučení pro použití stínů

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ňElevationPrvkyCharakteristika stínu
00 dpText, ikony, pozadíBez stínu, plochá vrstva
11–4 dpTlačítka, vstupní poleLehký stín, malý posun
26–12 dpKarty, SnackbarMírný stín, znatelné rozmazání
316–24 dpDialogy, menuHluboký stín, velké rozmazání
424+ dpModální oknaMaximá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).

Stíny ve Flutteru: BoxShadow a PhysicalModel

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).

dart
// 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

Čím se elevation liší od stínu?

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.

Proč se stín nezobrazuje na Androidu?

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.

Jak vytvořit vnitřní stín (inner shadow) na iOS?

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).

Jak animovat stín při stisknutí tlačítka?

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.

Kolik stínů lze použít na jedné obrazovce?

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í

  • Stín (shadow) — vizuální efekt hloubky založený na elevation prvku v Z-souřadnici.
  • Na iOS se stíny konfigurují přes CALayer: shadowColor, shadowOffset, shadowRadius, shadowOpacity.
  • V Androidu jsou stíny spravovány přes elevation a OutlineProvider pro vlastní tvar.
  • Material Design definuje pět úrovní elevation: 0, 1–4, 6–12, 16–24 a 24+ dp.
  • Jetpack Compose používá Modifier.shadow() a elevation v Card/Surface pro správu stínů.
  • Flutter implementuje stíny přes BoxShadow (BoxDecoration) a PhysicalModel (fyzický stín).
  • Optimalizace: nastavte shadowPath (iOS), outlineProvider (Android), použijte PhysicalModel (Flutter).

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í.

Prodiskutovat projekt

Přečtěte si také