VillainHR

响应式开发

响应式 PWA 2017-03-09

PWA 是专门应对手机开发而提出的概念,不过,由于手机端在国内四分五裂的局面看来(还包括 PC/Pad),屏幕尺寸的不同,网页设计的样式和大小当然也是完全不一样的。为了让 Web 能完美的在多端上运行,这里,我们就需要进行响应式开发。

响应式的目的就是让一个网站尽可能的适配所有大小的网页。当然,响应式开发所用到的技术也是非常之多,不过,主要的还是 CSS 。

meta 标签

meta 标签之所以重要,是因为它在手机端适配上起到的作用可以说是非凡的意义。meta 标签分很多种,比如:

<meta name="keywords" content="your tags" />
<meta name="description" content="150 words" />
<meta name="robots" content="index,follow" />
<meta name="author" content="author name" /> <!-- 定义网页作者 -->
<meta name="google" content="index,follow" />
<meta name="googlebot" content="index,follow" />
<meta name="verify" content="index,follow" />
//...

meta 标签根据 name 的不同有着自己独特的任务,大部分是设计 SEO 的,我这里就不详谈了。meta 与响应式相关的 nameviewport。它是为了防止页面被浏览器/用户私自缩放而制定的。如何使用呢?很简单,在 head 标签中直接添加:

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
</head>

下图是设置了之后的效果:

iphonescale.jpg-88.2kB

不过,上述 viewport meta 标签对 PC 是无效的,所以,在 PC 上无需担心。我先简单讲解一下 viewport 里面的基本属性:

  • width: viewport 的大小
  • device-width: 当前设备屏幕的宽度
  • height: viewport 的高度
  • device-height: 当前设备屏幕的高度
  • initial-scale: 当前页面的缩放比例。1.0 是不缩放
  • maximum-scale: 当前页面的最大缩放比。
  • user-scalable: 能让用户能够进行缩放页面(大部分情况是双击)。为了取消一些浏览器的 click 延迟,需要设置为 no

media query

MQ(media query)是在 CSS2.1 提出来的概念,在 CSS3 中得到增强。它主要是针对屏幕的相关参数的变化,做出相关的文件选取或者显示区别。具体用法为:

<link rel="stylesheet" type="text/css"
  media="screen and (max-device-width: 480px)"
  href="shetland.css" />
  
<style>
@media (max-width: 600px) {
  .facet_sidebar {
    display: none;
  }
}
</style>

只有满足 MQ 要求的样式/CSS 才能被应用,不过,不管用不用 MQ,所有的 CSS StyleSheet 都会被下载。所以,这就比较尴尬。我们来先来看一下语法。 这是所有的语法值:

media_query_list: <media_query> [, <media_query> ]*
media_query: [[only | not]? <media_type> [ and <expression> ]*]
  | <expression> [ and <expression> ]*
expression: ( <media_feature> [: <value>]? )
media_type: all | aural | braille | handheld | print |
  projection | screen | tty | tv | embossed | speech
media_feature: width | min-width | max-width
  | height | min-height | max-height
  | aspect-ratio | min-aspect-ratio | max-aspect-ratio
  | color | min-color | max-color
  | color-index | min-color-index | max-color-index
  | monochrome | min-monochrome | max-monochrome
  | resolution | min-resolution | max-resolution
  | scan | grid

我们先来看一下基础属性。

基础属性

首先,我们这里不会对所有的基础属性进行讲解,只会选常用的。基础属性需要对属性进行赋值,例如:

height:200px

width

定义设备的宽度。当然配套的就有:max-widthmin-width。还有啥 device-width/device-height 这两个属性,它们已经从标准从废除了,一般都用 width/height 进行替代。 最经常用到的就是 min-widthmax-width 这两个属性。

  • min-width 表示 >= 该宽度值。min-width: 200em
  • max-width 表示 <= 该宽度值。max-width: 200em

举个实在的例子,假如有一个元素要在 500px~800px 之内显示,其它范围内隐藏,使用 media query 就应该写为。

// 范围在 [500,800] 之内
@media (max-width: 800px) and (min-width:500px) {
  .facet_sidebar {
    display: block;
  }
}

// 范围在 [500,800] 之外隐藏
@media (max-width: 500px) , (min-width:800px) {
  .facet_sidebar {
    display: none;
  }
}

height

定义设备的高度,不过这个不常用到。用法和 width 一样,只是它是用来定义高度的。

// 范围在 [500,800] 之内
@media (max-height: 800px) and (min-height:500px) {
  .facet_sidebar {
    display: block;
  }
}

device-ratio

该属性表示设备屏幕的宽高比,这主要是对完美主义设置的,不同屏幕的比例不一样,带来的视觉也会发生变化。注意,在赋值的时候,应该写为:宽/高。中间用 / 连接。例如,针对 3:7 和 1:1 的屏幕应用不同的 CSS:

// 3:7
<link rel="stylesheet" type="text/css"
  media="device-ration: 3/7"
  href="3-to-7.css" />
  
// 1:1
<link rel="stylesheet" type="text/css"
  media="device-ration: 3:7"
  href="3-to-7.css" />

另外,还有两个配套的:max-device-ratiomin-deivce-ratio。用法和上面的一样,这里我就不多说了。

orientation

该属性是用来检测屏幕的翻转,即,横向和纵向。不过,它的取值有点怪。

  • landscape:横向模式。大家可以理解为一般风景的时候都是广角,能够将很大的美景收入眼中。
  • portrait:纵向模式(也就正常模式)。本意是肖像画的意思,大家想想 蒙娜丽莎的微笑 的画就 OK。

用法也简单:

@media (orientation: portrait) { ... }

resolution

该属性对于 retina 屏幕来说很有效,这支持两种单位,一个是 dpi(dots per inch)dppx(Dots Per Pixel)。这里,我们需要对这两个单位做一些解释,首先是 dpi。

dpi 表示每单位英寸面积内有多少像素点(注意,是物理像素点)。一般来说,Web 是大于 72dpi 的。不过,该单位不常用到 Web 中,通常是针对打印机和照相机相关参数的描述(特别是打印机,主要是该单位)。

dppx 每个设备像素(即,CSS 中的 px 单位)中包含几个物理像素,该单位和 dpr 完全,只是不同的叫法。dpr 是 device-pixel-ratio,像素分辨率。它的计算公式为:

设备像素比 = 物理像素 / 设备独立像素

一般,retina 的 dppx 是 2。不过,iphone6 一下是 2,iphone6p 是 2.64,而 iphone 6 Plus 以上是 3(尴尬)。一般情况下,我们只要对 2 和 3 做相关处理即可。当然,他还有 min-resulotionmax-resolution 两个配套处理。

@media (min-resolution:2dppx){ ... }

逻辑处理

在 MQ 中,逻辑处理和程序中的一样,有:andnot,(表示或),only。例如:

@media (max-width: 800px) and (min-width:500px) {
  .facet_sidebar {
    display: block;
  }
}

在 MQ 中,还有几个常量值,表示设备的类型,常用的有:allhandheldprintscreen等等。

  • all:所有设备适用
  • handheld: 手提设备
  • print:打印设备
  • screen:屏幕设备

例如:

@media screen and (max-width: 800px) and (min-width:500px) {
  .facet_sidebar {
    display: block;
  }
}

不同资源文件

media 不仅可以用在 CSS 中,还可以直接运动到 link,用来筛选我们网站需要的资源,比如,根据 resolution 来进行区分:

<link rel="stylesheet" media="screen and (resolution: 0.75dppx )" href="ldpi.css" />
<link rel="stylesheet" media="screen and (resolution: 1.0dppx )" href="mdpi.css" />
<link rel="stylesheet" media="screen and (resolution: 1.5dppx )" href="hdpi.css" />
<link rel="stylesheet" media="screen and (resolution: 2.0dppx )" href="retina.css" />

或者横竖不同的样式:

<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">    // 竖放加载
<link rel="stylesheet" media="all and (orientation:landscape)"href="landscape.css">   // 横放加载

flex 布局

弹性布局是在 2009 年提出的,这是区别于以往常规布局的一种新的布局方式。它是基于一维(x/y)方向进行布局。最新提出的 grid 二维布局,则是面向未来的大型网站的布局结构。这里,我们不贪多,先讲一下 flex 的一维布局方式。

基本术语

首先声明一点,flex 布局,不仅仅是你使用 display:flex 就行。这是一个完整的概念,是由许多标签属性共同组成的。我们先来看一下它的基本术语:

flexbox.png-11.5kB

其中,最为重要的是主轴(main axis) 和 辅轴(cross axis),容器(container) 和 子元素(items)的概念。我们一个一个来介绍一下:

  • main axis:主轴是 flex item 在设置尺寸大小,排列方式的参照物。是有 flex-direction 设置。
    • main-start / main-end:主轴的开头/末尾
    • main-size:主轴的尺寸大小
  • cross axis:辅轴是垂直于主轴的方向。
    • cross-start / cross-end:辅轴的开头/末尾
    • cross-size:辅轴的大小
  • container:是 flexbox 的容器元素。使用 display:flex 来进行命名。
  • items:是容器的第一级子元素。两者的区别,可参照下图:

image_1b9q3kbmruuvimv7k01hpjckh9.png-10kB

在 flexbox 中,可以根据作用对象的不同,将属性分为父容器属性和元素属性。下面,我们就这两类来展开讲解。

容器属性

定义一个容器很简单,直接使用 display:flex 进行修饰即可:

// inline-flex 是修饰行内不可分离的 flexbox 布局
.container {
  display: flex; /* or inline-flex */
}

flex-direction

该标签可以用来设置 主轴 的方向,通常有 4 种:

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
  • row:从左到右(按照中国排版标准来定义)。默认值
  • row-reverse:反向,从右到左排列。
  • column:自上而下
  • column-reverse:自下而上

具体排布可参照如图:

image_1b9q46ps0fhp19pcj931k2h0em.png-2.4kB

flex-wrap

该标签定义是否可以进行换行。默认情况下,所有弹性盒子里的元素都会排列在一行里。它有 3 个属性值:

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap:不换行。超出的元素会根据剩余空间的大小来确定自身的大小。默认值
  • wrap:可以换行,如果元素超出容器的尺寸,则可以排列到下一行中。
  • wrap-reverse:反向换行,该属性和上一个的区别在于,多余的那一行将会替代原来的位置。差异如图:

image_1b9q4feem12pi1etd1vldhetrmv13.png-7.4kB

flex-flow

该标签没啥说的,就是 flex-direction 和 flex-wrap 的合并标签。

flex-flow: <‘flex-direction’> || <‘flex-wrap’>

justify-content

用来定义子元素在主轴上排列的方式。可用属性值有 5 个:

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}
  • flex-start:items 紧贴着 container 的 main-start 排列。默认值
  • flex-end:items 紧贴着 container 的 main-end 排列
  • center:items 在 container 里,居中排布
  • space-between:items 会带上空隙,在 container 中均匀排布,不过,首尾 item 紧贴边。
  • space-around:每个 item 会均匀分配一些空隙,首尾只有一份空隙,其余有两份,因为,其余是两个 item 的和。具体差异如图:

image_1b9q4qtg0h7717k2kk11g7q1sqo1g.png-13.8kB

align-items

定义元素在辅轴上的排列。它的几个值和 justify-content 差不多:

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}
  • flex-start: items 紧贴在辅轴的 cross-start
  • flex-end:items 紧贴在辅轴的 cross-end
  • center:items 在辅轴上,居中排列。
  • baseline:items 根据内容的 baseline 对齐排列。
  • stretch:items 充满整个辅轴。具体排布如下图:

image_1b9q5c3hclgjm0qocq1v9imlh1t.png-15kB

align-content

该标签是用来定义多行情况下,行元素整体的排布。(如果只是一行,就没必要了。)具体属性有:

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
  • flex-start:多行元素紧贴着 main-start 排布
  • flex-end:多行元素紧贴着 main-end 排布
  • center:多行元素在辅轴上,居中排布
  • space-between:多行元素根据空隙,在辅轴上均匀排布,并且,首尾贴边
  • space-around:每行元素两端会自动带上一份空隙,不过,首尾两端只有一份,其余有两份(是两行空隙之和)
  • stretch:每行元素均匀充满整个主轴,默认值。具体排布见图:

image_1b9q5tcpd13oqqpu1veu1g62tod2a.png-17.3kB

接下来,我们来看一下 items 相关的 flexbox 属性。

items 属性

在 items 设置相关的属性,是直接在子元素中设置,而不是在父容器中。只要是父容器下的第一级子元素都被称作为 items。接下来,我们就来看一下,与之相关的标签属性。

order

默认情况下 items 是 HTML 中的顺序来排布的,不过,你可以通过 order 标签来手动更改他们的顺序。数值越大,排列的位置约靠后

// 有 3 个元素。item_1 排第一个
.item_1 {
  order: 2;
}
// 当设置 order 之后 item_1 变为最后一个

flex-grow

该标签从来设置子元素自身可以占据多大的空隙,接受的值只能为 >=0 的整数,默认为 0。例如:

.item_1 {
  flex-grow: 1;
}
.item_2 {
  flex-grow: 1;
}

此时,会将空隙平均分为两份,item_1 和 item_2 各占一份。如果这样:

.item_1 {
  flex-grow: 1;
}
.item_2 {
  flex-grow: 2;
}

那么,空隙一共会分为 3 分,item_1 占 1 份,item_2 占两份。

flex-shrink

该标签是用来定义,如果在行内时,有元素超出容器的宽度,那么其它元素会相应的自适应缩小。默认情况下,所有的子元素的 shrink 都为 1:

flex-shrink:1

如果你将 item_1 设置为 2,则超出的部分会被多分 1 份到 item_1 上进行缩小。

flex-basis

设置在没有空隙分配时的默认尺寸。如果有空隙出现,并且,你没有设置 flex-grow,那么默认是不会分配空隙到该元素的 content 中。如果你设置了 flex-grow,那么优先当其他元素已经达到使用 width 或者 height 设置的尺寸时,才会给其分配相应的空隙。 在弹性盒子中,widthheight 有效性是在有多余空间,并且处于默认 item 样式(即,没 grow/shrink)时。大部分情况,如果你想设置固定大小的盒子,需要将 grow 和 shrink 设置为 0.

.fix-item{
    flex-basis:200px;
    flex-grow:0;
    flex-shrink:0;
}

该标签有两个取值类型:

.item {
  flex-basis: <length> | auto; /* default auto */
}

auto 表示按默认情况来,即,遵循缩放,多余的空间会分配到 content 中去。

flex

该标签也是一个综合标签,flex-shrink 和 flex-basis 是可选的。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

默认值为:

.item {
  flex: 0 1 auto;
}

align-self

单独设置 item 在辅轴上分布的位置。取值和 align-items 一样。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

例如:

image_1b9qt86ek1k6134v1eu4q6i14g62n.png-5.1kB

另外,float, clear 和 vertical-align 这几个标签,对 items 无效,这点需要牢记。

兼容

flex 现在的兼容性已经很棒了,所有的主流平台都会兼容,不过,如果你还有针对 Android 4.3 以前的版本,则需要加上相关的 prefix。大致的 prefix,如下:

 display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;

不过,最好还是采用编译的形式,有时候就不用自己手动加了。

rem vh vw 响应式

在响应式开发中,一般提倡使用的是灵活单位而非固定的 px 值。近年来比较好用的就是 rem 单位。另外,还有其他的单位,例如:emvhvw 等。这里,集中说明一下:

  • em:准确的说是相对于父节点的字号来计算的,如果自身定义了字号那么就相对自身字号来计算(针对其他属性使用 em 单位)。例如:
.parent{
    font-size:20px;
}
.child{
    font-size:2em; // 40px
    padding:2em; // 80px
}
  • vh/vw:这两个单位实际上是相当于 viewport 来定义的。vh 相当于 1% 的 viewport 高度。vw 相当于 1% 的 viewport 宽度。这就可以让我们脱离父元素宽度的限制了。常常用于整块布局,而它的兼容性也挺好的,Android 4.4 都支持。
  • vmin/vmax:这两个单位和上面的区别在于,它们不代表某个具体的宽高,而是代表大小,如果宽 > 高则,vmax = 1% 宽,vmin = 1% 高,反之依然。他们的兼容性和 vh/vw 一样,也是在 Android 4.4 以上可用。这两个属性看起来挺鸡肋的,不过实际上用处很多。例如,实现背景图的 containercover 的效果。
// 实现 container
.bg{
    width:100vmin;
    height:100vmin;
}

如图:

image_1b9t3c1lp15ha132c16i61a7m16f89.png-21.7kB

// 实现 cover 效果
.bg{
    width: 100vmax;
    height: 100vmax;
}

如图:

image_1b9t3d8kj1doo1hphii111iv1bmet.png-23.1kB

  • rem:该单位是相对于根元素 html 的大小。该属性值用处比较大,常常用在 retina 兼容上。
// 根据根元素的 font-size 设置
html{
    font-size:14px;
}
.some-node{
    font-size:2rem; // 28px
}

在 retina 兼容屏上,常常会根据 dpr 的大小来手动调整根元素的 font-size,来对相关的屏幕进行兼容。

// iphone6 的基准值
@media (min-width : 375px) and (max-width : 667px) and (resolution : 2dppx){
      html{font-size: 37.5px;}
}

//iphone5 的基准值
@media (min-width : 320px) and (max-width : 568px) and (resolution : 2dppx){
      html{font-size: 32px;}
}

大致的属性使用就是上面几类,大家有空的时候多多写一下,就能铭记于心了。

原文链接: https://www.villianhr.com/2017/03/09/响应式开发