تطبيقات الويب التقدمية
التصميم المتجاوب لتطبيقات PWA
مقدمة إلى التصميم المتجاوب لتطبيقات PWA
يجب أن توفر تطبيقات الويب التقدمية تجربة ممتازة على جميع الأجهزة. يضمن التصميم المتجاوب أن يبدو تطبيق PWA الخاص بك ويعمل بشكل رائع على الهواتف والأجهزة اللوحية وأجهزة سطح المكتب وكل شيء بينهما.
فلسفة التصميم للهاتف أولاً
التصميم للهاتف أولاً يبدأ بالتصميم لأصغر شاشة والتحسين التدريجي للشاشات الأكبر:
لماذا الهاتف أولاً؟
- يفرض التركيز على المحتوى والميزات الأساسية
- أداء أفضل على الأجهزة المحمولة
- أسهل في التوسيع من التقليص
- معظم المستخدمين يصلون إلى PWAs على الأجهزة المحمولة أولاً
/* نهج CSS للهاتف أولاً */
/* أنماط أساسية للهاتف (لا حاجة لـ media query) */
.container {
width: 100%;
padding: 1rem;
}
.grid {
display: flex;
flex-direction: column;
gap: 1rem;
}
/* أنماط الجهاز اللوحي (768px فما فوق) */
@media (min-width: 768px) {
.container {
max-width: 720px;
margin: 0 auto;
}
.grid {
flex-direction: row;
flex-wrap: wrap;
}
.grid-item {
flex: 0 0 calc(50% - 0.5rem);
}
}
/* أنماط سطح المكتب (1024px فما فوق) */
@media (min-width: 1024px) {
.container {
max-width: 960px;
}
.grid-item {
flex: 0 0 calc(33.333% - 0.667rem);
}
}
/* أنماط سطح المكتب الكبير (1280px فما فوق) */
@media (min-width: 1280px) {
.container {
max-width: 1200px;
}
}
وسم Viewport Meta
وسم viewport meta ضروري للتصميم المتجاوب. يتحكم في كيفية عرض PWA على الأجهزة المحمولة:
<!-- إعدادات viewport الموصى بها لتطبيقات PWA -->
<meta name="viewport"
content="width=device-width,
initial-scale=1,
maximum-scale=5,
user-scalable=yes">
دعنا نحلل كل خاصية:
- width=device-width: يعين عرض viewport إلى عرض الجهاز
- initial-scale=1: يعين مستوى التكبير الأولي إلى 100%
- maximum-scale=5: يسمح للمستخدمين بالتكبير حتى 500% (إمكانية الوصول)
- user-scalable=yes: يسمح بالقرص للتكبير (إمكانية الوصول)
تحذير: لا تعين أبداً
user-scalable=no أو maximum-scale=1 لأن هذا يمنع المستخدمين ذوي الإعاقات البصرية من التكبير. هذا انتهاك لإمكانية الوصول.
الصور المتجاوبة
يجب أن تتكيف الصور مع أحجام ودقة الشاشة المختلفة:
1. استخدام srcset لدقة مختلفة
<!-- تقديم أحجام صور مختلفة بناءً على كثافة الشاشة -->
<img src="image-400.jpg"
srcset="image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 900px) 50vw,
33vw"
alt="صورة متجاوبة"
loading="lazy">
2. استخدام عنصر picture للتوجيه الفني
<!-- صور مختلفة لأحجام شاشة مختلفة -->
<picture>
<source media="(max-width: 600px)"
srcset="hero-mobile.jpg">
<source media="(max-width: 1200px)"
srcset="hero-tablet.jpg">
<img src="hero-desktop.jpg"
alt="صورة رئيسية"
loading="lazy">
</picture>
3. صور خلفية CSS
/* صور خلفية متجاوبة */
.hero {
background-image: url('hero-mobile.jpg');
background-size: cover;
background-position: center;
}
@media (min-width: 768px) {
.hero {
background-image: url('hero-tablet.jpg');
}
}
@media (min-width: 1200px) {
.hero {
background-image: url('hero-desktop.jpg');
}
}
/* للشاشات عالية الدقة */
@media (min-width: 1200px) and (-webkit-min-device-pixel-ratio: 2),
(min-width: 1200px) and (min-resolution: 192dpi) {
.hero {
background-image: url('hero-desktop@2x.jpg');
}
}
الطباعة المتجاوبة
يجب أن يكون النص قابلاً للقراءة على جميع أحجام الشاشات دون تكبير:
/* حجم الخط الأساسي (الهاتف) */
html {
font-size: 16px; /* لا تقل أبداً عن 16px لنص الجسم */
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, Oxygen, Ubuntu, sans-serif;
line-height: 1.6;
}
/* طباعة مرنة باستخدام clamp() */
h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
line-height: 1.2;
}
h2 {
font-size: clamp(1.5rem, 4vw, 2.5rem);
line-height: 1.3;
}
p {
font-size: clamp(1rem, 2vw, 1.125rem);
max-width: 70ch; /* عرض قراءة مثالي */
}
/* مسافات متجاوبة */
.section {
padding: clamp(2rem, 5vw, 4rem) 1rem;
}
تخطيطات مرنة باستخدام CSS Grid و Flexbox
تخطيط Grid المتجاوب
/* Grid متجاوب تلقائياً */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
padding: 1rem;
}
/* Grid متجاوب مع مناطق مسماة */
.app-layout {
display: grid;
grid-template-areas:
"header"
"nav"
"main"
"sidebar"
"footer";
gap: 1rem;
}
@media (min-width: 768px) {
.app-layout {
grid-template-areas:
"header header"
"nav nav"
"main sidebar"
"footer footer";
grid-template-columns: 2fr 1fr;
}
}
@media (min-width: 1024px) {
.app-layout {
grid-template-areas:
"header header header"
"nav main sidebar"
"footer footer footer";
grid-template-columns: 200px 2fr 1fr;
}
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.sidebar { grid-area: sidebar; }
.footer { grid-area: footer; }
تخطيط Flexbox المتجاوب
/* تخطيط بطاقات مرن */
.card-container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
padding: 1rem;
}
.card {
flex: 1 1 100%; /* عرض كامل على الهاتف */
min-width: 0; /* السماح لعناصر flex بالانكماش أقل من حجم المحتوى */
}
@media (min-width: 600px) {
.card {
flex: 1 1 calc(50% - 0.5rem); /* عمودان على الجهاز اللوحي */
}
}
@media (min-width: 900px) {
.card {
flex: 1 1 calc(33.333% - 0.667rem); /* ثلاثة أعمدة على سطح المكتب */
}
}
أهداف اللمس والتفاعلات المحمولة
يجب أن تكون أهداف اللمس كبيرة بما يكفي للنقر المريح:
/* الحد الأدنى لحجم هدف اللمس: 44x44px (iOS) أو 48x48px (Android) */
.button,
.link,
.touch-target {
min-width: 48px;
min-height: 48px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.5rem;
}
/* مسافة كافية بين أهداف اللمس */
.nav-list {
display: flex;
gap: 0.5rem; /* على الأقل 8px بين الأهداف */
}
/* إزالة تأثيرات التمرير على أجهزة اللمس */
@media (hover: none) {
.button:hover {
/* إزالة أو تعديل أنماط التمرير */
background-color: inherit;
}
}
/* تمكين تأثيرات التمرير فقط على الأجهزة التي تدعمها */
@media (hover: hover) {
.button:hover {
background-color: #007bff;
transform: translateY(-2px);
}
}
/* تفاعلات خاصة باللمس */
.swipeable {
touch-action: pan-y; /* السماح بالتمرير العمودي فقط */
-webkit-overflow-scrolling: touch; /* تمرير سلس على iOS */
}
أنماط متجاوبة خاصة بـ PWA
1. التنقل السفلي (نمط الهاتف المحمول)
/* التنقل السفلي للهاتف المحمول */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-around;
background: white;
border-top: 1px solid #ddd;
padding: 0.5rem;
z-index: 1000;
}
.bottom-nav-item {
display: flex;
flex-direction: column;
align-items: center;
min-width: 48px;
padding: 0.5rem;
text-decoration: none;
color: #666;
}
/* التبديل إلى الشريط الجانبي على الشاشات الأكبر */
@media (min-width: 768px) {
.bottom-nav {
position: static;
flex-direction: column;
width: 200px;
border-top: none;
border-right: 1px solid #ddd;
}
}
2. رأس متجاوب مع قائمة الهامبرجر
<!-- بنية HTML -->
<header class="app-header">
<div class="header-container">
<button class="menu-toggle" aria-label="تبديل القائمة">
<span class="hamburger"></span>
</button>
<h1 class="logo">تطبيق PWA الخاص بي</h1>
<nav class="main-nav">
<ul class="nav-list">
<li><a href="#home">الرئيسية</a></li>
<li><a href="#about">حول</a></li>
<li><a href="#contact">اتصل</a></li>
</ul>
</nav>
</div>
</header>
/* قائمة الهاتف المحمول (مخفية افتراضياً) */
.menu-toggle {
display: block;
background: none;
border: none;
min-width: 44px;
min-height: 44px;
}
.main-nav {
position: fixed;
top: 60px;
left: -100%;
width: 80%;
max-width: 300px;
height: calc(100vh - 60px);
background: white;
transition: left 0.3s ease;
box-shadow: 2px 0 10px rgba(0,0,0,0.1);
}
.main-nav.active {
left: 0;
}
.nav-list {
list-style: none;
padding: 1rem;
}
.nav-list a {
display: block;
padding: 1rem;
min-height: 48px;
}
/* قائمة سطح المكتب (مرئية دائماً) */
@media (min-width: 768px) {
.menu-toggle {
display: none;
}
.main-nav {
position: static;
width: auto;
height: auto;
background: transparent;
box-shadow: none;
}
.nav-list {
display: flex;
gap: 1rem;
}
}
3. بطاقات متجاوبة مع CSS Grid
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
gap: 1.5rem;
padding: 1rem;
}
.card {
display: flex;
flex-direction: column;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.card-image {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
}
.card-content {
padding: 1rem;
flex: 1;
}
إدراجات المنطقة الآمنة (الأجهزة ذات النتوءات)
التعامل مع النتوءات والمناطق الآمنة على الأجهزة المحمولة الحديثة:
/* إضافة إدراجات المنطقة الآمنة إلى viewport meta */
<meta name="viewport"
content="width=device-width,
initial-scale=1,
viewport-fit=cover">
/* استخدام متغيرات بيئة CSS للمناطق الآمنة */
.app-header {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 1rem;
padding-top: max(1rem, env(safe-area-inset-top));
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
.app-footer {
padding-bottom: max(1rem, env(safe-area-inset-bottom));
}
/* أقسام كاملة النزيف */
.full-bleed {
width: 100vw;
margin-left: calc(-1 * env(safe-area-inset-left));
margin-right: calc(-1 * env(safe-area-inset-right));
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
تمرين:
- أنشئ تخطيط PWA متجاوب مع:
- CSS للهاتف أولاً يبدأ من 320px
- وسم viewport meta مناسب
- تنقل متجاوب (هامبرجر على الهاتف، أفقي على سطح المكتب)
- شبكة بطاقات متجاوبة (عمود واحد هاتف، 2 جهاز لوحي، 3 سطح مكتب)
- أزرار ملائمة للمس (دقيقة 48x48px)
- نفذ صوراً متجاوبة باستخدام srcset وعناصر picture
- أضف طباعة مرنة باستخدام clamp()
- اختبر على أجهزة وأحجام شاشة متعددة
- تأكد من أن جميع العناصر التفاعلية تلبي متطلبات حجم هدف اللمس
نصيحة: استخدم محاكاة الأجهزة في DevTools للمتصفح لاختبار تصميمك المتجاوب. Chrome DevTools لديه وضع متجاوب يتيح لك اختبار أحجام الأجهزة المختلفة وحتى خنق الشبكة والمعالج لمحاكاة ظروف الهاتف المحمول الحقيقية.