Safe Area — là gì, khoảng cách từ notch và StatusBar

Tác giả: IT Sectr Đã đăng: 2026-02-25 Thời gian đọc: 8 phút

Chúng tôi trình bày Safe Area là gì — vùng an toàn màn hình đảm bảo nội dung không bị che bởi các thành phần hệ thống: notch, Dynamic Island, StatusBar, chỉ báo Home và các góc bo tròn. Safe Area là thành phần bắt buộc của bố cục thích ứng trong iOS và Android, nếu thiếu nó, giao diện có thể hiển thị không chính xác trên các thiết bị có khuyết. Theo Apple HIG (2025), kể từ khi iPhone X ra mắt năm 2017, tất cả ứng dụng phải sử dụng Safe Area Layout Guide.

Những điểm chính

  • Safe Area — vùng màn hình không có các thành phần hệ thống: notch, StatusBar, Home Indicator, góc bo tròn.
  • Trong iOS, Safe Area được triển khai qua SafeAreaLayoutGuide và bổ ngữ .safeAreaInset() trong SwiftUI.
  • Trong Android, Safe Area được triển khai qua WindowInsets và WindowInsetsCompat để tương thích ngược.
  • Dynamic Island trên iPhone 14 Pro trở lên thay thế notch và cũng được xem xét trong Safe Area.
  • Theo Google Android Docs (2025), bỏ qua Safe Area là một trong ba lý do chính khiến ứng dụng bị từ chối trên Google Play và App Store.

Safe Area là gì?

Safe Area là vùng hình chữ nhật trên màn hình nơi nội dung được đảm bảo không bị che bởi các thành phần hệ thống phần cứng và phần mềm: khuyết camera (notch), Dynamic Island, thanh trạng thái (StatusBar), chỉ báo điều hướng cử chỉ (Home Indicator), góc màn hình bo tròn và thanh điều hướng. Ranh giới của Safe Area thay đổi động khi xoay thiết bị, gọi bàn phím hoặc khởi động Split View. Theo Apple Human Interface Guidelines (2025), bỏ qua Safe Area được coi là lỗi thiết kế và có thể dẫn đến việc ứng dụng bị từ chối trong quá trình xét duyệt.

Tại sao cần Safe Area

Safe Area giải quyết vấn đề phân mảnh màn hình trong hệ sinh thái di động. Trước iPhone X, tất cả iPhone đều có màn hình hình chữ nhật với tỷ lệ giống nhau. Với sự ra đời của notch, số lượng biến thể màn hình đã tăng lên hơn 20 — kích thước notch khác nhau, Dynamic Island, góc bo tròn, chỉ báo. Safe Area trừu tượng hóa nhà phát triển khỏi những khác biệt này bằng cách cung cấp API thống nhất cho khoảng cách thích ứng. Theo Apple Developer (2025), iOS tự động áp dụng Safe Area cho view gốc, nhưng UICollectionView và UIScrollView yêu cầu cấu hình thủ công.

Thiết bịLoại khuyếtKhoảng cách trênKhoảng cách dướiStatusBar
iPhone SE (thế hệ 3)Không có20px0px
iPhone 13 ProNotch47px34pxTrong notch
iPhone 14 ProDynamic Island59px34pxTrong DI
iPhone 16 ProDynamic Island59px34pxTrong DI
Android Pixel 8Punch-hole (camera)24px24pxThanh trạng thái

Safe Area trong iOS: SafeAreaLayoutGuide và SwiftUI

Trong iOS, Safe Area được triển khai qua SafeAreaLayoutGuide trong UIKit và bổ ngữ safeAreaInset trong SwiftUI. SafeAreaLayoutGuide là một hướng dẫn bố cục được thêm vào mỗi UIView và xác định hình chữ nhật không có thành phần hệ thống. Trong Interface Builder, Safe Area hiển thị dưới dạng vùng màu xanh lam. SwiftUI tự động áp dụng Safe Area cho hầu hết các container nhưng cho phép bỏ qua qua .ignoresSafeArea().

Swift
// 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 trong UIKit xác định bốn neo — trên, dưới, đầu, cuối — tự động tính đến notch, StatusBar và Home Indicator. Cách tiếp cận này hoạt động trên tất cả thiết bị iOS từ iOS 11 trở đi. Trong SwiftUI, hiệu ứng tương tự đạt được qua bổ ngữ nội dung bên trong NavigationStack hoặc VStack — SwiftUI tự động áp dụng Safe Area Insets.

Swift
// SwiftUI: safeAreaInset và ignoresSafeArea
ZStack {
    Color.blue
        .ignoresSafeArea()
    VStack {
        Text("Nội dung trong Safe Area")
            .foregroundColor(.white)
        Spacer()
    }
}
.safeAreaInset(edge: .bottom) {
    Text("Thanh ở cuối màn hình")
        .padding()
        .background(.thinMaterial)
}

Trong SwiftUI, .ignoresSafeArea() cho phép nền mở rộng ra ngoài Safe Area, trong khi .safeAreaInset(edge:) thêm bảng tùy chỉnh làm giảm Safe Area ở phía được chỉ định. Đây là mẫu tiêu chuẩn cho thanh điều hướng, thanh công cụ và biểu ngữ quảng cáo.

Safe Area trong Android: WindowInsets và System Bars

Trong Android, Safe Area được triển khai qua WindowInsets (API 30+) và WindowInsetsCompat (thư viện AndroidX). WindowInsets cung cấp khoảng cách cho Status Bar, Navigation Bar, IME (bàn phím) và cử chỉ hệ thống. Bắt đầu từ Android 10 (API 29), Google khuyến nghị sử dụng WindowInsetsCompat.getInsets() với WindowInsetsCompat.Type.systemBars() để có bộ khoảng cách thống nhất cho tất cả thành phần hệ thống.

Kotlin
// 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
        }
    }
}

Trong ví dụ này, WindowInsets trả về khoảng cách cho tất cả thanh hệ thống — Status Bar ở trên, Navigation Bar ở dưới. setOnApplyWindowInsetsListener được gọi mỗi khi khoảng cách thay đổi (xoay, gọi bàn phím). Phương thức systemBars() kết hợp thanh trạng thái, thanh điều hướng và thanh tùy chỉnh thành một tập hợp, đơn giản hóa mã.

Edge-to-Edge trong Android

Bắt đầu từ Android 15, Google yêu cầu hiển thị edge-to-edge cho tất cả ứng dụng nhắm mục tiêu API mới. Điều này có nghĩa là ứng dụng vẽ bên dưới các thanh hệ thống và Safe Area được áp dụng qua handleWindowInsets hoặc WindowInsetController. Theo Android Developer Blog (2025), 68% ứng dụng đã chuyển sang edge-to-edge, cải thiện nhận thức thị giác trên thiết bị có màn hình lớn.

Safe Area, Padding và Insets: khác biệt là gì

Safe Area, Padding và Insets là các khái niệm liên quan nhưng khác nhau. Safe Area là vùng màn hình được đảm bảo không có thành phần hệ thống. Padding là khoảng cách bên trong của một phần tử từ các cạnh của nó. Insets là các giá trị bù số cụ thể do API Safe Area trả về. Theo Apple Tech Notes (2025), nhầm lẫn giữa Safe Area và Padding là nguyên nhân của 40% vấn đề thích ứng trong các cửa hàng ứng dụng.

Khái niệmĐịnh nghĩaNền tảngTính thay đổi
Safe AreaVùng không có thành phần hệ thốngiOS, AndroidĐộng
PaddingKhoảng cách bên trong viewTất cả nền tảngTĩnh
Layout MarginsKhoảng cách từ mép bố cụciOS (UIKit)Tĩnh/động
WindowInsetsKhoảng cách hệ thống trong AndroidAndroidĐộng

Ví dụ triển khai Safe Area với mã

Hãy xem xét các kịch bản điển hình: Safe Area trong UIKit cho hướng ngang với notch, Safe Area trong SwiftUI với bảng tùy chỉnh, Safe Area trong Android Compose. Ví dụ cho iOS UIKit — đặt bộ sưu tập trong Safe Area trên iPhone có Dynamic Island. Ví dụ cho Jetpack Compose — sử dụng WindowInsets trong Material 3.

Kotlin
// Jetpack Compose: khoảng cách 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("Nội dung trong Safe Area")
        }
    }
}

Trong Jetpack Compose, Scaffold tự động xem xét WindowInsets qua tham số contentWindowInsets. InnerPadding được truyền cho nội dung và áp dụng cho các phần tử bên trong. Column với bổ ngữ padding(innerPadding) đảm bảo văn bản không nằm dưới các thanh hệ thống.

Lỗi thường gặp khi làm việc với Safe Area

Theo phân tích App Store Review của Apple (2025), năm lỗi phổ biến nhất là: bỏ qua Safe Area ở hướng ngang, sử dụng khoảng cách cứng thay vì SafeAreaLayoutGuide, xử lý Safe Area không đúng trong UIScrollView, quên khoảng cách trong trình bày modal và thiếu thích ứng cho Dynamic Island. Khoảng cách cứng (20px cố định ở trên) là lỗi phổ biến nhất: trên iPhone 14 Pro, 20px đó trở thành 59px và nội dung bị cắt.

  • Bỏ qua hướng ngang — ở hướng ngang, Safe Area có khoảng cách khác: Home Indicator di chuyển sang phải và khoảng cách trên giảm.
  • Khoảng cách cứng — giá trị 20px hoặc 44px chỉ hoạt động trên iPhone cũ không có notch. Trên thiết bị hiện đại, khoảng cách chênh lệch 2-3 lần.
  • ScrollView và Safe Area — contentInsetAdjustmentBehavior trong UIScrollView cần được đặt thành .always, nếu không nội dung sẽ bị ẩn dưới các thanh hệ thống.

Câu hỏi thường gặp

Làm thế nào để lấy khoảng cách Safe Area trong SwiftUI?

Trong SwiftUI, Safe Area được áp dụng tự động cho hầu hết container. Để đọc khoảng cách, hãy sử dụng EnvironmentValues: @Environment(\.safeAreaInsets) var safeAreaInsets. Cho bảng tùy chỉnh, hãy sử dụng .safeAreaInset(edge:content:). Cho nền cần mở rộng dưới các thành phần hệ thống, hãy áp dụng .ignoresSafeArea().

Edge-to-edge trong Android là gì?

Edge-to-edge là chế độ hiển thị nơi ứng dụng vẽ dưới các thanh hệ thống (Status Bar, Navigation Bar) và Safe Area được áp dụng qua WindowInsets. Bắt đầu từ Android 15, Google yêu cầu edge-to-edge cho tất cả ứng dụng có targetSdk 35. Nó được triển khai qua WindowInsetsCompat hoặc handleWindowInsets trong Jetpack Compose.

Tôi có cần xử lý Safe Area cho WebView không?

Có, WebView cũng phải xem xét Safe Area. Trong iOS, hãy sử dụng webView.scrollView.contentInsetAdjustmentBehavior = .always. Trong Android, thêm android:fitsSystemWindows="true" trong XML hoặc padding lập trình qua ViewCompat.setOnApplyWindowInsetsListener. Môi trường CSS (env(safe-area-inset-top)) hoạt động trong Safari nhưng không hoạt động trong WebView hệ thống Android.

Tổng kết

  • Safe Area — vùng màn hình không có notch, Dynamic Island, StatusBar và Home Indicator.
  • iOS: triển khai qua SafeAreaLayoutGuide trong UIKit và .safeAreaInset trong SwiftUI.
  • Android: triển khai qua WindowInsets (API 30+) hoặc WindowInsetsCompat (AndroidX).
  • Dynamic Island trên iPhone 14 Pro trở lên tăng khoảng cách trên của Safe Area lên 59px.
  • Bỏ qua Safe Area là một trong những lý do chính khiến ứng dụng bị từ chối trên App Store và Google Play.
  • Khoảng cách cứng không được chấp nhận — luôn sử dụng API lập trình của Safe Area.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm