Shadow: الجوهر، إنشاء الظلال في تطبيقات الجوال

المؤلف: IT Sectr نُشر: 2026-02-28 وقت القراءة: 9 دق

Shadow (ظل) — تأثير بصري في واجهات الجوال يخلق وهم العمق والتسلسل الهرمي بين العناصر. تُظهر الظلال أي عنصر يقع أعلى في المستوى z وبالتالي هو أكثر أهمية أو تفاعلية. وفقًا لـ Material Design Guidelines (Google، 2026)، تستخدم الظلال النظامية خمسة ارتفاعات رئيسية (elevation): 0 dp (مسطح)، 1–4 dp (أزرار)، 6–12 dp (بطاقات)، 16–24 dp (حوارات)، 24+ dp (نوافذ مشروطة). اقرأ المزيد عن ارتفاع العناصر في مقالة عن Elevation.

أهم النقاط

  • الظل (shadow) — تأثير بصري يخلق العمق عن طريق تعتيم المنطقة تحت العنصر مع تمويه الحواف.
  • على iOS، تُضبط الظلال عبر خصائص CALayer: shadowColor، shadowOffset، shadowRadius، shadowOpacity.
  • في Android، تُدار الظلال من خلال elevation (Material Design) أو الرسم المخصص عبر OutlineProvider.
  • يدعم Jetpack Compose الظلال عبر Modifier.shadow() و elevation في Card/Surface.
  • في Flutter، تُنفّذ الظلال عبر BoxShadow في BoxDecoration أو من خلال PhysicalModel.

ما هو الظل في واجهة المستخدم؟

الظل (shadow) في واجهات المستخدم هو تأثير بصري يحاكي الإضاءة والعمق. يُنشأ الظل عن طريق رسم نسخة داكنة غير واضحة من العنصر، منزاحة عن الأصل. في تصميم الجوال، تؤدي الظلال ثلاث وظائف: تُظهر التسلسل الهرمي (كلما كان العنصر أعلى، الظل أطول)، تُشير إلى التفاعلية (الأزرار ذات الظل تبدو قابلة للضغط)، تفصل المحتوى عن الخلفية (البطاقات ذات الظل تُقرأ ككتل منفصلة).

في Material Design من Google، ترتبط الظلال ارتباطًا وثيقًا بمفهوم elevation. يحتل كل عنصر ارتفاعًا معينًا في الإحداثي z، والظل هو إسقاط للإضاءة العلوية. لا تفرض Human Interface Guidelines من Apple نظامًا صارمًا للارتفاعات، لكنها توصي باستخدام الظلال لإنشاء تسلسل هرمي بصري وعمق في الواجهات.

وفقًا لدراسة Nielsen Norman Group (2024)، تعمل الظلال الموضوعة بشكل صحيح على تقليل الوقت اللازم للعثور على عنصر تفاعلي بنسبة 24%. تساعد الظلال أيضًا المستخدمين ذوي الإعاقات البصرية على تمييز حدود العناصر. ومع ذلك، فإن الاستخدام المفرط للظلال (3+ مستويات على الشاشة) يزيد العبء المعرفي ويضعف الإدراك.

الظلال على iOS: CALayer وSwiftUI

على iOS، تُنفّذ الظلال عبر خصائص CALayer: shadowColor يحدد لون الظل، shadowOffset — الإزاحة في CGSize (x، y)، shadowRadius — نصف قطر التمويه، shadowOpacity — الشفافية من 0 إلى 1. لتحسين الأداء، يُوصى أيضًا بتعيين shadowPath — مسار UIBezierPath يصف شكل الظل، حتى لا تحسبه Core Animation تلقائيًا.

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

"> التحسين: shadowPath صريح
cardView.layer.shadowPath = UIBezierPath(
    roundedRect: cardView.bounds,
    cornerRadius: 12
).cgPath

في SwiftUI، تُضبط الظلال عبر المُعدِّل .shadow() مع المعلمات color، radius، x، y. يطبق SwiftUI shadowPath تلقائيًا ويدير أداء العرض. للظلال المتقدمة (الظلال الداخلية، ظلال متعددة)، استخدم overlay() مع LinearGradient.

swift
// 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، تُدار عملية التنقيط عبر .drawingGroup().

الظلال في Android: elevation والظلال المخصصة

في Android، تُنفّذ الظلال في Material Design عبر elevation — خاصية View تحدد ارتفاع العنصر في الإحداثي z. يعرض النظام الظل تلقائيًا بناءً على elevation و outlineProvider (محيط العنصر). كلما زاد الارتفاع، كان الظل أكبر وأكثر ضبابية. للعرض (View) التي لا ترث من Material Design (مثل AppCompat)، تعمل الظلال فقط مع تسريع الأجهزة ممكّنًا.

xml
<!-- 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، استخدم OutlineProvider. يسمح ViewOutlineProvider بتعيين شكل عشوائي عبر outline.setRoundRect() أو outline.setPath(). بدون OutlineProvider، يُعرض الظل بناءً على الشكل المستطيل للعرض، دون مراعاة تدوير الزوايا.

kotlin
// 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  // نصف قطر الزاوية
        )
    }
}
myView.elevation = 8f  // ارتفاع الظل بالبكسل
myView.translationZ = 4f  // ارتفاع إضافي عند الضغط

في Jetpack Compose، تُدار الظلال عبر Modifier.shadow() و elevation في مكوني Card و Surface. يقبل Modifier.shadow() elevation و shape. على عكس نظام العرض، يعرض Compose الظلال في خط أنابيب العرض الخاص به، مما يوفر سلوكًا أكثر قابلية للتنبؤ عبر جميع إصدارات Android.

kotlin
// 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العناصرخاصية الظل
00 dpنص، أيقونات، خلفيةبدون ظل، طبقة مسطحة
11–4 dpأزرار، حقول إدخالظل خفيف، إزاحة صغيرة
26–12 dpبطاقات، Snackbarظل معتدل، تمويه ملحوظ
316–24 dpحوارات، قوائمظل عميق، تمويه كبير
424+ dpنوافذ مشروطةظل أقصى، العنصر يطفو

أفضل الممارسات: (1) لا تستخدم الظلال للعناصر التي لا ينبغي أن تجذب الانتباه (خلفيات، فواصل)، (2) يجب أن يتوافق ارتفاع الظل مع أهمية العنصر — كلما كان أكثر أهمية، كان أعلى، (3) عند الضغط على الزر، قلل elevation مع حركة للتغذية الراجعة اللمسية، (4) تجنب الظلال على الخلفيات الداكنة — استخدم overlay (تفتيح/تعتيم) بدلاً من الظل. في Material You (Android 12+)، تتكيف الظلال مع السمة: على الخلفيات الداكنة، يُستبدل elevation بطبقة لونية (surface tint).

الظلال في Flutter: BoxShadow وPhysicalModel

في Flutter، تُنفّذ الظلال عبر BoxShadow داخل BoxDecoration. يقبل BoxShadow color، offset، blurRadius و spreadRadius. يدعم Flutter ظلالًا متعددة: تمرير قائمة BoxShadow يسمح بإنشاء تأثيرات معقدة — على سبيل المثال، ظل خارجي + إضاءة داخلية. PhysicalModel هو بديل يحاكي ظلًا فيزيائيًا بناءً على الشكل (BeveledRectangleBorder، CircleBorder).

dart
// 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 مع ظلال متعددة قد يسبب إعادة طلاء عند كل تغيير. للعناصر الثابتة، استخدم PhysicalModel — يخزن الظل مؤقتًا في طبقة منفصلة (RepaintBoundary). في Flutter 3.16+، يُدعم elevation من Material 3 مع ظلال تكيفية، والتي تغير اللون والتمويه حسب السمة (فاتح/داكن).

الأسئلة الشائعة

بماذا يختلف elevation عن shadow؟

Elevation هو الارتفاع الرقمي لعنصر في الإحداثي z، بينما shadow (الظل) هو التأثير البصري الناتج عن هذا الارتفاع. في Android، elevation هي خاصية View تولد ظلًا تلقائيًا. في التصميم، غالبًا ما يُستخدم elevation و shadow بالتبادل، لكن تقنيًا elevation هو السبب و shadow هو النتيجة.

لماذا لا يظهر الظل على Android؟

تحقق من: (1) أن View بها elevation أكبر من 0، (2) تم تعيين outlineProvider (إذا كانت View ليست من مكتبة Material)، (3) تسريع الأجهزة مفعل (android:hardwareAccelerated="true" في البيان). يدير CardView outlineProvider تلقائيًا. للعرض المخصصة، استدعِ view.outlineProvider = ViewOutlineProvider.BACKGROUND.

كيفية إنشاء ظل داخلي (inner shadow) على iOS؟

لا يدعم CALayer الظلال الداخلية مباشرة. استخدم مزيجًا: CAGradientLayer بلون أسود وشفافية داخل قناع، أو ضع 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 على شاشة واحدة. إذا كان هناك المزيد من العناصر ذات الظلال، فجمّعها بنفس الارتفاع. العدد المفرط من الظلال يخلق ضوضاء بصرية ويقلل أداء العرض على الأجهزة متوسطة ومنخفضة المدى.

الملخص

  • الظل (shadow) هو تأثير بصري للعمق يعتمد على elevation العنصر في الإحداثي z.
  • على iOS، تُضبط الظلال عبر CALayer: shadowColor، shadowOffset، shadowRadius، shadowOpacity.
  • في Android، تُدار الظلال عبر elevation و OutlineProvider للشكل المخصص.
  • يحدد Material Design خمسة مستويات من elevation: 0، 1–4، 6–12، 16–24، 24+ dp.
  • Jetpack Compose يستخدم Modifier.shadow() و elevation في Card/Surface لإدارة الظلال.
  • Flutter ينفذ الظلال عبر BoxShadow (BoxDecoration) و PhysicalModel (ظل فيزيائي).
  • التحسين: حدد shadowPath (iOS)، outlineProvider (Android)، استخدم PhysicalModel (Flutter).

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا