本教學是 Envato Tuts 上的「使用 PHP 建立您的新創公司」系列的一部分。在本系列中,我將使用我的會議規劃器應用程式作為現實生活中的範例,指導您從概念到現實啟動新創公司。在此過程中的每一步,我都會將 Meeting Planner 程式碼作為開源範例發布,您可以從中學習。我也會解決出現的與新創企業相關的業務問題。
從策略上講,在 iOS 和 Android 上為 Meeting Planner 建立行動應用程式是有意義的,但從財務角度來看,我尚未為此籌集資源。馬修·英格拉姆(Mathew Ingram) 最近在《財富》雜誌上撰文稱,由於面向行動用戶的產品過多,「至少從統計數據來看,沒有人會下載您的應用程式。」因此,雖然我當然可以透過應用程式增強Meeting Planner 體驗,但就我目前的資源而言,採用它的可能性並沒有立即意義。
但是,讓 Meeting Planner 在行動裝置上提供出色的網路體驗非常重要。
在今天的節目中,我將回顧並討論為此做出的更改 - 本質上使我們的 Web 應用程式更像是一個響應式網站,可以在行動裝置和平板電腦上輕鬆使用。查看結果(在您的手機或平板電腦上)!
今天這一集的程式設計挑戰之一是我不是設計師或 CSS 編碼員。有時我覺得我甚至不應該自己編碼;在 Microsoft,我是團隊專案經理,也就是說,我們有圖形設計師、人員配備齊全的可用性實驗室、CSS 不存在等等。
在開始這項工作之前,我對學習媒體查詢、斷點和專門的 CSS 感到害怕——這不是我擅長的主題,而且非常耗時且非常注重細節。然而,48 小時之內,一切都快速而完美地完成了。如果你瀏覽到故事的底部,你會發現所有更改最終只需要很少的 CSS 行。突然,當我開始在手機上瀏覽 Meeting Planner 時,我對新的響應式網路體驗的運作效果感到非常興奮。
坦白說,這讓我覺得目前沒有必要專門的行動應用程式。目前,我們可以透過行動網路體驗來吸引受眾,尤其是在即將到來的關鍵 alpha 和 beta 階段。
同時,如果您尚未試用會議規劃器,請繼續透過手機或平板電腦安排您的第一次會議。我確實參與了下面的評論主題,所以請告訴我您的經驗!您也可以透過 Twitter @reifman 聯繫我。我總是對新功能請求和建議的教程主題感興趣。
提醒一下,Meeting Planner 的所有程式碼都是用 PHP 的 Yii2 框架寫的。如果您想了解有關 Yii2 的更多信息,請查看我們的並行系列“使用 Yii2 進行編程”。
首先,我使用 iOS 手機瀏覽了 Meeting Planner 服務的當前狀態,並截取了初始應用程式的螢幕截圖。這並不可怕,但也不是很好。讓我們回顧一下我的發現。
主頁看起來不錯,儘管從美學上講,我希望標題文字「使調度變得容易」能夠稍微不同,即在三個大約相等長度的行上。然而,Bootstrap 很好地管理了下拉式選單,頁面的其餘部分也能正常運作:
同樣,除了標題的美觀佈局和左邊距一致性之外,註冊頁面基本上具有功能性:
一旦該人開始規劃會議,目前的索引頁面就需要改進。列太多。主題被壓扁了。也許我首先選擇在這裡顯示的資訊並不重要。當然,命令選項也不在視圖中。頁面需要針對行動裝置進行更大幅度的調整。
其他頁面運作良好,例如某個主題的新會議請求。但是,行動用戶可能不希望提供文字區域欄位來輸入較長的介紹會議的訊息:
使用我們正在使用的引導擴展,新增參與者也會變得有點功能失調:
地點和時間的規劃視圖開始崩潰。同樣,桌面設計為行動裝置提供了太多細節和太多選項:
「地點」頁面可以正常運行,但需要改進按鈕的佈局。也許行動用戶不需要此功能。
同樣,桌面標籤和照片佈局在行動裝置上也會出現問題。還需要重新考慮:
當然,網站還有很多可以改進的地方。有些區域需要針對行動裝置進行重新考慮,有些區域需要最小化,而有些區域則需要進行美觀調整。讓我們開始工作吧。
當我開始這項任務時,我對媒體查詢和斷點的經驗幾乎為零。前幾天,我一直拖延著,擔心自己會陷入一個陌生的泥淖。我從練習媒體查詢開始來取笑我的編輯:
@media only life and (max-energy-level: 60%) and (-caffeine-ratio: 2) { .editorBossperson { available-to:false; visible-to:false; } }
開玩笑有助於打破我腦中的心理堅冰。 Envato 的編輯之神總是可以看到我。
我開始考慮許多領域:
我在網路上不斷遇到的一個有用的概念是「行動優先設計」。不幸的是,我是老派,我沒有這樣做。但重新思考具有以下主題的每個頁面是有幫助的:行動優先。
例如,具有四個表格列的會議索引必須刪除,並且在縱向手機上會讓人迷失方向。
我一直在問自己,如何設計所有頁面以便在手機上使用。
我花了一些努力才克服了深入研究 CSS 的猶豫。為了熱身,我開始致力於最小化下拉式選單並簡化移動功能的範圍。
目前,我決定為較小的裝置建立一個基本媒體查詢,並在整個網站上使用它。這是前端/site.css:
/* ----------- mobile displays ----------- */ @media only screen and (min-device-width: 320px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { /* hides drop down menu items and footer items */ .itemHide,li.menuHide { display:none; visible:false; }
事實證明,進行更改相對簡單。對於我想在行動裝置上隱藏的任何選單項,我只需要新增一個 CSS 屬性,例如選單隱藏
。
這是新增到 /frontend/views/layouts/main.php 的 menuHide
屬性:
$menuItems[] = [ 'label' => 'Account', 'items' => [ [ 'label' => Yii::t('frontend','Places'), 'url' => ['/place/yours'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Friends'), 'url' => ['/friend'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Profile'), 'url' => ['/user-profile'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Contact information'), 'url' => ['/user-contact'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Settings'), 'url' => ['/user-setting'], //'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Reminders'), 'url' => ['/reminder'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Logout').' (' . \common\components\MiscHelpers::getDisplayName(Yii::$app->user->id) . ')', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post'] ], ], ]; echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => $menuItems, ]);
突然之間,下拉式選單變得不再那麼複雜:
漸漸地,我意識到簡化和減少行動網路中的功能將創造最佳體驗。人們總是可以返回桌面來存取其他功能,至少目前是這樣。這也是在 alpha 和 beta 階段收集人們回饋的機會。
Yii 的預設佈局包括一個麵包屑小部件,它是透過 Composer 載入的,並且很難自訂。我嘗試添加 CSS 來隱藏第一個元素和第一個“/”分隔符:
這花了一些時間,但讓我更深入地研究了 CSS,例如第 n 個孩子的內容,並建立了我的信心:
/* removes home and / from breadcrumb */ ul.breadcrumb li:first-child, li.tabHide { display:none; visible:false; } ul.breadcrumb li:nth-child(2)::before { content:''; }
我不知道 CSS 可以修改內容。
結果如下:
接下來,我添加了 CSS 來為行動裝置上的按鈕提供額外的填充,從而減少指尖按下時出錯的可能性。例如,以下是桌面裝置上的提交和取消按鈕:
這是我使用的 CSS,並開始添加到網站周圍的各種按鈕和可點擊圖示:
/* fingertip spacing for buttons */ a.icon-pad { padding: 0 5px 0 2px; } .button-pad { padding-left:7px; }
該表單在行動裝置上的外觀如下 - 請注意提交和取消之間的新填充:
製作主頁標題「Scheduling Made Easy」其實需要更多時間。最終,我在文字中添加了 <br>
標籤,並在不在行動裝置上時預設隱藏它。但我還必須使用 itemHide
類別在 span 標記中新增一個空格。
<h1> <?php echo Yii::t('frontend','Scheduling'); ?> <br class="rwd-break" /> <span class="itemHide"> </span> <?php echo Yii::t('frontend','Made Easy') ?> </h1>
这是 .rwd-break
的 CSS。默认情况下它是隐藏的,并且仅出现在响应式显示中,从而按照我想要的方式破坏标题文本。
.rwd-break { display:none; } /* ----------- mobile displays ----------- */ @media only screen and (min-device-width: 320px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { ... .rwd-break { display:block; } }
如果没有 span 标记空间,文本将在没有正确居中的情况下中断。
随着我越来越认为“移动优先”,我意识到基于手机的用户并不需要我页面上的所有功能。他们不需要所有选项卡,不需要有关会议的数据表,也不需要所有图标按钮选项。事实上,对于会议页面,他们只需要能够打开会议(他们可以从会议视图页面本身取消会议)。
我将主题和参与者列合并为一个垂直列,结果看起来好多了。
在 /frontend/views/meeting/index.php 中,我将 .tabHide
添加到两个四个选项卡中的:
<!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <li class="active"><a href="#planning" role="tab" data-toggle="tab">Planning</a></li> <li ><a href="#upcoming" role="tab" data-toggle="tab">Confirmed</a></li> <li class="tabHide"><a href="#past" role="tab" data-toggle="tab" >Past</a></li> <li class="tabHide"><a href="#canceled" role="tab" data-toggle="tab">Canceled</a></li> </ul>
并且,在 /frontend/views/meeting/_grid.php 中,我重组了该列以合并主题和参与者:
if ($mode =='upcoming' || $mode =='past') { echo GridView::widget([ 'dataProvider' => $dataProvider, //'filterModel' => $searchModel, 'columns' => [ [ 'label'=>'Details', 'attribute' => 'meeting_type', 'format' => 'raw', 'value' => function ($model) { // to do - remove legacy code when subject didn't exist if ($model->subject=='') { return '<div><a href="'.Url::to(['meeting/view', 'id' => $model->id]).'">'.$model->getMeetingHeader().'</a><br /><span class="index-participant">'.$model->getMeetingParticipants($model->id).'</span></div>'; } else { return '<div><a href="'.Url::to(['meeting/view', 'id' => $model->id]).'">'.$model->subject.'</a><br /><span class="index-participant">'.$model->getMeetingParticipants($model->id).'</span></div>'; } }, ],
隐藏 ActionColumn
需要进行一些研究,但看起来像这样:
['class' => 'yii\grid\ActionColumn','header'=>'Options','template'=>'{view} {decline} {cancel}', 'headerOptions' => ['class' => 'itemHide'], 'contentOptions' => ['class' => 'itemHide'], 'buttons'=>[ 'view' => function ($url, $model) { return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, [ 'title' => Yii::t('frontend', 'view'), 'class' => 'icon-pad', ]); }, 'decline' => function ($url, $model) { return ($model->status==$model::STATUS_SENT ) ? Html::a('<span class="glyphicon glyphicon-thumbs-down"></span>', $url, [ 'title' => Yii::t('frontend', 'decline'), 'class' => 'icon-pad', ]) : ''; }, 'cancel' => function ($url, $model) { return ($model->status==$model::STATUS_SENT || $model->status==$model::STATUS_CONFIRMED ) ? Html::a('<span class="glyphicon glyphicon-remove-circle"></span>', $url, [ 'title' => Yii::t('frontend', 'cancel'), 'data-confirm' => Yii::t('frontend', 'Are you sure you want to cancel this meeting?'), 'class' => 'icon-pad', ]) : ''; }, ] ],
最终,这些更改在改进移动设备的过程中简化了桌面界面。
到目前为止,对我来说最具挑战性的任务是针对移动设备调整上面的会议安排页面。手机上的情况一团糟,我很害怕。另外,我一直担心将来如何为多个参与者采用这个界面 - 响应性要求可能只会让这变得更加困难。
我对 Yii 的 Kartik Bootstrap Switch Widget 扩展的使用在修改布局方面有其自身的局限性。将这些元素放置在表格列中效果很好,但使表格列响应式对于媒体查询来说并不那么简单。
当然,正如我在上面的会议列表页面中所示,隐藏列很容易,但修改位置就不那么容易了。
我首先从显示时间和地点选项的水平表格设计转向垂直的纵向风格。而且,显然,表和列有自己的能力,可以在没有媒体查询的情况下使用 HTML5 和 CSS 进行包装。
您可以在此处查看改进后的空白会议计划页面:
每个部分视图都需要额外的 css 列才能使预定义的 Bootstrap 网格布局正常工作,例如左 col-xs4 和右 col-xs-8。这是一个例子:
<div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"> <div class="row"> <div class="col-lg-4 col-md-4 col-xs-4"><h4>What</h4></div> <div class="col-lg-8 col-md-8 col-xs-8"><div style="float:right;"> <?php if ($isOwner) { echo Html::a('', ['update', 'id' => $model->id], ['class' => 'btn btn-primary glyphicon glyphicon-pencil','title'=>'Edit']); } ?> </div> </div> </div> </div>
使地点和时间安排表格具有响应性是最困难的。我进行了实验并最终成功地使用了随着内容窗口(或设备)缩小而自然换行的表列。
我还消除了在其自己的列中显示参与者状态并禁用开关的情况 - 您无法更改它们,那么为什么将它们显示为开关呢?相反,我创建了参与者在地点和时间的状态的文本摘要。以下是 getWhenStatus()
的代码:
public static function getWhenStatus($meeting,$viewer_id) { // get an array of textual status of meeting times for $viewer_id // Acceptable / Rejected / No response: $whenStatus['text'] = []; $whenStatus['style'] = []; foreach ($meeting->meetingTimes as $mt) { // build status for each time $acceptableChoice=[]; $rejectedChoice=[]; $unknownChoice=[]; // to do - add meeting_id to MeetingTimeChoice for sortable queries foreach ($mt->meetingTimeChoices as $mtc) { if ($mtc->user_id == $viewer_id) continue; switch ($mtc->status) { case MeetingTimeChoice::STATUS_UNKNOWN: $unknownChoice[]=$mtc->user_id; break; case MeetingTimeChoice::STATUS_YES: $acceptableChoice[]=$mtc->user_id; break; case MeetingTimeChoice::STATUS_NO: $rejectedChoice[]=$mtc->user_id; break; } } $temp =''; // to do - update for multiple participants // to do - integrate current setting for this user in style setting if (count($acceptableChoice)>0) { $temp.='Acceptable to '.MiscHelpers::getDisplayName($acceptableChoice[0]); $whenStatus['style'][$mt->id]='success'; } else if (count($rejectedChoice)>0) { $temp.='Rejected by '.MiscHelpers::getDisplayName($rejectedChoice[0]); $whenStatus['style'][$mt->id]='danger'; } else if (count($unknownChoice)>0) { $temp.='No response from '.MiscHelpers::getDisplayName($unknownChoice[0]); $whenStatus['style'][$mt->id]='warning'; } $whenStatus['text'][$mt->id]=$temp; } return $whenStatus; }
这是它在桌面上的样子 - 注意文本行和开关的横向布局:
这是移动版本,更加纵向且堆叠,无需媒体查询:
作为示例,以下是我在“时间”面板上对表格列进行编码的 CSS: p>
table.table-list { width:100%; } table.table-list td.table-list-first { float: left; display: inline; width: auto; } table.table-list td.table-switches { width: auto; float: right; display: inline; padding-top: 10px; } .switch-pad { padding-left:7px; } .smallStatus { font-size:90%; color: grey; font-style: italic; }
这是来自 /frontend/views/meeting-time/_list.php 的部分表单的代码:
<?php use yii\helpers\Html; use frontend\models\Meeting; use \kartik\switchinput\SwitchInput; ?> <tr > <!-- panel row --> <td > <table class="table-list"> <!-- list of times --> <tr> <td class="table-list-first"> <!-- time & status --> <?= Meeting::friendlyDateFromTimestamp($model->start,$timezone) ?> <?php if ($whenStatus['text'][$model->id]<>'') { ?> <br /><span class="smallStatus"> <?php echo $whenStatus['text'][$model->id]; ?> </span><br /> <?php } ?> </td> <td class="table-switches"> <!-- col of switches to float right --> <table > <tr> <td > <?php if ($isOwner) { showTimeOwnerStatus($model,$isOwner); } else { showTimeParticipantStatus($model,$isOwner); } ?> </td> <td class="switch-pad"> <?php if ($timeCount>1) { if ($model->status == $model::STATUS_SELECTED) { $value = $model->id; } else { $value = 0; } if ($isOwner || $participant_choose_date_time) { // value has to match for switch to be on echo SwitchInput::widget([ 'type' => SwitchInput::RADIO, 'name' => 'time-chooser', 'items' => [ [ 'value' => $model->id], ], 'value' => $value, 'pluginOptions' => [ 'size' => 'mini','handleWidth'=>60,'onText' => '<i class="glyphicon glyphicon-ok"></i> choose','onColor' => 'success','offText'=>'<i class="glyphicon glyphicon-remove"></i>'], // $whenStatus['style'][$model->id], 'labelOptions' => ['style' => 'font-size: 12px'], ]); } } ?> </td> </tr> </table> </td> <!-- end col with table of switches --> </tr> </table> <!-- end table list of times --> </td> </tr> <!-- end panel row -->
这些会议视图变化的最大好处是,它们将简化未来有许多参与者的会议的用户体验设计挑战。无论参加会议的人数有多少,观点都会与上述基本相同。从本质上讲,这解决了我扩展到多人会议的最大障碍——用户体验设计。
我希望您喜欢跟随我研究响应式网页设计的细节。当网站的代码和视觉变化结合在一起时,我感到非常满意,并且对 CSS 的需要之少印象深刻。综合起来,您可以在这里看到:
.rwd-break { display:none; } table.table-list { width:100%; } table.table-list td.table-list-first { float: left; display: inline; width: auto; } table.table-list td.table-switches { width: auto; float: right; display: inline; padding-top: 10px; } .switch-pad { padding-left:7px; } .smallStatus { font-size:90%; color: grey; font-style: italic; } .setting-label label, #preferences label { font-weight:normal; } /* ----------- mobile displays ----------- */ @media only screen and (min-device-width: 320px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { /* hides drop down menu items and footer items */ .itemHide,li.menuHide { display:none; visible:false; } /* removes home and / from breadcrumb */ ul.breadcrumb li:first-child, li.tabHide { display:none; visible:false; } ul.breadcrumb li:nth-child(2)::before { content:''; } /* fingertip spacing for buttons */ a.icon-pad { padding: 0 5px 0 2px; } .button-pad { padding-left:7px; } .rwd-break { display:block; } }
我未来的设计工作将从“这在移动设备上看起来应该是什么样子?”
如前所述,我目前正在积极准备 Meeting Planner 的 alpha 版本。我主要关注使 alpha 版本顺利发布的关键改进和功能。
我现在正在跟踪 Asana 中的所有内容,我将在另一个教程中对此进行介绍;这非常有帮助。还有一些有趣的新功能仍在开发中。
我也開始更專注於即將透過 Meeting Planner 進行的投資收集工作。我剛開始根據 SEC 新眾籌規則的實施來嘗試 WeFunder。請考慮關注我們的個人資料。我還將在以後的教程中詳細介紹這一點。
再次,當您等待更多劇集時,請安排您的第一次會議(透過您的手機!)。另外,如果您在下面的評論中分享您的經驗,我將不勝感激,並且我始終對您的建議感興趣。您也可以透過 Twitter @reifman 直接與我聯繫。您也可以將它們發佈在會議策劃者支援網站上。
#觀看「使用 PHP 建立您的新創公司」系列中即將推出的教學。
以上是增強新創公司的行動網路體驗的詳細內容。更多資訊請關注PHP中文網其他相關文章!