CSS设计指南(响应式设计)

使用一项叫媒体查询的CSS 功能,很容易检测出用户设备的屏幕大小。然后,据以提供替代或额外的CSS,可针对相应屏幕实现更加优化的体验。使用这种方式创建对设备有感知力的网站,被称为响应式设计。

响应式设计的要素
响应式设计包含三个重要的方面。

  • 媒体查询:是一种CSS 语法,可以根据浏览器的特性,一般是屏幕或浏览器容器宽度提供CSS 规则;
  • 流式布局:是使用em 或百分比等相对单位设定页面总体宽度,让布局能够随屏幕大小而缩放;
  • 弹性图片:是使用相对单位确保图片再大也不会超过其容器。

媒体查询

媒体查询是CSS 代码的容器,其中的CSS 只在某些条件(比如,当前页面要被打印或者要显示在某种类型或尺寸的屏幕上)具备时才会应用。媒体查询可以用两种方式来写:@media 规则和<link>标签的media 属性。

@media规则

第一种方式是@media 规则,可以在样式表或<style>标签的CSS 中包含媒体查询,比如:

@media print {
  nav {
    display:none;
  }
}
//这条规则声明:如果当前页面要打印,那么就不显示nav 元素。

大家注意,这里是把CSS 规则嵌套在了一个@media 规则中,乍一看似乎有点不太习惯。尽管可以把CSS 规则嵌套在媒体查询里,但媒体查询本身却不能互相嵌套。下面再看一个假设的示例,其中涉及最大屏幕宽度。

/*只在屏幕宽度不大于568 像素时应用*/
@media screen and (max-width:568px) {
  .column {float:none; width:96%; margin:0 auto;}
}

媒体类型
最常用的媒体类型如下所示:

  • all:匹配所有设备;
  • handled:匹配手持设备(小屏幕、单色、带宽有限);
  • print:匹配分页媒体或打印预览模式下的屏幕;
  • screen:匹配彩色计算机屏幕;
  • 其他媒体类型还有braille(盲文点字触觉反馈设备)、embossed(盲文分页打印机)、projection(投影仪)、speech(语音合成器)、tty(电话机屏幕等固定宽度字符栅格设备)和tv(电视机)。

当然,任意时刻浏览器窗口中只能使用一种媒体类型。媒体类型从IE6 开始就得到支持了,但媒体特性到IE9 以上才得到支持。一般来说这并不是问题,因为我们使用媒体特性多数情况下都是为了检测平板电脑或智能手机等现代设备。

媒体特性
媒体特性也就是媒体某一方面的特征,一般带有min-或max-前缀。最常用的媒体
特性如下:
min-device-width 和max-device-width:匹配设备屏幕的尺寸;
min-width 和max-width:匹配视口的宽度,例如浏览器窗口宽度;
orientation(值为portrait 和landscape):匹配设备是横屏还是竖屏。
如果想通过媒体查询来根据用户对浏览器窗口的缩放重新调整布局,应该使用min-width 和max-width。
可以使用逻辑运算符and、not、or 及关键字all、only 组合媒体类型和媒体特性。其中,only 关键字可以用来对不支持媒体查询的浏览器隐藏样式表。

<link>标签的media属性

如果要通过媒体查询应用的CSS 规则非常多,那么就可以考虑使用<link>标签的media 属性设定条件,有选择地加载独立的样式表。

<link type="text/css" media="print" href="css/print_styles.css" />
<link type="text/css" media="screen and (max-width:568px)"
href="css/iphone_styles.css" />

断点

断点(breakpoint)在这里指的是媒体查询起作用的屏幕宽度,其写法类似如下形式。

@media screen and (max-width:640px) { /*CSS 规则*/ }
//在这里,断点是640 像素宽。如果有设备的屏幕宽度等于或小于断点设定的宽度,
//那么后面的CSS 就会起作用。

用<meta>标签设定视口

iPad 和iPhone 会把适合大屏幕的网页缩小,以便在它们较小的屏幕上能看到网页的全貌。这是一个通用技巧,但对于手机——特别是iPhone来说,由于文字实在太小了,为了看清楚网页内容,肯定得用扩展手势放大页面,然后再来来回回地扫屏。如果你想让自己的页面布局适合这些小屏幕,首先就要覆盖这种自动缩小的设定。方法是在页面的<head>标签里添加一个<meta>标签:

<meta name="viewport" content="width=device-width; maximumscale=1.0" />

这个<meta>标签告诉浏览器按照屏幕宽度来显示网页,不要缩小网页。虽然这样可以让布局以实际宽度显示,但在iOS 设备(如iPad 和iPhone)中却会引发一个已知的bug。关于这个bug 及如何解决,后面再交待。

针对平板优化布局

@media only screen and (max-width:1000px) { /*1000 像素的断点*/
    body {
        margin:0 8px 20px; /*添加右外边距,以防滚动条碍事儿*/
    }
    #wrapper {width:98%;} /*布局由固定变成流动*/
    header {
        height:100px; /*增加页眉高度,为重新定位菜单留出空间*/
        padding:1px 0 0 0; /*防止导航菜单的上外边距叠加*/
    }
    header nav.menu {
        margin-top:65px; /*把菜单移动到页面标题和搜索框下方 */
    }
    section#feature_area {padding-bottom:0;} /*用不着了*/
    section#feature_area article { /*让博文摘要部分与布局同宽*/
        float:none; /*不需要浮动了*/
        width:auto;/*自动填满布局*/
    }
    section#feature_area aside { /*原来的右栏同样与布局同宽*/
        float:none;
        width:auto;
    }
    section#feature_area aside form {
        float:left; /*浮动到左侧*/
        margin:15px 0 0 0; /*与nav 的上外边距一致*/
    }
    section#feature_area aside nav {
        width:17em; /*缩小博文链接区的宽度*/
    }
} /*1000 像素断点结束*/
在竖屏时由于宽度小于1000 像素,就会得到新的流动布局

针对智能手机优化布局

@media only screen and (max-width:640px) {
    header {height:100px;}
    header nav.menu {width:94%; font-size:.65em; } /*水平间距更多了*/
    section#book_area article { /*博文摘要*/
        width:auto;
        float:none;
        margin:0; padding:0; /*每本书的容器都与布局同宽*/
    }
    section#feature_area aside form,
    section#feature_area aside nav { /*博文链接*/
        margin:10px auto; /*添加上、下外边距*/
        float:none;
    }
    /*图片容器与布局同宽*/
    section#book_area article .inner {width:98%; margin:0 0 0 5px; }
    #book_area .inner h3 { /*取消文本旋转效果*/
        -webkit-transform:none;
        -moz-transform:none;
        -moz-transform-origin:none;
        -ms-transform-origin:none;
        transform:none;
        position:static;
    }
    #book_area article img { /*相对设备宽度确定图片宽度 */
        width:40%;
    }
    section#book_area {background:#fff; padding: 0 10px 10px; margin:0 0 10px;}
    #book_area article aside { /*在图片旁边显示弹出层*/
        display:block;
        position:static;
        float:right;
        margin:0; padding:0 0 20px 0;
        font-size:.8em;
        border:none;
        width:55%;
        box-shadow:none;
    }
    section#book_area article aside::before, /*隐藏弹出层的三角*/
    section#book_area article aside::after {
        display:none;
    }
}

针对竖屏进一步优化

@media only screen and (max-width:320px) { /*iPhone 竖屏*/
    header {height:90px;} /*缩小页眉高度*/
    header section#title h1 {font-size:1.25em;} /*文本再小一点*/
    header section#title h2 {font-size:.75em;} /*文本再小一点*/
    header form.search {top:6px; right:2px;} /*搜索框上移*/
    /*按比例缩小,并上移菜单*/
    header nav.menu {font-size:.55em; margin-top:55px;}
    nav.menu ul li a {
        padding:5px 4px; /*增大链接,方便点击*/
        margin:0;
    }
}

最后两个问题

移动Safari中的缩放bug

Safari Mobile(iPhone 浏览器)中有一个bug,在设备从竖屏旋转到横屏时会导致缩放和重绘问题。有一个JavaScript 脚本可以解决这个重绘问题,请参考这里:
http://webdesignerwall.com/tutorials/iphone-safari-viewport-scaling-bug

让下拉菜单支持触摸

最后,还有一个问题要解决,那就是让下拉菜单支持触摸操作。
问题在于,支持触摸的设备会跳过:hover 规则中对visibility 属性的过渡。似乎也不算太意外,毕竟这个属性只是简单地切换了一个布尔值的状态,从而实现显示和隐藏。但这也说明visibility 属性不是过渡动画的理想对象。除非我去掉visibility属性,否则菜单在触摸屏上没法用。可是如果真这样做,在非触摸屏上只要鼠标经过菜单下方,就会导致下拉菜单显示出来。因为下拉菜单虽然处于完全透明状态,但它对鼠标还是“可见的”。解决方案是使用Modernizr 检测设备是否支持触摸,如果支持再去掉对visibility 属性的过渡。如果设备支持触摸,Modernizr 会给根元素html 添加一个touch 类,我们就可以针对触摸设备单写一条规则:

/*Modernizr 检测到触屏,再去掉妨碍菜单过渡的visibility 属性*/
.touch nav.menu li ul {
  -webkit-transition:1s opacity;
  -moz-transition:1s opacity;
  transition:1s opacity;
}

这条规则对(不支持触摸的)非移动设备是不适用的。在触摸设备上,有了它用户在触摸相关菜单项时,下拉菜单就会显示出来。不过,当用户再触摸别的地方时,菜单会立即消失,而不是淡出屏幕。实际上,淡出效果的唯一好处,就是当用户鼠标意外离开时,再移回去还能把菜单“召回”。因此,在不使用鼠标的触摸设备上,这种“突然消失”的效果还是可以接受的。
请大家注意,这个菜单只有在触摸屏幕其他地方的时候才会消失。因为触摸其他地方会触发收缩bug 的代码(上一节介绍过),强迫JavaScript 运行,这样就足以让菜单意识到当前已经不再是悬停状态而关闭了。另一个实现这种“触摸其他地方关闭”效果的方法是执行某个JavaScript 函数。比如,下面就是执行jQuery 的noop 函数(英文noop 的意思是“无操作”)的例子。虽然这个函数什么也不做,但只要通过触摸屏幕其他地方来调用它,就可以关闭菜单了。

(function(){ $(window).on('touchstart',$.noop); })();

假如你不需要修复缩放bug,那么只要加上这行代码就可以关闭菜单了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    wzhiq896阅读 1,737评论 0 2
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    love2013阅读 2,306评论 0 11
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,741评论 1 92
  • 第三方公司的风格山东理工;离开多少个 史蒂芬港史蒂芬港nbrtertsfgh
    phoenix_afs阅读 153评论 0 1
  • 上个月,软银宣布斥资33亿美元现金或每股8.08美元,收购美资管公司堡垒投资集团(Fortress Investm...
    清大管理阅读 429评论 0 0