一、响应式布局概念
Responsive design 能实现不同屏幕分辨率的终端上浏览网页展示不同样的样式。使网站在手机和平板电脑上有更好的浏览阅读体验
二、响应式设计的步骤
1. 设置 Meta 标签
大多数移动浏览器将HTML 页面视图(viewport) 的宽为设备宽度,用来适应屏幕分辨率
你可以使用视图的 meta标签 来进行重置
<!-- 按快捷键 meta:vp+tab 可以快速生成 -->
<head>
<meta charset="UTF-8">
<!-- 在<head>标签里加入这个meta标签 -->
<!-- 下面的视图标签告诉浏览器,使用设备的宽度作为视图宽度并禁止初始的缩放 -->
<meta name="viewport" content="width=device-width,
initial-scale=1.0,
minimum-scale=1.0
maximum-scale=1.0,
user-scalable=no">
</head>
[1]user-scalable = no 属性能够解决 iPad 切换横屏之后触摸才能回到具体尺寸的问题
2. 通过媒介查询来设置样式 Media Queries
Media Queries 是响应式设计的核心
/* 它根据条件告诉浏览器如何为指定视图宽度渲染页面。假如一个终端的分辨率小于 980px */
@media screen and (max-width: 980px) {
#head { … }
#content { … }
#footer { … }
}
2.1 设置多种试图宽度
/** iPad **/
@media only screen and (min-width: 768px) and (max-width: 1024px) {}
/** iPhone **/
@media only screen and (min-width: 320px) and (max-width: 767px) {}
2.2 智能手机(纵向和横向)视图
/* 智能手机(纵向和横向)Smartphones (portrait and landscape) */
@media only screen and (min-device-width : 320px) and (max-device-width : 480px) {
}
/* 智能手机(横向) */
@media only screen and (min-width : 321px) {
}
/* 智能手机(纵向)Smartphones (portrait) */
@media only screen and (max-width : 320px) {
}
3. 响应式图像
响应式设计的网页图像,就是 响应式图像 responsive image
响应式图像的解决方案有很多,JavaScript 和 CSS 都可以实现。本文介绍最简单的、语义性最好的 HTML 方法,浏览器原生支持
3.1 问题的由来
/* <img>标签用于插入网页图像,所有情况默认插入的都是同一张图像 */
<img src="foo.jpg">
上面代码在桌面端和手机上,插入的都是图像文件 foo.jpg,这种处理方法固然简单,但是有三大弊端:
- 体积: 一般来说,桌面端显示的是大尺寸的图像,文件体积较大。手机的屏幕较小,只需要小尺寸的图像,可以节省带宽,加速网页渲染
- 像素密度: 桌面显示器一般是单倍像素密度,而手机的显示屏往往是多倍像素密度,即多个像素合成为一个像素,称为 Retina屏幕。图像文件很可能在桌面端很清晰,放到手机上会有点模糊,因为像素扩充了
- 视觉风格: 桌面显示器的面积较大,图像可以容纳更多细节。手机的屏幕较小,许多细节是看不清的,需要突出重点
上面两张图片,右边的手机图片经过裁剪以后,更突出图像重点,明显效果更好
视网膜屏幕(retina屏幕) 清晰度解决方案
视网膜屏幕指的是屏幕的物理像素密度更高的屏幕
物理像素可以理解为屏幕上的一个发光点,无数发光的点组成的屏幕
视网膜屏幕比一般屏幕的物理像素点更小,常见有2倍和3倍的视网膜屏幕
- 2倍视网膜屏幕: 物理像素点大小是一般屏幕的1/4
- 3倍视网膜屏幕: 物理像素点大小是一般屏幕的1/9
3.2 像素密度的选择:srcset属性
window.devicePixelRatio 查看像素分辨比
为了解决上一节的这些问题,HTML 语言提供了一套完整的解决方案。首先,<img>标签 引入了srcset属性
srcset属性 用来指定多张图像,适应不同像素密度的屏幕。它的值是一个逗号分隔的字符串,每个部分都是一张图像的 URL,后面接一个空格,然后是像素密度的描述符。请看下面的例子
<img srcset="foo-320w.jpg,
foo-480w.jpg 1.5x,
foo-640w.jpg 2x"
src="foo-640w.jpg">
- srcset属性 给出了三个图像 URL,适应三种不同的像素密度
- 图像 URL 后面的像素密度描述符,格式是 像素密度倍数 + 字母x
- 1x表示单倍像素密度,可以省略
- 浏览器根据当前设备的像素密度,选择需要加载的图像
- 如果 srcset属性 都不满足条件,那么就加载 src属性 指定的默认图像
3.3. 图像大小的选择:srcset属性 + sizes属性
像素密度的适配,只适合显示区域一样大小的图像。如果希望不同尺寸的屏幕,显示不同大小的图像,srcset属性就不够用了,必须搭配sizes属性
<img srcset="foo-160.jpg 160w,
foo-320.jpg 320w,
foo-640.jpg 640w,
foo-1280.jpg 1280w"
sizes="(max-width: 440px) 100vw,
(max-width: 900px) 33vw,
254px"
src="foo-1280.jpg">
- 第一步: srcset属性列出所有可用的图像
- 上面代码中,srcset属性 列出四张可用的图像,每张图像的 URL 后面是一个空格,再加上宽度描述符
- 宽度描述符就是图像原始的宽度,加上字符w。上例的四种图片的原始宽度分别为160像素、320像素、640像素和1280像素
- 第二步: sizes属性列出不同设备的图像显示宽度
- sizes属性 的值是一个逗号分隔的字符串,除了最后一部分,前面每个部分都是一个放在括号里面的媒体查询表达式,后面是一个空格,再加上图像的显示宽度
- 上面代码中,sizes属性给出了三种屏幕条件,以及对应的图像显示宽度。宽度不超过440像素的设备,图像显示宽度为100%;宽度441像素到900像素的设备,图像显示宽度为33%;宽度900像素以上的设备,图像显示宽度为254px
- 第三步: 浏览器根据当前设备设置的宽度, 在sizes属性获得图像的显示宽度,然后从srcset属性找出最接近该宽度的图像,进行加载
- 假定当前设备的屏幕宽度是480px,浏览器从sizes属性查询得到,图片的显示宽度是33vw(即33%),等于160px。srcset属性里面,正好有宽度等于160px的图片,于是加载foo-160.jpg。
⚠️注意: sizes属性必须与srcset属性搭配使用。单独使用sizes属性是无效的
3.4
上面两节分别解决了像素密度和屏幕大小的适配,但是如果要同时适配不同像素密度、不同大小的屏幕,应该怎么办呢?
这时,就要用到 <picture>标签。它是一个容器标签,内部使用 <source>和<img>,指定不同情况下加载的图像
<!-- 设备宽度如果不超过500px,就加载竖屏的图像,否则加载横屏的图像 -->
<picture>
<source media="(max-width: 500px)" srcset="cat-vertical.jpg">
<source media="(min-width: 501px)" srcset="cat-horizontal.jpg">
<img src="cat.jpg" alt="cat">
</picture>
上面代码中,
- <source>标签 的 media属性 给出媒体查询表达式,srcset属性就是 <img>标签 的srcset属性,给出加载的图像文件。sizes属性其实这里也可以用,但由于有了media属性,就没有必要了。
- 浏览器按照 <source>标签 出现的顺序,依次判断当前设备是否满足media属性的媒体查询表达式,如果满足就加载srcset属性指定的图片文件,并且不再执行后面的<source>标签和 <img>标签
- <img>标签 是默认情况下加载的图像,用来满足上面所有 <source>标签 都不匹配的情况
下面给出一个例子,同时考虑屏幕尺寸和像素密度的适配
<picture>
<source srcset="homepage-person@desktop.png,
homepage-person@desktop-2x.png 2x"
media="(min-width: 990px)">
<source srcset="homepage-person@tablet.png,
homepage-person@tablet-2x.png 2x"
media="(min-width: 750px)">
<img srcset="homepage-person@mobile.png,
homepage-person@mobile-2x.png 2x"
alt="Shopify Merchant, Corrine Anestopoulos">
</picture>
上面代码中,标签 的 media属性 给出屏幕尺寸的适配条件,每个条件都用srcset属性,再给出两种像素密度的图像 URL
3.5 标签的type属性
除了响应式图像 <source>标签 还可以用来选择不同格式的图像。比如,如果当前浏览器支持 Webp 格式,就加载这种格式的图像,否则加载 PNG 图像
<picture>
<source type="image/svg+xml" srcset="logo.xml">
<source type="image/webp" srcset="logo.webp">
<img src="logo.png" alt="ACME Corp">
</picture>
<source>标签 的type属性给出图像的 MIME 类型,srcset是对应的图像 URL
- 浏览器按照 标签 出现的顺序,依次检查是否支持type属性指定的图像格式,如果支持就加载图像,并且不再检查后面的 标签
- 图像加载优先顺序依次为 svg 格式、webp 格式和 png 格式
3.6 处理图片缩放的方法
- 宽度设置为 auto %
- 设置最小最大宽度 min-width max-width
img { width: auto; max-width: 100%; }
3.7 使用 content 属性
::before+::after+content 属性来动态显示一些内容或者做其它很酷的事情,在 CSS3 中,任何元素都可以使用 content 属性了
<img src="image.jpg"
data-src-600px="image-600px.jpg"
data-src-800px="image-800px.jpg" alt="">
<style>
@media (min-device-width:600px) {
img[data-src-600px] {
content: attr(data-src-600px, url);
}
}
@media (min-device-width:800px) {
img[data-src-800px] {
content: attr(data-src-800px, url);
}
}
</style>
<style>
.box:after {
content: "我是一个使用*content*属性生产的静态文字";
}
div[data-line]:after {
content: "[line "attr(data-line) "]";
}
</style>
<div class="box" data-line="1" onclick="clickMethod(this)"></div>
<script>
var clickMethod = function (e) {
console.log(e,e.getAttributeNames(), document.querySelector(".box").getAttributeNames());
}
</script>
4. 其他属性
例如 pre ,iframe,video 等,都需要和img一样控制好宽度。对于table,建议不要增加 padding 属性,低分辨率下使用内容居中:
table th, table td { padding: 0 0; text-align: center; }