本教程是 Envato Tuts +上的“ 使用PHP构建启动”系列 的一部分。 在本系列文章中,我 将以 我的 Meeting Planner 应用程序作为真实示例 ,指导您完成从概念到现实的启动 。 在此过程的每一步中,我都会将Meeting Planner代码作为开放源代码示例发布,您可以从中学习。 当出现问题时,我还将解决与启动相关的业务问题。
移动应用程序与响应式网络
从策略上讲,在iOS和Android上为Meeting Planner构建移动应用程序是有意义的,但是从财务上讲,我尚未为此目的筹集资源。 马修·英格拉姆( Mathew Ingram)最近在《财富》杂志上撰文指出,由于为移动用户提供了大量产品,“至少从统计上来说,没有人会下载您的应用程序。” 因此,尽管可以肯定我可以通过一个应用程序来增强Meeting Planner的体验,但是采用我的当前资源对采用它的可能性没有直接的意义。
但是,使Meeting Planner成为移动设备上的出色Web体验非常重要。
在今天的一集中,我将回顾和讨论针对此所做的更改-本质上是使我们的Web应用程序更多地是一个响应Swift的网站,可在移动设备和平板电脑上轻松使用。 在手机或平板电脑上查看结果!
今天的一集编码的挑战之一是我不是设计师或CSS编码器。 有时候,我觉得我什至不应该自己编码。 在Microsoft,我是组程序经理 ,即我们有图形设计师,人员配备齐全的可用性实验室,CSS不存在,等等。
在进行这项工作之前,我感到很胆怯,试图学习媒体查询,断点和专用CSS-这不是我擅长的主题,它既费时又非常注重细节。 然而,在48小时内,一切都Swift而优美地融合在一起。 如果您浏览故事的底部,您将看到所有更改最终只需要几行CSS。 突然,当我开始在手机上浏览Meeting Planner时,我对新的自适应Web体验的运行效果感到非常兴奋。
坦白说,这让我感到目前不需要专用的移动应用程序。 现在,我们可以通过移动网络体验来吸引更多的观众,尤其是在即将到来的关键Alpha和Beta阶段。
同时,如果您还没有尝试使用Meeting Planner,请继续并通过手机或平板电脑安排您的第一次会议 。 我确实参加了下面的评论主题,所以请告诉我您的经历! 您也可以通过Twitter @reifman与我联系 。 我一直对新功能请求和建议的教程主题感兴趣。
提醒一下,Meeting Planner的所有代码都是在PHP的Yii2框架中编写的。 如果您想了解有关Yii2的更多信息,请查看我们的平行系列“ 使用Yii2编程” 。
当前的移动状态
首先,我使用iOS手机浏览了会议计划程序服务的当前状态,并拍摄了初始应用程序的屏幕截图。 这并不可怕,但是也不是很好。 让我们回顾一下我发现的东西。
主页
主页看起来不错,尽管从美学上我希望引导文本“使计划变得容易”会有所不同,即在三个长度相等的行上。 但是,Bootstrap可以很好地管理下拉菜单,并且该页面的其余部分可以正常运行:
注册页面
同样,除了标题的美观布局和左页边距一致性之外,注册页面基本上可以正常运行:
计划会议
该人员开始计划会议后,当前的索引页面需要改进。 列过多。 主题被压扁了。 也许我最初选择在此处显示的信息不是必需的。 而且,当然,命令选项不在视图中。 该页面需要针对移动设备进行更显着的调整。
其他页面运行良好,例如针对主题的新会议请求。 但是,可能不希望向移动用户提供textarea字段来输入较长的介绍会议的消息:
使用我们正在使用的bootstrap扩展,添加参与者也变得有些不正常:
地点和时间的规划视图开始崩溃。 同样,桌面设计为移动设备提供了太多的细节和太多的选择:
其他地区
“位置”页面可以正常工作,但需要改进按钮的布局。 也许移动用户不需要此功能。
同样,桌面选项卡和照片布局在移动设备上也会崩溃。 还需要重新考虑:
开发解决方案
当然,网站上有很多地方可以改进。 对于移动设备,有些区域需要重新考虑,某些区域需要最小化,而其他方面则需要进行美学调整。 让我们开始工作。
不同的方法
开始这项任务时,我对媒体查询和断点几乎没有零经验。 几天前,我因潜入我担心的陌生泥潭而拖延了时间。 我从练习媒体查询开始,以挑逗我的编辑器 :
@media only life
and (max-energy-level: 60%)
and (-caffeine-ratio: 2) {
.editorBossperson {
available-to:false;
visible-to:false;
}
}
开玩笑帮助打破了我的脑海。 Envato的编辑之神总是向我敞开怀抱 。
我开始考虑许多领域:
- 简化功能,尤其是在会议计划过程中
- 识别要显示给移动设备的关键信息
- 隐藏移动设备上的某些功能,例如元素,列和菜单选项
- 使用媒体查询和断点
- 专注于Alpha版本最重要的领域
我一直在网络上遇到的一个有用的概念是“ Mobile First设计”。 不幸的是,我是一所老学校,还没有做到这一点。 但是重新思考每个主题为“ Mobile First”的页面都是有帮助的。
例如,必须要有四个表列的会议索引,并且在纵向电话上会迷失方向。
我一直在问自己,如何设计所有页面才能通过电话工作。
预热媒体查询
下拉菜单
我花了一些力气克服了对深入CSS的犹豫。 为了进行热身,我开始致力于最小化下拉菜单并简化移动功能的范围。
现在,我决定为较小的设备创建一个基本媒体查询,并在整个站点中使用该查询。 这是frontend / 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属性,例如menuHide
。
这是添加到/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的默认布局包括一个面包屑小部件,该小部件可通过作曲家加载且难以自定义。 我尝试添加CSS以隐藏第一个元素和第一个“ /”分隔符:
花了一些时间,但让我更深入地研究了CSS,例如nth-child内容,并建立了信心:
/* 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;
}
这是该表格在移动设备上的外观-请注意Submit和Cancel之间的新填充:
自适应文本包装
实际上,使首页标题为“ 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:
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 -->
这些会议视图更改的最好之处在于,它们将简化UX设计挑战,以便将来与许多参与者进行会议。 无论开会的人数多少,看法基本上都与上面相同。 本质上,这解决了我扩展到多个参与者会议的最大障碍-UX设计。
下一步是什么?
我希望您在我从事响应式Web设计的细节时一直喜欢它。 当网站的代码和视觉变化融合在一起时,我对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;
}
}
我未来的设计工作将开始,“在手机上应该是什么样?”
如前所述,我目前正在竭尽全力地准备会议计划程序以发布Alpha版。 我主要关注的是将使Alpha版本顺利进行的主要改进和功能。
我现在正在跟踪Asana中的所有内容,这将在另一个教程中进行介绍。 它非常有用。 还有一些有趣的新功能还在路上。
我还将开始更多地关注与会议计划程序一起进行的即将进行的投资收集工作。 我刚刚开始根据SEC新的众筹规则的实施对WeFunder进行试验。 请考虑关注我们的个人资料 。 我还将在以后的教程中写更多有关此的内容。
同样,在等待更多剧集时, 安排第一次会议(通过电话!) 。 另外,如果您在下面的评论中分享您的经验,我也将不胜感激,并且我始终对您的建议感兴趣。 您也可以直接通过Twitter @reifman与我联系 。 您也可以将它们发布在Meeting Planner支持站点上 。
在“ 用PHP构建您的启动”系列中观看即将发布的教程。
相关链接
翻译自: https://code.tutsplus.com/tutorials/building-your-startup-improving-the-mobile-web--cms-26705