یک رویکرد غیر پاسخگو برای ساخت برنامه های وب بین دستگاهی

بوریس اسموس
Boris Smus

کوئری‌های رسانه‌ای عالی هستند، اما…

مدیا کوئری‌ها فوق‌العاده هستند، موهبتی الهی برای توسعه‌دهندگان وب‌سایت که می‌خواهند تغییرات کوچکی در استایل‌شیت‌های خود ایجاد کنند تا تجربه بهتری را برای کاربران در دستگاه‌هایی با اندازه‌های مختلف فراهم کنند. مدیا کوئری‌ها اساساً به شما امکان می‌دهند CSS سایت خود را بسته به اندازه صفحه نمایش سفارشی کنید. قبل از اینکه به این مقاله بپردازید، در مورد طراحی واکنش‌گرا بیشتر بدانید و چند نمونه خوب از استفاده از مدیا کوئری‌ها را در اینجا ببینید: mediaqueri.es .

همانطور که برد فراست در مقاله قبلی خود اشاره کرده است، تغییر ظاهر تنها یکی از موارد بسیاری است که هنگام ساخت وب سایت برای موبایل باید در نظر بگیرید. اگر تنها کاری که هنگام ساخت وب سایت موبایل خود انجام می‌دهید، سفارشی سازی طرح بندی خود با کوئری‌های رسانه‌ای است، پس ما با وضعیت زیر روبرو هستیم:

  • همه دستگاه‌ها جاوا اسکریپت، CSS و فایل‌های (تصاویر، ویدیوها) یکسانی را دریافت می‌کنند که منجر به زمان بارگذاری طولانی‌تر از حد لازم می‌شود.
  • همه دستگاه‌ها DOM اولیه یکسانی دریافت می‌کنند، که به طور بالقوه توسعه‌دهندگان را مجبور به نوشتن CSS بیش از حد پیچیده می‌کند.
  • انعطاف‌پذیری کمی برای تعیین تعاملات سفارشی متناسب با هر دستگاه وجود دارد.

برنامه‌های وب به چیزی بیش از پرس‌وجوهای رسانه‌ای نیاز دارند

اشتباه برداشت نکنید. من از طراحی واکنش‌گرا از طریق مدیا کوئری‌ها متنفر نیستم و قطعاً فکر می‌کنم جایگاهی در جهان دارد. علاوه بر این، برخی از مشکلات ذکر شده در بالا را می‌توان با رویکردهایی مانند تصاویر واکنش‌گرا ، بارگذاری پویای اسکریپت و غیره حل کرد. با این حال، در یک نقطه خاص، ممکن است متوجه شوید که در حال انجام اصلاحات تدریجی زیادی هستید و شاید بهتر باشد از نسخه‌های مختلف استفاده کنید.

با افزایش پیچیدگی رابط‌های کاربری که می‌سازید و گرایش شما به سمت برنامه‌های وب تک‌صفحه‌ای، باید برای سفارشی‌سازی رابط‌های کاربری برای هر نوع دستگاه، تلاش بیشتری کنید. این مقاله به شما آموزش می‌دهد که چگونه این سفارشی‌سازی‌ها را با حداقل تلاش انجام دهید. رویکرد کلی شامل طبقه‌بندی دستگاه بازدیدکننده شما در کلاس دستگاه مناسب و ارائه نسخه مناسب به آن دستگاه، ضمن به حداکثر رساندن استفاده مجدد از کد بین نسخه‌ها است.

چه کلاس‌های دستگاهی را هدف قرار می‌دهید؟

تعداد زیادی دستگاه متصل به اینترنت وجود دارد و تقریباً همه آنها مرورگر دارند. پیچیدگی در تنوع آنهاست: لپ‌تاپ‌های مک، ایستگاه‌های کاری ویندوز، آیفون‌ها، آیپدها، تلفن‌های اندرویدی با ورودی لمسی، چرخ‌های اسکرول، صفحه کلید، ورودی صوتی، دستگاه‌های دارای حساسیت به فشار، ساعت‌های هوشمند، توسترها و یخچال‌ها و بسیاری دیگر. برخی از این دستگاه‌ها همه جا هستند، در حالی که برخی دیگر بسیار نادر هستند.

انواع دستگاه‌ها.
انواع دستگاه‌ها ( منبع ).

برای ایجاد یک تجربه کاربری خوب، باید بدانید کاربران شما چه کسانی هستند و از چه دستگاه‌هایی استفاده می‌کنند. اگر یک رابط کاربری برای یک کاربر دسکتاپ با ماوس و کیبورد بسازید و آن را به یک کاربر گوشی هوشمند بدهید، رابط کاربری شما ناامیدکننده خواهد بود زیرا برای اندازه صفحه نمایش دیگری و روش ورودی دیگری طراحی شده است.

دو سرِ افراطی در طیف رویکردها وجود دارد:

  1. یک نسخه بسازید که روی همه دستگاه‌ها کار کند. در نتیجه، تجربه کاربری (UX) آسیب خواهد دید، زیرا دستگاه‌های مختلف ملاحظات طراحی متفاوتی دارند.

  2. برای هر دستگاهی که می‌خواهید از آن پشتیبانی کنید، یک نسخه بسازید. این کار مدت زیادی طول خواهد کشید، زیرا نسخه‌های زیادی از برنامه خود خواهید ساخت. همچنین، وقتی گوشی هوشمند جدید بعدی از راه برسد (که تقریباً هر هفته اتفاق می‌افتد)، مجبور خواهید بود نسخه دیگری ایجاد کنید.

اینجا یک بده بستان اساسی وجود دارد: هرچه دسته‌بندی‌های دستگاه بیشتری داشته باشید، می‌توانید تجربه کاربری بهتری ارائه دهید، اما طراحی، پیاده‌سازی و نگهداری آن به کار بیشتری نیاز دارد.

ایجاد یک نسخه جداگانه برای هر کلاس دستگاهی که انتخاب می‌کنید، ممکن است به دلایل عملکردی یا اگر نسخه‌هایی که می‌خواهید برای کلاس‌های مختلف دستگاه ارائه دهید بسیار متفاوت باشند، ایده خوبی باشد. در غیر این صورت، طراحی وب واکنش‌گرا یک رویکرد کاملاً منطقی است.

یک راه حل بالقوه

در اینجا یک راه حل وجود دارد: دستگاه‌ها را در دسته‌های مختلف طبقه‌بندی کنید و بهترین تجربه ممکن را برای هر دسته طراحی کنید. اینکه چه دسته‌هایی را انتخاب می‌کنید به محصول و کاربر هدف شما بستگی دارد. در اینجا یک طبقه‌بندی نمونه وجود دارد که به خوبی دستگاه‌های محبوب وب‌محور امروزی را در بر می‌گیرد.

  1. صفحه نمایش‌های کوچک + لمسی (عمدتاً تلفن‌ها)
  2. صفحه نمایش‌های بزرگ + لمسی (عمدتاً تبلت‌ها)
  3. صفحه نمایش‌های بزرگ + صفحه کلید/ماوس (عمدتاً کامپیوترهای رومیزی/لپ‌تاپ)

این تنها یکی از بسیاری از تجزیه و تحلیل‌های ممکن است، اما در زمان نوشتن این مطلب بسیار منطقی به نظر می‌رسد. دستگاه‌های تلفن همراه بدون صفحه لمسی (مانند تلفن‌های همراه معمولی، برخی از کتابخوان‌های الکترونیکی اختصاصی) در لیست بالا وجود ندارند. با این حال، اکثر این دستگاه‌ها دارای ناوبری صفحه کلید یا نرم‌افزار صفحه‌خوان هستند که اگر سایت خود را با در نظر گرفتن دسترسی‌پذیری بسازید، به خوبی کار خواهند کرد.

نمونه‌هایی از برنامه‌های وب مختص فرم فاکتور

نمونه‌های زیادی از ویژگی‌های وب وجود دارد که نسخه‌های کاملاً متفاوتی را برای عوامل شکل مختلف ارائه می‌دهند. جستجوی گوگل و همچنین فیس‌بوک این کار را انجام می‌دهند. ملاحظات مربوط به این شامل عملکرد (دریافت دارایی‌ها، رندر صفحات) و تجربه کاربری عمومی‌تر می‌شود.

در دنیای برنامه‌های بومی، بسیاری از توسعه‌دهندگان ترجیح می‌دهند تجربه خود را با کلاس دستگاه تطبیق دهند. به عنوان مثال، Flipboard برای iPad رابط کاربری بسیار متفاوتی در مقایسه با Flipboard در iPhone دارد. نسخه تبلت برای استفاده با دو دست و ورق زدن افقی بهینه شده است در حالی که نسخه تلفن برای تعامل با یک دست و ورق زدن عمودی در نظر گرفته شده است. بسیاری از برنامه‌های iOS دیگر نیز نسخه‌های تلفن و تبلت بسیار متفاوتی ارائه می‌دهند، مانند Things (لیست کارها) و Showyou (ویدیوی اجتماعی)، که در زیر معرفی شده‌اند:

سفارشی‌سازی قابل توجه رابط کاربری برای تلفن و تبلت.
سفارشی‌سازی قابل توجه رابط کاربری برای تلفن و تبلت.

رویکرد شماره ۱: تشخیص سمت سرور

در سرور، ما درک بسیار محدودتری از دستگاهی که با آن سر و کار داریم، داریم. احتمالاً مفیدترین سرنخ موجود، رشته عامل کاربر است که از طریق هدر User-Agent در هر درخواست ارائه می‌شود. به همین دلیل، همان رویکرد شنود UA در اینجا نیز کار خواهد کرد. در واقع، پروژه‌های DeviceAtlas و WURFL این کار را از قبل انجام می‌دهند (و اطلاعات اضافی زیادی در مورد دستگاه ارائه می‌دهند).

متأسفانه هر یک از این موارد چالش‌های خاص خود را دارند. WURFL بسیار بزرگ است و حاوی 20 مگابایت XML است که به طور بالقوه برای هر درخواست، سربار قابل توجهی را در سمت سرور ایجاد می‌کند. پروژه‌هایی وجود دارند که XML را به دلایل عملکردی تقسیم می‌کنند. DeviceAtlas متن‌باز نیست و برای استفاده نیاز به مجوز پولی دارد.

گزینه‌های ساده‌تر و رایگان‌تری هم وجود دارد، مانند پروژه Detect Mobile Browsers . البته ایراد این است که تشخیص دستگاه به ناچار جامعیت کمتری خواهد داشت. همچنین، فقط بین دستگاه‌های تلفن همراه و غیر تلفن همراه تمایز قائل می‌شود و پشتیبانی محدودی از تبلت را فقط از طریق مجموعه‌ای از تنظیمات موردی ارائه می‌دهد.

رویکرد شماره ۲: تشخیص سمت کلاینت

ما می‌توانیم با استفاده از تشخیص ویژگی، اطلاعات زیادی در مورد مرورگر و دستگاه کاربر کسب کنیم. نکات اصلی که باید مشخص کنیم این است که آیا دستگاه قابلیت لمسی دارد و آیا صفحه نمایش آن بزرگ است یا کوچک.

ما باید جایی خط تمایز بین دستگاه‌های لمسی کوچک و بزرگ بکشیم. در مورد قاب‌های لبه‌دار مانند گلکسی نوت ۵ اینچی چطور؟ تصویر زیر تعدادی از دستگاه‌های محبوب اندروید و iOS را روی هم (با وضوح صفحه نمایش مربوطه) نشان می‌دهد. علامت ستاره نشان می‌دهد که دستگاه با تراکم پیکسلی دو برابر عرضه می‌شود یا می‌تواند عرضه شود. اگرچه تراکم پیکسلی ممکن است دو برابر شود، CSS همچنان اندازه‌های یکسانی را گزارش می‌دهد.

یک نکته‌ی کوتاه در مورد پیکسل‌ها در CSS: پیکسل‌های CSS در وب موبایل با پیکسل‌های صفحه نمایش یکسان نیستند . دستگاه‌های iOS retina روش دو برابر کردن تراکم پیکسل را معرفی کردند (مثلاً iPhone 3GS در مقابل 4، iPad 2 در مقابل 3). رابط‌های کاربری Safari موبایل retina هنوز هم برای جلوگیری از اختلال در وب، عرض دستگاه را یکسان گزارش می‌دهند. از آنجایی که سایر دستگاه‌ها (مثلاً Android) نمایشگرهایی با وضوح بالاتر دارند، آنها نیز از همین ترفند عرض دستگاه استفاده می‌کنند.

وضوح دستگاه (برحسب پیکسل).
وضوح دستگاه (برحسب پیکسل).

با این حال، آنچه این تصمیم را پیچیده می‌کند، اهمیت در نظر گرفتن هر دو حالت عمودی و افقی است. ما نمی‌خواهیم هر بار که دستگاه را تغییر جهت می‌دهیم، صفحه را دوباره بارگذاری کنیم یا اسکریپت‌های اضافی را بارگیری کنیم، اگرچه ممکن است بخواهیم صفحه را به طور متفاوتی رندر کنیم.

در نمودار زیر، مربع‌ها نشان‌دهنده حداکثر ابعاد هر دستگاه هستند که در نتیجه همپوشانی خطوط عمودی و افقی (و تکمیل مربع) حاصل شده است:

وضوح تصویر عمودی + افقی (به پیکسل)
وضوح تصویر عمودی + افقی (به پیکسل)

با تنظیم آستانه روی 650px ، آیفون و گلکسی نکسوس را به عنوان «smalltouch» و آیپد و گلکسی تب را به عنوان «تبلت» طبقه‌بندی می‌کنیم. گلکسی نوت دوجنسیتی در این مورد به عنوان «تلفن» طبقه‌بندی می‌شود و طرح‌بندی تلفن را دریافت خواهد کرد.

و بنابراین، یک استراتژی معقول می‌تواند چیزی شبیه به این باشد:

if (hasTouch) {
  if (isSmall) {
    device = PHONE;
  } else {
    device = TABLET;
  }
} else {
  device = DESKTOP;
}

یک نمونه حداقلی از رویکرد تشخیص ویژگی را در عمل ببینید.

رویکرد جایگزین در اینجا استفاده از شنود UA برای تشخیص نوع دستگاه است. اساساً شما مجموعه‌ای از روش‌های اکتشافی را ایجاد می‌کنید و آنها را با navigator.userAgent کاربر خود مطابقت می‌دهید. شبه کد چیزی شبیه به این است:

var ua = navigator.userAgent;
for (var re in RULES) {
  if (ua.match(re)) {
    device = RULES[re];
    return;
  }
}

نمونه‌ای از رویکرد تشخیص UA را در عمل ببینید.

نکته‌ای در مورد بارگذاری سمت کلاینت

اگر تشخیص UA را روی سرور خود انجام می‌دهید، می‌توانید تصمیم بگیرید که هنگام دریافت درخواست جدید، چه CSS، JavaScript و DOM را ارائه دهید. با این حال، اگر تشخیص سمت کلاینت را انجام می‌دهید، وضعیت پیچیده‌تر است. چندین گزینه دارید:

  1. به یک URL مخصوص نوع دستگاه که شامل نسخه مربوط به این نوع دستگاه است، هدایت می‌شود.
  2. فایل‌های مربوط به نوع دستگاه را به صورت پویا بارگذاری کنید.

رویکرد اول ساده است و نیاز به یک ریدایرکت مانند window.location.href = '/tablet' دارد. با این حال، اکنون اطلاعات نوع دستگاه به مکان اضافه می‌شود، بنابراین ممکن است بخواهید از History API برای پاکسازی URL خود استفاده کنید. متأسفانه این رویکرد شامل یک ریدایرکت است که می‌تواند کند باشد، به خصوص در دستگاه‌های تلفن همراه.

رویکرد دوم کمی پیچیده‌تر برای پیاده‌سازی است. شما به مکانیزمی برای بارگذاری پویای CSS و JS نیاز دارید، و (بسته به مرورگر)، ممکن است نتوانید کارهایی مانند سفارشی‌سازی <meta viewport> را انجام دهید. همچنین، از آنجایی که هیچ ریدایرکتی وجود ندارد، شما با HTML اصلی که ارائه شده است، گیر می‌کنید. البته، می‌توانید آن را با جاوا اسکریپت دستکاری کنید، اما بسته به برنامه شما، این ممکن است کند و/یا غیر زیبا باشد.

تصمیم گیری در مورد کلاینت یا سرور

اینها بده بستان‌های بین رویکردها هستند:

مشتری حرفه‌ای :

  • از آنجایی که بر اساس اندازه/قابلیت‌های صفحه نمایش به جای UA، شواهد بیشتری برای آینده وجود دارد.
  • نیازی به به‌روزرسانی مداوم فهرست UA نیست.

سرور حرفه ای :

  • کنترل کامل بر اینکه چه نسخه‌ای برای چه دستگاه‌هایی ارائه شود.
  • عملکرد بهتر: نیازی به تغییر مسیر کلاینت یا بارگذاری پویا نیست.

ترجیح شخصی من این است که با device.js و تشخیص سمت کلاینت شروع کنم. با تکامل برنامه شما، اگر متوجه شدید که تغییر مسیر سمت کلاینت یک نقص عملکرد قابل توجه است، می‌توانید به راحتی اسکریپت device.js را حذف کرده و تشخیص UA را روی سرور پیاده‌سازی کنید.

معرفی device.js

Device.js نقطه شروعی برای انجام تشخیص دستگاه مبتنی بر پرس‌وجوی رسانه‌ای و معنایی بدون نیاز به پیکربندی خاص سمت سرور است و در زمان و تلاش مورد نیاز برای تجزیه رشته توسط عامل کاربر صرفه‌جویی می‌کند.

ایده این است که شما نشانه‌گذاری ( link rel=alternate ) مورد پسند موتور جستجو را در بالای <head> خود ارائه دهید که نشان می‌دهد کدام نسخه‌های سایت خود را می‌خواهید ارائه دهید.

<link rel="alternate" href="http://foo.com" id="desktop"
    media="only screen and (touch-enabled: 0)">

در مرحله بعد، می‌توانید تشخیص UA سمت سرور را انجام دهید و تغییر مسیر نسخه را خودتان مدیریت کنید، یا از اسکریپت device.js برای انجام تغییر مسیر سمت کلاینت مبتنی بر ویژگی استفاده کنید.

برای اطلاعات بیشتر، به صفحه پروژه device.js و همچنین یک برنامه جعلی که از device.js برای تغییر مسیر سمت کلاینت استفاده می‌کند، مراجعه کنید.

توصیه: MVC با نماهای مختص به فرم فاکتور

احتمالاً الان دارید فکر می‌کنید که دارم به شما می‌گویم سه اپلیکیشن کاملاً مجزا بسازید، یکی برای هر نوع دستگاه. نه! اشتراک‌گذاری کد کلید ماجرا است.

امیدوارم شما از یک چارچوب شبیه MVC مانند Backbone، Ember و غیره استفاده کرده باشید. اگر این کار را کرده‌اید، با اصل جداسازی دغدغه‌ها آشنا هستید، به طور خاص اینکه رابط کاربری (لایه نمایش) شما باید از منطق شما (لایه مدل) جدا باشد. اگر این موضوع برای شما تازگی دارد، با برخی از این منابع در مورد MVC و MVC در جاوا اسکریپت شروع کنید.

داستان چند دستگاهی بودن به خوبی با چارچوب MVC موجود شما سازگار است. می‌توانید به راحتی نماهای خود را به فایل‌های جداگانه منتقل کنید و برای هر نوع دستگاه، یک نمای سفارشی ایجاد کنید. سپس می‌توانید کد یکسانی را به همه دستگاه‌ها، به جز لایه نما، ارائه دهید.

MVC چند دستگاهی.
MVC چند دستگاهی.

پروژه شما ممکن است ساختار زیر را داشته باشد (البته، شما می‌توانید بسته به کاربردتان، ساختاری را انتخاب کنید که منطقی‌تر باشد):

models/ (مدل‌های اشتراکی) item.js item-collection.js

controllers/ (کنترلرهای مشترک) item-controller.js

نسخه‌ها/ (موارد مربوط به دستگاه) تبلت/ دسکتاپ/ تلفن/ (کد مربوط به تلفن) style.css index.html views/ item.js item-list.js

این نوع ساختار به شما امکان می‌دهد تا به طور کامل کنترل کنید که هر نسخه چه فایل‌هایی را بارگذاری می‌کند، زیرا برای هر دستگاه HTML، CSS و جاوا اسکریپت سفارشی دارید. این بسیار قدرتمند است و می‌تواند به ساده‌ترین و کارآمدترین روش توسعه برای وب چند دستگاهی، بدون تکیه بر ترفندهایی مانند تصاویر تطبیقی، منجر شود.

وقتی ابزار ساخت مورد علاقه‌تان را اجرا کردید، تمام فایل‌های جاوا اسکریپت و CSS خود را برای بارگذاری سریع‌تر، به فایل‌های تکی الحاق و فشرده‌سازی می‌کنید و HTML تولیدی شما چیزی شبیه به کد زیر خواهد بود (برای گوشی، با استفاده از device.js):

<!doctype html>
<head>
  <title>Mobile Web Rocks! (Phone Edition)</title>

  <!-- Every version of your webapp should include a list of all
        versions. -->
  <link rel="alternate" href="http://foo.com" id="desktop"
      media="only screen and (touch-enabled: 0)">
  <link rel="alternate" href="http://m.foo.com" id="phone"
      media="only screen and (max-device-width: 650px)">
  <link rel="alternate" href="http://tablet.foo.com" id="tablet"
      media="only screen and (min-device-width: 650px)">

  <!-- Viewport is very important, since it affects results of media
        query matching. -->
  <meta name="viewport" content="width=device-width">

  <!-- Include device.js in each version for redirection. -->
  <script src="device.js"></script>

  <link rel="style" href="phone.min.css">
</head>
<body>
  <script src="phone.min.js"></script>
</body>

توجه داشته باشید که کوئری رسانه‌ای (touch-enabled: 0) غیر استاندارد است (فقط در فایرفاکس با پیشوند moz vendor پیاده‌سازی شده است)، اما (به لطف Modernizr.touch ) توسط device.js به درستی مدیریت می‌شود.

لغو نسخه

تشخیص دستگاه گاهی اوقات می‌تواند اشتباه انجام شود و در برخی موارد، کاربر ممکن است ترجیح دهد طرح‌بندی تبلت را در تلفن خود بررسی کند (شاید از گلکسی نوت استفاده می‌کند)، بنابراین مهم است که به کاربران خود حق انتخاب بدهید که از کدام نسخه سایت شما استفاده کنند، اگر می‌خواهند به صورت دستی آن را لغو کنند.

رویکرد معمول این است که از نسخه موبایل خود، لینکی به نسخه دسکتاپ ارائه دهید. پیاده‌سازی این کار به اندازه کافی آسان است، اما device.js از این قابلیت با پارامتر GET device پشتیبانی می‌کند.

نتیجه‌گیری

به طور خلاصه، هنگام ساخت رابط‌های کاربری تک صفحه‌ای چند دستگاهی که به طور کامل با دنیای طراحی واکنش‌گرا سازگار نیستند، این کارها را انجام دهید:

  1. مجموعه‌ای از کلاس‌های دستگاه را برای پشتیبانی انتخاب کنید و معیارهایی را برای طبقه‌بندی دستگاه‌ها به کلاس‌ها تعیین کنید.
  2. برنامه MVC خود را با جداسازی قوی دغدغه‌ها بسازید و نماها را از بقیه کدبیس جدا کنید.
  3. از device.js برای تشخیص کلاس دستگاه سمت کلاینت استفاده کنید.
  4. وقتی آماده شدید، اسکریپت و استایل‌شیت‌های خود را در یکی از کلاس‌های هر دستگاه بسته‌بندی کنید.
  5. اگر عملکرد تغییر مسیر سمت کلاینت مشکل دارد، device.js را رها کنید و به تشخیص UA سمت سرور بروید.