Shadow (тень) — визуальный эффект в мобильных интерфейсах, который создаёт иллюзию глубины и иерархии между элементами. Тени показывают, какой элемент находится выше в z-плоскости и, следовательно, является более важным или интерактивным. По данным Material Design Guidelines (Google, 2026), системные тени используют пять ключевых высот (elevation): 0 dp (плоский), 1–4 dp (кнопки), 6–12 dp (карточки), 16–24 dp (диалоги), 24+ dp (модальные окна). Подробнее о высоте элементов читайте в статье об Elevation.
Главное
Тень (shadow) в пользовательских интерфейсах — это визуальный эффект, имитирующий освещение и глубину. Тень создаётся путём отрисовки тёмной размытой копии элемента, смещённой относительно оригинала. В мобильном дизайне тени выполняют три функции: показывают иерархию (выше элемент — длиннее тень), сигнализируют об интерактивности (кнопки с тенью выглядят нажимаемыми), отделяют контент от фона (карточки с тенью читаются как отдельные блоки).
В Material Design Google тени неразрывно связаны с концепцией elevation (высоты). Каждый элемент занимает определённую высоту в z-координате, и тень — это проекция освещения сверху. Human Interface Guidelines Apple не предписывают строгую систему высот, но рекомендуют использовать тени для создания визуальной иерархии и глубины в интерфейсах.
По данным исследования Nielsen Norman Group (2024), правильно расставленные тени сокращают время поиска интерактивного элемента на 24%. Тени также помогают пользователям с нарушениями зрения различать границы элементов. Однако избыточное использование теней (3+ уровня на экране) увеличивает когнитивную нагрузку и ухудшает восприятие.
На iOS тени реализуются через свойства CALayer: shadowColor задаёт цвет тени, shadowOffset — смещение в CGSize (x, y), shadowRadius — радиус размытия, shadowOpacity — непрозрачность от 0 до 1. Для производительности рекомендуется также задавать shadowPath — UIBezierPath, который описывает форму тени, чтобы Core Animation не вычисляла её автоматически.
// UIKit: настройка тени через CALayer
import UIKit
let cardView = UIView()
cardView.backgroundColor = .systemBackground
cardView.layer.cornerRadius = 12
// Настройка тени
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.15
cardView.layer.shadowOffset = CGSize(width: 0, height: 4)
cardView.layer.shadowRadius = 8
"> Optimзация: явный shadowPath
cardView.layer.shadowPath = UIBezierPath(
roundedRect: cardView.bounds,
cornerRadius: 12
).cgPath
В SwiftUI тени задаются через модификатор .shadow() с параметрами color, radius, x, y. SwiftUI автоматически применяет shadowPath и управляет производительностью рендеринга. Для продвинутых теней (внутренние тени, множественные тени) используйте overlay() с LinearGradient.
// SwiftUI: тень через модификатор shadow
import SwiftUI
VStack {
Text("Карточка с тенью")
.padding()
.background(Color.white)
.cornerRadius(16)
.shadow(
color: .black.opacity(0.15),
radius: 10,
x: 0,
y: 4
)
}
Производительность теней на iOS: если shadowPath не задан, Core Animation вычисляет тень на основе формы слоя каждый кадр, что может вызывать подтормаживания при анимации. Для статичных элементов всегда задавайте shadowPath. Для анимированных элементов используйте shouldRasterize = true на CALayer, чтобы кэшировать тень в отдельный слой. В SwiftUI rasterization управляется через .drawingGroup().
В Android тени в Material Design реализуются через elevation — свойство View, которое задаёт высоту элемента в z-координате. Система автоматически отрисовывает тень на основе elevation и outlineProvider (контура элемента). Чем выше elevation, тем больше и размытее тень. Для View, не наследующих Material Design (например, AppCompat), тени работают только при включённом аппаратном ускорении.
<!-- XML: elevation через атрибуты -->
<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">
<!-- Контент карточки -->
</androidx.cardview.widget.CardView>
Для кастомных теней в Android View System используется OutlineProvider. ViewOutlineProvider позволяет задать произвольную форму через outline.setRoundRect() или outline.setPath(). Без OutlineProvider тень отрисовывается по прямоугольной форме View, что не учитывает скругление углов.
// Kotlin: кастомный OutlineProvider для тени
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 // corner radius
)
}
}
myView.elevation = 8f // высота тени в px
myView.translationZ = 4f // дополнительная высота при нажатии
В Jetpack Compose тени управляются через Modifier.shadow() и elevation в компонентах Card и Surface. Modifier.shadow() принимает elevation и shape. В отличие от View System, Compose отрисовывает тени в собственном рендер-пайплайне, что даёт более предсказуемое поведение на всех версиях Android.
// Jetpack Compose: тень через 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 с кастомной тенью")
}
Правильное использование теней улучшает восприятие интерфейса, неправильное — создаёт визуальный шум и ухудшает производительность. Material Design определяет пять уровней elevation: 0 dp (без тени), 1–4 dp (кнопки, чипсы), 6–12 dp (карточки, меню), 16–24 dp (диалоги, боттом-шиты), 24+ dp (модальные окна, FAB).
| Уровень | Elevation | Элементы | Характеристика тени |
|---|---|---|---|
| 0 | 0 dp | Текст, иконки, фон | Без тени, плоский слой |
| 1 | 1–4 dp | Кнопки, поля ввода | Лёгкая тень, небольшое смещение |
| 2 | 6–12 dp | Карточки, Snackbar | Умеренная тень, заметное размытие |
| 3 | 16–24 dp | Диалоги, меню | Глубокая тень, большое размытие |
| 4 | 24+ dp | Модальные окна | Максимальная тень, элемент парит |
Правила хорошего тона: (1) не используйте тени для элементов, которые не должны привлекать внимание (фоны, разделители), (2) высота тени должна соответствовать важности элемента — чем важнее, тем выше, (3) при нажатии на кнопку уменьшайте elevation анимированно для тактильной обратной связи, (4) избегайте теней на тёмных фонах — используйте overlay (осветление/затемнение) вместо тени. В Material You (Android 12+) тени адаптируются под тему: на тёмном фоне elevation заменяется цветовым слоем (surface tint).
Во Flutter тени реализуются через BoxShadow внутри BoxDecoration. BoxShadow принимает color, offset, blurRadius и spreadRadius. Flutter поддерживает множественные тени: передача списка BoxShadow позволяет создавать сложные эффекты — например, внешнюю тень + внутреннюю подсветку. PhysicalModel — альтернатива, которая симулирует физическую тень на основе формы (BeveledRectangleBorder, CircleBorder).
// Flutter: тень через 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('Контейнер с тенью'),
)
// PhysicalModel для физической тени
PhysicalModel(
color: Colors.white,
elevation: 6.0,
shadowColor: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(12.0),
child: Text('Физическая модель с тенью'),
)
Производительность: BoxShadow с множественными тенями может вызывать перерисовку при каждом изменении (repaint). Для статичных элементов используйте PhysicalModel — он кэширует тень в отдельный слой (RepaintBoundary). Во Flutter 3.16+ добавлена поддержка Material 3 elevation с адаптивными тенями, которые меняют цвет и размытие в зависимости от темы (light/dark).
Часто задаваемые вопросы
Elevation — это числовая высота элемента в z-координате, а shadow (тень) — визуальный эффект, создаваемый этой высотой. В Android elevation — свойство View, которое автоматически генерирует тень. В дизайне elevation и shadow часто используются как взаимозаменяемые термины, но технически elevation — причина, shadow — следствие.
Проверьте: (1) у View задано elevation больше 0, (2) задан outlineProvider (если View не из Material библиотеки), (3) включено аппаратное ускорение (android:hardwareAccelerated="true" в манифесте). CardView автоматически управляет outlineProvider. Для кастомных View вызовите view.outlineProvider = ViewOutlineProvider.BACKGROUND.
CALayer не поддерживает внутренние тени напрямую. Используйте комбинацию: CAGradientLayer с чёрным цветом и прозрачностью внутри маски (mask), либо наложите UIImageView с растровой внутренней тенью. В SwiftUI внутренняя тень реализуется через overlay с LinearGradient и blendMode(.multiply).
В Android используйте translationZ для анимации: в состоянии покоя elevation = 2 dp, при нажатии translationZ = 4 dp (суммарная высота 6 dp). На iOS анимируйте shadowOffset и shadowRadius одновременно с трансформацией кнопки. В SwiftUI используйте withAnimation с изменением elevation через Modifier.shadow(). Во Flutter — AnimatedContainer с изменением BoxShadow.
Material Design рекомендует не более трёх уровней elevation на одном экране. Если элементов с тенью больше — объединяйте их в группы с одинаковой высотой. Избыточное количество теней создаёт визуальный шум и снижает производительность рендеринга на устройствах среднего и бюджетного сегмента.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также