本教程是 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中文网其他相关文章!