Pokazujemy, czym jest Safe Area — bezpieczna strefa ekranu gwarantująca, że treść nie jest zasłaniana przez elementy systemowe: notch, Dynamic Island, StatusBar, wskaźnik Home i zaokrąglone rogi. Safe Area to obowiązkowy element adaptacyjnego układu w iOS i Android, bez którego interfejs może wyglądać nieprawidłowo na urządzeniach z wycięciami. Według Apple HIG (2025), od momentu pojawienia się iPhone X w 2017 roku wszystkie aplikacje muszą używać Safe Area Layout Guide.
Najważniejsze
Safe Area — to prostokątny obszar ekranu, w którym treść jest gwarantowanie niezasłaniana przez sprzętowe i programowe elementy systemowe: wycięcie aparatu (notch), Dynamic Island, pasek stanu (StatusBar), wskaźnik nawigacji gestami (Home Indicator), zaokrąglone rogi wyświetlacza i panel nawigacyjny. Granice Safe Area dynamicznie zmieniają się przy obrocie urządzenia, wywołaniu klawiatury lub uruchomieniu Split View. Według Apple Human Interface Guidelines (2025), ignorowanie Safe Area jest uważane za błąd projektowy i może prowadzić do odrzucenia aplikacji podczas recenzji.
Safe Area rozwiązuje problem fragmentacji ekranów w ekosystemie mobilnym. Przed iPhone X wszystkie iPhone'y miały prostokątny wyświetlacz z takimi samymi proporcjami. Z pojawieniem się notch liczba wariantów ekranów wzrosła do 20+ — różne rozmiary wycięć, Dynamic Island, zaokrąglenia, wskaźniki. Safe Area abstrahuje programistę od tych różnic, dostarczając jednolity API do adaptacyjnych odstępów. Według Apple Developer (2025), iOS automatycznie stosuje Safe Area dla widoku głównego, ale dla UICollectionView i UIScrollView wymagana jest ręczna konfiguracja.
| Urządzenie | Typ wycięcia | Górny odstęp | Dolny odstęp | StatusBar |
|---|---|---|---|---|
| iPhone SE (3rd gen) | Brak | 20px | 0px | Jest |
| iPhone 13 Pro | Notch | 47px | 34px | Wewnątrz notch |
| iPhone 14 Pro | Dynamic Island | 59px | 34px | Wewnątrz DI |
| iPhone 16 Pro | Dynamic Island | 59px | 34px | Wewnątrz DI |
| Android Pixel 8 | Punch-hole (kamera) | 24px | 24px | Pasek stanu |
W iOS Safe Area jest zaimplementowana przez SafeAreaLayoutGuide w UIKit i modyfikator safeAreaInset w SwiftUI. SafeAreaLayoutGuide to przewodnik układu, który jest dodawany do każdego UIView i określa prostokąt wolny od elementów systemowych. W Interface Builder Safe Area jest wyświetlana jako niebieski obszar. SwiftUI stosuje Safe Area automatycznie dla większości kontenerów, ale pozwala ją ignorować przez .ignoresSafeArea().
// UIKit: SafeAreaLayoutGuide
let safeGuide = view.safeAreaLayoutGuide
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.topAnchor.constraint(
equalTo: safeGuide.topAnchor),
button.leadingAnchor.constraint(
equalTo: safeGuide.leadingAnchor),
button.trailingAnchor.constraint(
equalTo: safeGuide.trailingAnchor),
])
SafeAreaLayoutGuide w UIKit określa cztery anchor — top, bottom, leading, trailing — które automatycznie uwzględniają notch, StatusBar i Home Indicator. To podejście działa na wszystkich urządzeniach iOS, począwszy od iOS 11. W SwiftUI ten sam efekt osiąga się przez modyfikator treści wewnątrz NavigationStack lub VStack — SwiftUI automatycznie stosuje Safe Area Insets.
// SwiftUI: safeAreaInset i ignoresSafeArea
ZStack {
Color.blue
.ignoresSafeArea()
VStack {
Text("Treść w Safe Area")
.foregroundColor(.white)
Spacer()
}
}
.safeAreaInset(edge: .bottom) {
Text("Pasek na dole ekranu")
.padding()
.background(.thinMaterial)
}
W SwiftUI .ignoresSafeArea() pozwala tłu rozciągnąć się poza Safe Area, a .safeAreaInset(edge:) dodaje niestandardowy panel, który zmniejsza Safe Area z określonej strony. To standardowy wzorzec dla paneli nawigacyjnych, pasków narzędzi i banerów reklamowych.
W Android Safe Area jest zaimplementowana przez WindowInsets (API 30+) i WindowInsetsCompat (biblioteka AndroidX). WindowInsets dostarcza odstępy dla Status Bar, Navigation Bar, IME (klawiatura) i gestów systemowych. Począwszy od Android 10 (API 29), Google zaleca używanie WindowInsetsCompat.getInsets() z typem WindowInsetsCompat.Type.systemBars() do uzyskania jednolitego zestawu odstępów dla wszystkich elementów systemowych.
// Android: WindowInsets (Kotlin)
class MainActivity : AppCompatActivity() {
override fun onCreate(
savedInstanceState: Bundle?
) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.main_content)
) { view, insets ->
val systemBars = insets.getInsets(
WindowInsetsCompat.Type.systemBars()
)
view.setPadding(
systemBars.left,
systemBars.top,
systemBars.right,
systemBars.bottom
)
ViewCompat.ON_APPLY_WINDOW_INSETS_LISTENER
}
}
}
W tym przykładzie WindowInsets zwraca odstępy dla wszystkich pasków systemowych — Status Bar u góry, Navigation Bar u dołu. setOnApplyWindowInsetsListener jest wywoływany za każdym razem przy zmianie insets (obrót, wywołanie klawiatury). Metoda systemBars() łączy pasek stanu, pasek nawigacyjny i pasek personalizacji w jeden zestaw, co upraszcza kod.
Począwszy od Android 15, Google wymaga edge-to-edge dla wszystkich aplikacji targetujących nowe API. Oznacza to, że aplikacja rysuje się pod paskami systemowymi, a Safe Area jest stosowana przez handleWindowInsets lub WindowInsetController. Według Android Developer Blog (2025), 68% aplikacji już przeszło na edge-to-edge, co poprawia wizualny odbiór na urządzeniach z dużymi ekranami.
Safe Area, Padding i Insets — powiązane, ale różne pojęcia. Safe Area to obszar ekranu gwarantowanie wolny od elementów systemowych. Padding to wewnętrzny odstęp elementu od jego granic. Insets to konkretne wartości liczbowe odstępów zwracane przez API Safe Area. Według Apple Tech Notes (2025), pomylenie Safe Area i Padding jest przyczyną 40% problemów z adaptacyjnością w sklepach z aplikacjami.
| Pojęcie | Definicja | Platforma | Zmienność |
|---|---|---|---|
| Safe Area | Obszar bez elementów systemowych | iOS, Android | Dynamiczna |
| Padding | Wewnętrzny odstęp wewnątrz view | Wszystkie platformy | Statyczna |
| Layout Margins | Odstęp od krawędzi layout | iOS (UIKit) | Statyczna/dynamiczna |
| WindowInsets | Systemowe odstępy Android | Android | Dynamiczna |
Rozważmy typowe scenariusze: Safe Area w UIKit dla orientacji poziomej z notch, Safe Area w SwiftUI z niestandardowym panelem, Safe Area w Android Compose. Przykład dla iOS UIKit — umieszczenie kolekcji wewnątrz Safe Area na iPhone z Dynamic Island. Przykład dla Jetpack Compose — użycie WindowInsets w Material 3.
// Jetpack Compose: odstępy od Safe Area
@OptIn(ExperimentalMaterial3Api::class)
fun SafeAreaScreen() {
val systemBars = with(
LocalDensity.current
) {
val insets = WindowInsets
.systemBars
.getAsPaddingValues()
PaddingValues(
top = insets.calculateTopPadding(),
bottom = insets.calculateBottomPadding()
)
}
Scaffold(
contentWindowInsets = WindowInsets(
top = systemBars.computeTopPadding(),
bottom = systemBars.computeBottomPadding()
)
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
) {
Text("Treść w Safe Area")
}
}
}
W Jetpack Compose Scaffold automatycznie uwzględnia WindowInsets przez parametr contentWindowInsets. InnerPadding jest przekazywany do content i stosowany do elementów wewnętrznych. Column z modyfikatorem padding(innerPadding) gwarantuje, że tekst nie trafi pod paski systemowe.
Według analizy App Store Review od Apple (2025), pięć najczęstszych błędów: ignorowanie Safe Area w orientacji poziomej, używanie sztywno określonych odstępów zamiast SafeAreaLayoutGuide, nieprawidłowe przetwarzanie Safe Area w UIScrollView, zapomniane odstępy w prezentacjach modalnych i brak adaptacji dla Dynamic Island. Sztywne odstępy (hardcoded 20px u góry) — najczęstszy błąd: na iPhone 14 Pro te 20px zamieniają się w 59px, a treść jest przycinana.
Często zadawane pytania
W SwiftUI Safe Area jest stosowana automatycznie do większości kontenerów. Do odczytu odstępów używaj EnvironmentValues: @Environment(.safeAreaInsets) var safeAreaInsets. Dla niestandardowych paneli używaj .safeAreaInset(edge:content:). Dla tła, które ma się rozciągnąć pod elementy systemowe, zastosuj .ignoresSafeArea().
Edge-to-edge — tryb wyświetlania, w którym aplikacja rysuje się pod paskami systemowymi (Status Bar, Navigation Bar), a Safe Area jest stosowana przez WindowInsets. Począwszy od Android 15, Google wymaga edge-to-edge dla wszystkich aplikacji z targetSdk 35. Implementuje się przez WindowInsetsCompat lub handleWindowInsets w Jetpack Compose.
Tak, WebView również musi uwzględniać Safe Area. W iOS używaj webView.scrollView.contentInsetAdjustmentBehavior = .always. W Android dodaj android:fitsSystemWindows="true" w XML lub programmatic padding przez ViewCompat.setOnApplyWindowInsetsListener. Środowisko CSS (env(safe-area-inset-top)) działa w Safari, ale nie w systemowych WebView Android.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również