今天我们将一起完成另外一个设计,Twitter
的新界面。和上一周的设计一样,它来源于dribble.com
。
这个设计是一个非常典型的Web2.0应用模式,从内容上分析,它包括下面这样一些信息:
这种模式在很多的设计中都可以用到,我们在实现的时候,顺便可以关注一下设计师是如何组织这些信息的。
在进入实际的开发之前,我们先来学习一些基本的知识,这些知识会帮助我们更好的实现页面,应用样式。
HTML5是下一代(新一代)HTML的标准。相较于HTML4,HTML5有了很多的修改,引入了一些新的标签,废弃了一些旧的标签,更新了一些标签的寓意等。它更关注HTML文档的语义化,使得HTML不仅仅可以被浏览器识别,更可能被爬虫或者其他应用使用等。
CSS3同样是对CSS2的扩展。它引入了众多的特性,比如自定义字体集,阴影,圆角,动画等等。在引入这些特性之前,Web开发者经常需要自己做一些绕过
工作,比如实现阴影的时候会使用一张背景图片来实现,而圆角则需要为4个角都做一张小图片来拼凑起来。
我们在这一小节主要讨论这样几个新的标签
从标签的名称也可以看到HTML5在文档的语义化方面的改善。这些标签的引入,使得HTML文档更像一个文档。下面我们来分别介绍这6种标签。
nav
标签的语义为:当前文档的导航。nav
作为一个容器,包含了链接到其他文档或者当前文档的其他部分的链接。比如他可以被实现为当前站点的菜单栏的容器:
<nav>
<ul>
<li><a href="/product">Product</a></li>
<li><a href="/contact">Contact</a></li>
<li><a href="/detail">Detail</a></li>
</ul>
</nav>
另外一个可能的场景是,在页脚上,通常会放置一些子站点的链接,这些链接也可以放置在nav
中。比如REA
是澳洲房产搜索的一个平台,它旗下有一系列的站点,比如商业地产,投资等,除了澳洲之外,它在意大利,香港等地也有站点。
header
标签的语义为:当前文档的头信息或者当前文档中section的头信息。比如上周中我们的页面上的Hero Section
中的两个标题:
<header>
<h1>Relax, Finding An Agent Just Got Easier</h1>
<h2>Receive proposals from best agents for free</h2>
</header>
或者在section
中也可以使用:
<section>
<header>
<h1>This is my title</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eligendi officia minima iure sed enim itaque ipsa ea vel aliquam labore neque beatae qui, illo repudiandae, a laudantium voluptates reprehenderit eos?</p>
</header>
</section>
<section>
<header>
<h1>This is another</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Molestiae voluptatem nam aperiam. Voluptatem animi consequatur consectetur error in fuga sit voluptatibus rerum, nisi, officiis dicta vero repudiandae ea, fugit illo.</p>
</header>
</section>
虽然它是header
,但是并不一定在物理上位于文档的头部,它更多的是一个逻辑概念。
aside
的语义为:对于那些与当前文档内容相关,但又不是主要内容的内容,可以放置在aside
中。通常我们会将这种内容放置在侧栏
中,但是应该注意的是,侧栏并不和aside
完全对应。侧栏是一个视觉设计,而aside
是一个逻辑概念。
aside
可以是相对于整个文档的,也可以是相对于某个seciton/article的:
<article>
<h1>Dont design, redisign</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<aside>
<h1>Colour theory</h1>
<dl>
<dt></dt>
<dt></dt>
</dl>
</aside>
</article>
在article
中的aside
,与article
的相关性更高一些(相对于整个文档)。如果aside
不在article
中,那么它又应该是当前页面的次要内容。
<body>
<header>
<h1>Dont design, redisign</h1>
<h2>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</h2>
</header>
<aside>
<h1>Web design</h1>
<dl>
<dt></dt>
<dt></dt>
</dl>
</aside>
</body>
section
可以表示一个文档,或者一组逻辑上相关的内容。但是它并不是一个通用的容器,如果仅仅是为了样式而需要引入一个容器,那么推荐使用div
,而section
更多的是和内容本身相关(而不是展现)。
reveal.js是一个很好的例子,它是一个用HTML编写幻灯片的工具,每张幻灯片都是相对独立的,它被包含在一个section
中:
<section>
<h2>UI for developers</h2>
<pre><code data-item>
***<没钱赚商店>购物清单***
名称:雪碧,数量:2瓶,单价:3.00(元),小计:6.00(元)
名称:可口可乐,数量:4瓶,单价:15.00(元),小计:60.00(元)
----------------------
挥泪赠送商品:
名称:雪碧,数量:1瓶
----------------------
总计:60.00(元)
节省:3.00(元)
**********************
</code></pre>
</section>
article
的语义为:它表示页面上的一块独立内容,本身应该是字包含的(一个足以表意的实体)。并不局限在一篇文章这个狭义的article
上。比如一篇博客,一条评论,一篇文章/新闻,一条微博等。这个独立的内容可以被分发到别处,或者被作为RSS的条目来使用。
我们今天要实现的每一天twist
都可以使一个article
。
<article class="post">
<img src="images/juntao.png" alt="" class="avator">
<header>
<span class="name">Juntao</span>
<span class="account">@juntao</span>
<span class="time">2m</span>
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus veniam quas, deserunt! Provident sit, impedit, facilis molestias minus quas hic ad deserunt quia, alias velit architecto debitis itaque doloremque quaerat.</p>
<footer>
</footer>
</article>
footer
与header
可以对照着看,它也不仅仅是狭义的页脚,还可以被使用在section
或者article
中。在理解这些元素的时候,尽量放在文档/内容的角度来考虑,而不是从视觉上考虑。比如footer
并不一定非要放在页面的最底部。
<footer>
<nav>
<a href="/product">Product</a>
<a href="/contact">Contact</a>
<a href="/detail">Detail</a>
</nav>
<h2>CopyRight@2014</h2>
</footer>
CSS3引入了众多的新特性,使得Web设计变得非常容易。在此之前,人们需要借助JavaScript技巧,精心设计的图片等来完成一些设计上的效果。目前CSS3的众多特性已经为所有的主流浏览器所支持,在你的设计中,你也可以放心的使用这些特性了。当然,异常总是存在的,比如奇葩的IE
系列(事实上,我本人总是有意无意的在躲避IE
)。
在介绍其他例子之前,我们先定义一个基准,假设我们有一个很简单的Box:
<section class="container">
<section class="box">
I'm a box
</section>
</section>
圆角风格可以让一个带有边框的元素看起来没有那么锋利,事实上苹果公司的很多设计都带有一些圆角,比如窗口,桌面图标等。
在CSS3中,实现圆角非常简单,只需要定义一个圆角的半径即可:
.rounded {
border-radius: 8px 8px 8px 8px;
}
这四个数字分别表示:左上,右上,右下,左下。当然,如果四个角的圆角半径一样的话,可以简写为:
.rounded {
border-radius: 8px;
}
背景渐变可以以渐变的方式来修改一个元素的背景色,从而展现出立体的效果。背景渐变可以分为两类:线性渐变
和径向渐变
。线性渐变需要指定一个方向,然后一组颜色。
颜色值按照方向上的长度被分配,比如下面这个例子中我们使用了两个颜色:
.gradient {
background: linear-gradient(to bottom, #eee, #666);
}
如果使用三种颜色:
.gradient {
background: linear-gradient(to bottom, #eee, #666, #eee);
}
径向渐变默认的会从圆心开始,并逐渐按照径向来分配选中的一组颜色:
.gradient-rounded {
background: radial-gradient(#666, #eee, #666);
}
盒阴影可以体现元素的立体感,在之前,要实现一个阴影,开发者需要绘制两个不同颜色的元素,然后叠加在一起。CSS3中的盒阴影可以大大简化这个过程。
定义一个盒阴影,需要指定这样一些参数:阴影在x轴上的偏移,阴影在y轴上的偏移,阴影的模糊半径,阴影的颜色。
.box-shadow {
box-shadow: 5px 5px 0 orange;
}
上例中我们将模糊半径设置为了0
,从而得到了一个清晰的阴影,如果将模糊半径设置为5px
:
如果将偏移设置为负数,则可以得到一个在左上角的偏移:
.box-shadow {
box-shadow: -5px -5px 5px orange;
}
盒阴影还有一个参数,可以实现内阴影:
.box-shadow {
box-shadow: -5px -5px 5px orange inset;
}
和盒阴影相似,文字阴影用来为文字添加立体的效果。
.text-shadow {
text-shadow: 2px 2px 1px gray;
}
过渡发生在元素在两个状态中切换时,它会缓慢的
的将元素从一个状态变到另外一个状态。
比如我们上例中的box
,假设其样式为:
.box {
background: white;
color: orange;
}
当hover
时,其样式变成了
.box:hover {
background: orange;
color: white;
}
这时候从鼠标进入box到前景色/背景色互换,几乎没有延迟,这在某些情况下会变得比较烦人,特别是当鼠标在一个列表中通过时,会给人以眼花缭乱的感觉。过渡
则可以让这个过程变得舒缓:
.box {
background: white;
color: orange;
transition: all .5s ease-in-out;
}
这时候当鼠标进入box到实际颜色发生变化需要0.5
秒,而ease-in-out
是一个函数名,相应的还有ease-in
,ease-out
等。他们的区别在时间很短的时候几乎觉察不到,大家可以在这里看到详细的解释。
变换事实上为我们提供了基本的动画能力,比如我们在很多网站上都见到过这样的效果:当鼠标挪到一张图片的缩略图上时,图片会变大一些,挪开之后又会复原。当然,使用JavaScript也可以模拟这个动作,不过CSS3中已经自带了这样的特性。
在CSS3中使用变换非常简单,比如刚才提到的这个效果:
.element:hover {
transform: scale(1.2);
}
当鼠标挪进该元素时,元素会变为之前的1.2
倍大。另一个常见的变换效果是旋转:
.element:hover {
transform: rotate(180deg);
}
当鼠标挪进该元素时,元素会旋转180度。我们最后再来看一个移动的变换:
.element:hover {
transform: translate(200px, 100px);
}
当鼠标挪进该元素时,元素会向右下方移动(x轴方向200像素,y轴方向100像素)。CSS3事实上支持非常多的变换函数,这里就不一一列举了,读者可以参考这个详细的函数列表。
好了,我们已经学习了足够多的理论知识了,下面就开始实际的页面开发吧,相信你已经摩拳擦掌,跃跃欲试了吧?
我们先来尝试编写整个页面的HTML结构,我们可以使用之前学习的HTML5的新标签,但是也不用彻底丢弃HTML4的标签:
<header>
<nav>
<ul>
<li><a href="#" class="compose"></a></li>
<li><a href="#" class="alert"></a></li>
<li><a href="#" class="email"></a></li>
<li><a href="#" class="tag"></a></li>
</ul>
</nav>
</header>
<aside>
<div class="profile"></div>
<div class="gallery"></div>
<div class="activities"></div>
</aside>
<section class="content">
<nav class="info">
<ul>
<li class="number">200</li>
<li class="number">120</li>
<li class="number">180</li>
<li class="number">200</li>
</ul>
</nav>
<div class="articles">
<article></article>
<article></article>
<article></article>
</div>
</section>
<aside>
<div class="trends"></div>
<div class="to-follow"></div>
</aside>
<footer>
<div class="copyright"></div>
</footer>
我们将页面分为5个主要的区域:头部,左边栏,内容区,右边栏,页脚。当然这只是一个初步的划分,如果我们发现有需要重新调整的地方,随时可以回来进行修改。
有了大的划分之后,我们就可以进行实际的开发了。我们先选择页面上的Tweet
条目进行实现,这部分非常有代表性,很多其他Web设计都包含了这样的模式,因此学会这个可以帮助我们快速的实现页面的其他部分。
一个Tweet在设计上是这样的:
对于每一条Tweet,根据HTML5对article
的描述,我们其实可以很自然的将Tweet实现为article
,所以我们可以这样定义一个Tweet:
<article class="post">
<img src="images/juntao.png" alt="" class="avator">
<section class="content">
<header>
<span class="name">Juntao</span>
<span class="account">@juntao</span>
<span class="time">2m</span>
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus veniam quas, deserunt! Provident sit, impedit, facilis molestias minus quas hic ad deserunt quia, alias velit architecto debitis itaque doloremque quaerat.</p>
<footer>
<nav>
<a href=""><i class="icon-redo"></i></a>
<a href=""><i class="icon-star"></i></a>
<a href=""><i class="icon-loop"></i></a>
<a href=""><i class="icon-ellipsis"></i></a>
<a href=""><i class="icon-maximize"></i></a>
</nav>
</footer>
</section>
</article>
每个Tweet
中,首先需要一张作者的头像,然后是用户昵称,用户名,时间,正文,在正文下面有一些link,包括转发,赞等。这种布局方式非常常见,你可以仔细看一下上一周的设计,同样会发现这种模式:左边是一个独立的图片,右边是另外一大块的信息,右边的信息都严格的左对齐。
通常要实现这种布局,我们需要先为左右两部分设置一个相同的父元素,比如此处的post
。然后将父元素的position
设置为relative
,将左边的元素的position
设置为absolute
,这样左边的元素就可以相对于父元素绝对定位了。最后,为右边的元素设置一个margin-left
,空出一定的距离给左边的元素。
在未应用样式之前:
我们先来为头像加上样式,首先需要限定头像的大小(30x30),然后将border-raduis设置为100%,这样可以得到一个完美的圆。最后,将其对于父元素的偏移设置好:
.avator {
width: 3em;
height: 3em;
@include border-radius(100%);
position: absolute;
top: 2em;
left: 2em;
}
然后我们需要将用户昵称,用户名等浮动起来,并且将底部的那些可以点击的链接也浮动起来:
.post {
position: relative;
text-align: left;
padding: 2em;
background: $post-bg-color;
border-bottom: 1px solid $body-color;
.content {
margin-left: 4em;
span {
margin-right: 1em;
&.name {
font-weight: bold;
}
&.account {
font-weight: lighter;
color: $gray-text-color;
}
&.time {
color: $gray-text-color;
float: right;
margin-right: 0;
}
}
}
header {
margin-bottom: 1em;
}
section {
margin-bottom: 1em;
p {
line-height: 1.4;
font-weight: normal;
}
img {
width: 100%;
margin-bottom: 1em;
}
}
footer {
a {
text-decoration: none;
color: $gray-text-color;
margin-right: 1em;
&:last-child {
float: right;
margin-right: 0;
}
&:hover {
color: $text-color;
}
}
}
}
这样就可以得到一个非常接近设计稿的Tweet
了:
在CSS2中,颜色可以通过三种方式来表示
red
,orange
#004c97
rgb(255, 122, 0)
颜色值有红,绿,蓝混合表示,每种颜色的取值都在区间0-255内,比如#004c97
表示,红色值为0(0x00)
,绿色值为76(0x4c)
,蓝色值为151(0x97)
。
在CSS3中又引入了三种新的颜色表示法,分别为rgba,hsl和hsla。rgba为rgb添加了alpha通道,即透明通道。
比如:
background-color: rgba(200, 120, 80, 0.2);
最后一个数字的取值范围在区间0-1之间,如果该值为0,则表示完全透明,值为1则表示完全不透明。
CSS3引入的HSL色彩空间是一个非常有意思的表示法。我们通常描述颜色的时候,不会直接转换成RGB的值,更多的时候我们会说:我想要这个按钮是亮一点的蓝色,或者当我们看到一种不太红的红色,我们直观的想法是让它更偏向红色一些。但是这些描述无法通过RGB表示法表达出来,而HSL则可以做到这一点。
HSL分别表示Hue(色相),Saturation(饱和度),Lightness(亮度)。色相就是我们常说的红色,蓝色等;饱和度是指,在色相中参入的白色的程度,饱和度越高,色彩就越锐利,越接近色彩本身的值;亮度是在色相中参入黑色的程度,亮度越高越亮,越低越暗。我们可以通过两张图来描述清楚HSL色彩空间:
从上图可以看出HSL色彩的分布情况。使用HSL来表示颜色需要三个参数:
background-color: hsl(30, 100%, 50%);
上面的颜色定义指:色相为30,饱和度为100%,亮度为50%的颜色,色相在色盘上的位置如下图所示:
如果已知一个颜色的定义是hsl(200, 80%, 40%)
,比如用户反馈说这个色彩太暗,我们可以很容易的调整40%
为45%
或者50%
;或者用户抱怨色彩不够深,不够蓝,我们事实上又可以调整色相后者饱和度。
随着不同尺寸的移动设备的出现,开发者需要完成一种设计,这种设计可以在不同的设备上都正常工作。流式布局(完全按照百分比来定位,去除代码中关于尺寸的硬编码)可以在不同的较大的屏幕上很好的工作。在移动设备上,虽然流失布局也很好的显示,但是由于手机屏幕本身的限制,一个很小的百分比的元素并不真的可用。比如在桌上显示器上,20%是一个足够大的可视区域,但是在手机上可能就完全无法识别了。
因此,响应式设计应用而生,简而言之,响应式设计为每个不同尺寸的设备分别作了设计。比如在桌面上,每行可以显示4张图片,而在iPad上,每行显示两张,在手机上,每行只显示一张图片。这样可以保证对于不同尺寸的设备都提供很高的可用性。
在CSS中,你可以知道屏幕的尺寸,并且根据尺寸的不同来应用不同的CSS文件,这个机制就是media query
。比如我们可以在一个link
标签中写这样的代码:
<link rel="stylesheet" media="screen and (max-width: 480px)" href="numbers-small.css" />
这个CSS会在最大视口(viewport)为480px的环境中生效。同样,我们可以在CSS代码中使用这样的表达式:
.information {
background-color: red;
}
@media screen and (min-width: 1024px) {
.information {
background-color: yellow;
}
}
所有的响应式设计都依赖于这个机制,一旦我们可以感知屏幕的尺寸,就可以为其应用不同的样式:将某些元素的宽度增大,隐藏某些元素等等。接下来我们来看一个实例,并从中学习如何在我们的页面中使用响应式设计。
比如Twitter new face
中,我们可以看到一些数字,我们可以将它改造成响应式的。
<section class="numbers">
<ul>
<li class="item">
<h4>Tweets</h4>
<p>200</p>
</li>
<li class="item">
<h4>Photo/Videos</h4>
<p>250</p>
</li>
<li class="item">
<h4>Following</h4>
<p>55</p>
</li>
<li class="item">
<h4>Followers</h4>
<p>180</p>
</li>
</ul>
</section>
我们在桌面浏览器中,需要将这4个数字展现在同一行上:
.numbers {
width: 60em;
margin: 2em auto;
background: $post-bg-color;
li {
float: left;
width: 25%;
box-sizing: border-box;
padding: 1.5em 3em;
border-bottom: 3px solid transparent;
transition: all .3s ease-in;
h4 {
text-transform: uppercase;
color: $gray-text-color;
}
p {
margin-top: 1em;
font-weight: bold;
}
&:hover {
border-bottom: 3px solid $twitter-color;
}
}
@include clearfix;
}
Sass在3.2之后,提供了非常方便的机制,我们可以根据不同的尺寸来应用不同的样式。首先定义一个mixin
,这个mixin
接受三个可能的参数,分别表示手机,平板和桌面浏览器。
@mixin respond-to($media) {
@if $media == handhelds {
@media only screen and (max-width: $break-small) { @content; }
}
@else if $media == medium-screens {
@media only screen and (min-width: $break-small + 1) and (max-width: $break-large - 1) { @content; }
}
@else if $media == wide-screens {
@media only screen and (min-width: $break-large) { @content; }
}
}
而我们需要先定义两个break-point:
$break-small: 320px;
$break-large: 1024px;
在使用的时候,只需要指定:
li {
float: left;
width: 25%;
@include respond-to(medium-screens) {
width: 50%;
}
//...
}
对于手机屏幕:
li {
float: left;
width: 25%;
@include respond-to(handhelds) {
float: none;
width: 100%;
}
//...
}