قسمت جلویی سرزمین میانه

گامی برای توسعه چند دستگاه

در اولین مقاله خود در مورد توسعه Chrome Experiment A Journey Through-earth روی توسعه WebGL برای دستگاه های تلفن همراه تمرکز کردیم. در این مقاله چالش‌ها، مشکلات و راه‌حل‌هایی را که هنگام ایجاد بقیه قسمت‌های جلویی HTML5 با آن‌ها مواجه شده‌ایم، مورد بحث قرار می‌دهیم.

سه نسخه از یک سایت

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

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

می‌توانیم صفحه فرود را به عنوان مثالی از نحوه تطبیق طرح برای اندازه‌های مختلف در نظر بگیریم.

عقاب ها ما را در صفحه فرود انداختند.
عقاب ها ما را در صفحه فرود انداختند.

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

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

از آنجایی که طرح‌ها در این مورد مبتنی بر شبکه‌ها یا قوانین نیستند و بین بخش‌های مختلف کاملاً منحصربه‌فرد هستند، واقعاً به عنصر و سناریوی خاصی بستگی دارد که از چه نقاط شکست یا سبک‌هایی استفاده شود. بیش از یک بار اتفاق افتاد که ما طرح‌بندی عالی را با sass-mixins و media-queries خوب تنظیم کرده بودیم، و سپس باید یک افکت بر اساس موقعیت ماوس یا اشیاء پویا اضافه می‌کردیم و در نهایت همه چیز را در جاوا اسکریپت بازنویسی می‌کردیم.

ما همچنین یک کلاس با حالت فعلی در تگ head اضافه می کنیم تا بتوانیم از آن اطلاعات در استایل های خود استفاده کنیم، مانند این مثال (در SCSS):

.loc-hobbit-logo {

  // Default values here.

  .desktop & {
     // Applies only in desktop mode.
  }

 .tablet &, .mobile & {
   
   // Different asset for mobile and tablets perhaps.

   @media screen and (max-height: 760px), (max-width: 760px) {
     // Breakpoint-specific styles.
   }

   @media screen and (max-height: 570px), (max-width: 400px) {
     // Breakpoint-specific styles.
   }
 }
}

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

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

ما اغلب از ابزار شبیه ساز در DevTools در حین توسعه استفاده می کردیم، به خصوص در Chrome Canary که دارای ویژگی های جدید بهبود یافته و تعداد زیادی از پیش تنظیم ها است. این یک راه خوب برای تأیید سریع طراحی است. ما هنوز نیاز داشتیم که به طور مرتب روی دستگاه های واقعی آزمایش کنیم. یکی از دلایل این بود که سایت در حال تطبیق با تمام صفحه است. صفحاتی که اسکرول عمودی دارند، در اکثر موارد، هنگام پیمایش، رابط کاربری مرورگر را پنهان می‌کنند (Safari در iOS7 در حال حاضر با این مشکل مواجه است) اما ما مجبور بودیم همه چیز را مستقل از آن جا دهیم. ما همچنین از یک پیش تنظیم در شبیه ساز استفاده کردیم و تنظیم اندازه صفحه را برای شبیه سازی از دست دادن فضای موجود تغییر دادیم. آزمایش بر روی دستگاه های واقعی نیز برای نظارت بر مصرف حافظه و عملکرد مهم است

رسیدگی به دولت

پس از صفحه فرود، به نقشه سرزمین میانه فرود می آییم. آیا متوجه تغییر URL شدید؟ این سایت یک برنامه کاربردی تک صفحه ای است که از History API برای مدیریت مسیریابی استفاده می کند.

هر بخش از سایت یک شی خاص خود را به ارث می برد که دارای عملکردهایی مانند عناصر DOM، انتقال، بارگیری دارایی ها، دفع و غیره است. وقتی بخش های مختلف سایت را کاوش می کنید، بخش ها شروع می شوند، عناصر به آن اضافه و از آن حذف می شوند. DOM و دارایی‌های بخش فعلی بارگیری می‌شوند.

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

نشان دادن مکان ها

برای نشان دادن تنظیمات زیبا و شخصیت‌های Middle-earth، ما یک سیستم مدولار از اجزای تصویر و متن ساختیم که می‌توانید آن را به صورت افقی بکشید یا بکشید. ما اسکرول بار را در اینجا فعال نکرده‌ایم زیرا می‌خواهیم سرعت‌های متفاوتی در محدوده‌های مختلف داشته باشیم، مانند توالی‌های تصویر که در آن حرکت را به پهلو متوقف می‌کنید تا زمانی که کلیپ پخش شود.

سالن تراندویل
جدول زمانی تالار Thranduil

جدول زمانی

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

ماژول ها و اجزای رفتار

ماژول های مختلفی که ما از آنها پشتیبانی می کنیم عبارتند از: توالی تصویر، تصویر ثابت، صحنه اختلاف منظر، صحنه تغییر فوکوس و متن.

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

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

محتوای موجود در ماژول متن با کشیدن افزونه TweenMax قابل کشیدن است. همچنین می‌توانید از چرخ پیمایش یا کشیدن انگشت با دو انگشت برای پیمایش عمودی استفاده کنید. به پلاگین throw-props توجه کنید که هنگام کشیدن انگشت و رها کردن، فیزیک به سبک fling را اضافه می کند.

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

با این کار ما می‌توانیم مکان‌های مختلف را فقط با یک فایل پیکربندی ایجاد کنیم که مشخص می‌کند چه دارایی‌هایی برای بارگیری و تنظیم انواع مختلف ماژول‌ها و مؤلفه‌ها وجود دارد.

توالی تصویر

چالش برانگیزترین ماژول ها از نظر عملکرد و اندازه دانلود، توالی تصویر است. یک سری مطالب برای خواندن در مورد این موضوع وجود دارد. در موبایل و تبلت، این تصویر ثابت را جایگزین می کنیم. اگر بخواهیم کیفیت مناسبی در موبایل داشته باشیم، برای رمزگشایی و ذخیره داده در حافظه بسیار زیاد است. ما چندین راه حل جایگزین را امتحان کردیم. ابتدا از یک تصویر پس‌زمینه و یک صفحه اسپریت استفاده کرد، اما زمانی که GPU نیاز به جابجایی بین صفحات اسپریت داشت، منجر به مشکلات حافظه و تاخیر شد. سپس ما سعی کردیم عناصر img را عوض کنیم، اما خیلی کند بود. رسم یک قاب از یک صفحه اسپریت به یک بوم کارآمدترین کار بود، بنابراین ما شروع به بهینه سازی آن کردیم. برای صرفه جویی در زمان محاسباتی هر فریم، داده های تصویر برای نوشتن در بوم از قبل از طریق یک بوم موقت پردازش شده و با putImageData() در یک آرایه ذخیره می شود، رمزگشایی شده و آماده استفاده است. سپس می‌توان شیت اصلی را جمع‌آوری کرد و ما فقط حداقل مقدار داده مورد نیاز را در حافظه ذخیره می‌کنیم. شاید در واقع ذخیره تصاویر رمزگشایی نشده کمتر باشد، اما در حین پاک کردن دنباله از این طریق، عملکرد بهتری دریافت می کنیم. قاب ها بسیار کوچک هستند، فقط 640x400، اما آنها فقط در حین تمیز کردن قابل مشاهده هستند. وقتی توقف می کنید، یک تصویر با وضوح بالا بارگیری می شود و به سرعت محو می شود.

var canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;

var ctx = canvas.getContext('2d');
ctx.drawImage(sheet, 0, 0);

var tilesX = imageWidth / tileWidth;
var tilesY = imageHeight / tileHeight;

var canvasPaste = canvas.cloneNode(false);
canvasPaste.width = tileWidth;
canvasPaste.height = tileHeight;

var i, j, canvasPasteTemp, imgData, 
var currentIndex = 0;
var startIndex = index * 16;
for (i = 0; i < tilesY; i++) {
  for (j = 0; j < tilesX; j++) {
    // Store the image data of each tile in the array.
    canvasPasteTemp = canvasPaste.cloneNode(false);
    imgData = ctx.getImageData(j * tileWidth, i * tileHeight, tileWidth, tileHeight);
    canvasPasteTemp.getContext('2d').putImageData(imgData, 0, 0);

    list[ startIndex + currentIndex ] = imgData;

    currentIndex++;
  }
}

صفحات sprite با Imagemagick تولید می شوند. در اینجا یک مثال ساده در GitHub آورده شده است که نشان می دهد چگونه یک spritesheet از تمام تصاویر داخل یک پوشه ایجاد کنید.

متحرک سازی ماژول ها

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

هر ماژول دارای یک لایه مشکی ظریف در بالای آن است که تیرگی آن را تنظیم می کند تا زمانی که در موقعیت مرکزی قرار دارد کاملاً شفاف باشد. این به شما کمک می کند تا در یک زمان بر روی یک ماژول تمرکز کنید، که تجربه را افزایش می دهد.

عملکرد صفحه

حرکت از یک نمونه اولیه کارآمد به یک نسخه بدون جاک به معنای رفتن از حدس زدن به دانستن آنچه در مرورگر اتفاق می افتد است. اینجاست که Chrome DevTools بهترین دوست شماست.

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

من دوست دارم از TweenMax از Greensock برای توئین کردن ویژگی ها، تبدیل ها و CSS استفاده کنم. در ظروف فکر کنید، ساختار خود را با اضافه کردن لایه‌های جدید تجسم کنید. به خاطر داشته باشید که تبدیل های موجود را می توان با تبدیل های جدید بازنویسی کرد. اگر فقط مقادیر دوبعدی را بیندازید، translateZ(0) که شتاب سخت‌افزاری را در کلاس CSS شما اجباری کرد، با یک ماتریس دو بعدی جایگزین می‌شود. برای نگه داشتن لایه در حالت شتاب در این موارد، از ویژگی "force3D:true" در tween استفاده کنید تا به جای ماتریس دو بعدی، یک ماتریس سه بعدی بسازید. وقتی CSS و جاوا اسکریپت توئین ها را برای تنظیم سبک ها ترکیب می کنید، به راحتی فراموش می شود.

شتاب سخت‌افزاری را در جاهایی که به آن نیاز نیست مجبور نکنید. هنگامی که می خواهید بسیاری از کانتینرها را به سخت افزار شتاب دهید، حافظه GPU می تواند به سرعت پر شود و نتایج ناخواسته ای ایجاد کند، به خصوص در iOS که حافظه محدودیت های بیشتری دارد. بارگیری دارایی های کوچکتر و بزرگ کردن آنها با css و غیرفعال کردن برخی از جلوه ها در حالت تلفن همراه، پیشرفت های زیادی را ایجاد کرد.

نشت حافظه زمینه دیگری بود که ما برای بهبود مهارت های خود در آن نیاز داشتیم. هنگام پیمایش بین تجارب مختلف WebGL، اشیاء، مواد، بافت ها و هندسه زیادی ایجاد می شود. اگر هنگام حرکت و حذف بخش، برای جمع‌آوری زباله آماده نباشند، احتمالاً باعث می‌شوند دستگاه پس از مدتی از کار بیفتد و حافظه آن تمام شود.

خروج از یک بخش با عملکرد دفع ناموفق.
خروج از یک بخش با عملکرد دفع ناموفق.
خیلی بهتر!
خیلی بهتر!

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

این صحنه در EffectComposer ارجاع داده شد.
این صحنه در EffectComposer ارجاع داده شد.

به طور کلی، خوب است قبل از دستکاری DOM دو بار فکر کنید. وقتی این کار را می کنید، به کارایی فکر کنید. اگر می توانید به آن کمک کنید، DOM را در یک حلقه بازی دستکاری نکنید. منابع را در متغیرها برای استفاده مجدد ذخیره کنید. اگر نیاز به جستجوی یک عنصر دارید، با ذخیره ارجاعات به کانتینرهای استراتژیک و جستجو در نزدیکترین عنصر جد، از کوتاهترین مسیر استفاده کنید.

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

تمام صفحه

در صورت در دسترس بودن، می‌توانید از طریق API تمام صفحه، سایت را در حالت تمام صفحه در منو قرار دهید. اما در دستگاه ها نیز تصمیم مرورگرها برای قرار دادن آن در تمام صفحه وجود دارد. Safari در iOS قبلاً یک هک داشت که به شما امکان می داد آن را کنترل کنید، اما دیگر در دسترس نیست، بنابراین هنگام ساخت یک صفحه بدون پیمایش، باید طراحی خود را برای کار بدون آن آماده کنید. احتمالاً می‌توانیم در به‌روزرسانی‌های آینده منتظر به‌روزرسانی در این مورد باشیم، زیرا بسیاری از برنامه‌های وب را شکسته است.

دارایی ها

دستورالعمل های متحرک برای آزمایش ها.
دستورالعمل های متحرک برای آزمایش ها.

در سرتاسر سایت ما انواع مختلفی از دارایی ها داریم، از تصاویر (PNG و JPEG)، SVG (درخط و پس زمینه)، صفحات spriteshe (PNG)، فونت های آیکون سفارشی و انیمیشن های Adobe Edge استفاده می کنیم. ما از PNG برای دارایی ها و انیمیشن ها (spritesheets) استفاده می کنیم که در آن عنصر نمی تواند مبتنی بر برداری باشد، در غیر این صورت سعی می کنیم تا حد امکان از SVG استفاده کنیم.

فرمت برداری به معنای عدم افت کیفیت است، حتی اگر آن را مقیاس بندی کنیم. 1 فایل برای همه دستگاه ها

  • اندازه فایل کوچک.
  • ما می توانیم هر قسمت را به طور جداگانه متحرک کنیم (برای انیمیشن های پیشرفته عالی است). به عنوان مثال، "زیرنویس" لوگوی هابیت (تخریب اسماگ) را هنگامی که کوچک می شود پنهان می کنیم.
  • می توان آن را به عنوان یک تگ HTML SVG جاسازی کرد یا به عنوان تصویر پس زمینه بدون بارگذاری اضافی استفاده کرد (همزمان با صفحه html بارگذاری می شود).

تایپ‌فیس‌های آیکون از نظر مقیاس‌پذیری دارای مزایایی مشابه SVG هستند و به جای SVG برای عناصر کوچکی مانند آیکون‌هایی که فقط باید بتوانیم روی آن‌ها رنگ را تغییر دهیم (هور، فعال و غیره) استفاده می‌شود. استفاده مجدد از آیکون ها نیز بسیار آسان است، فقط باید ویژگی CSS "content" یک عنصر را تنظیم کنید.

انیمیشن ها

در برخی موارد، متحرک سازی عناصر SVG با کد می تواند بسیار وقت گیر باشد، به خصوص زمانی که انیمیشن نیاز به تغییر زیادی در طول فرآیند طراحی داشته باشد. برای بهبود گردش کار بین طراحان و توسعه دهندگان، از Adobe Edge برای برخی از انیمیشن ها (دستورالعمل های قبل از بازی) استفاده می کنیم. گردش کار انیمیشن واقعاً به Flash نزدیک است و این به تیم کمک کرد، اما چند اشکال وجود دارد، به خصوص در مورد ادغام انیمیشن های Edge در فرآیند بارگذاری دارایی ما، زیرا با لودرهای خود و منطق پیاده سازی همراه است.

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

نتیجه گیری

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