探索前端响应式设计:实现跨设备无缝体验

Responsive Design,响应式设计是一种让网站或应用能够根据访问设备的不同特性(如视窗大小、屏幕分辨率等),智能地调整布局、图片大小、交互方式以及功能的设计方法。其目标是在任何设备上都能为用户提供最佳的视觉效果和操作体验。响应式设计可以通过有条件的应用 css 规则、媒体查询、容器查询和 flexbox 布局(flex 和 grid)来完成。

一、媒体查询(Media Queries)

媒体查询(Media Queries)是 CSS3 中的一项核心特性,它允许开发人员编写针对不同设备环境和视口条件的样式规则。媒体查询通过对设备的媒体类型、特性或某些特定条件进行检测,使得 CSS 可以根据这些条件的变化动态地应用相应的样式,从而实现网页内容在不同设备上的适配和响应式布局。

1.1 移动优先设计

移动优先设计是设计和构建响应式 Web 应用程序时可以采用的原则。

1.2 设置 viewport

<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />

<!-- 智能手表 -->
<!-- <meta name="disable-adaptations" content="watch" /> -->
  • width=device-width,网页的宽度等于设备的物理宽度
  • initial-scale=1,初始缩放级别,即页面加载时的缩放比例应为 1
  • viewport-fit=cover,此属性适用于具有刘海屏或圆角屏幕的现代智能手机。设置为 cover 意味着网页内容将延伸至整个可视区域,包括可能被设备“刘海”或“下巴”遮挡的部分。这就要求网页设计时考虑到安全区域(safe area)的概念,避免重要内容被遮挡。

1.3 禁止用户人为缩放文字大小

最好限制字体最小为 16px

html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

1.4 @media

(1)媒体类型(Media Types)

  • all: 包括所有设备,此类型下的样式在任何设备上都会被应用。
  • screen: 专用于计算机显示器、平板电脑和智能手机等具有显示屏的设备。
  • print: 在打印预览或者实际打印页面时生效,应用于打印样式。
  • speech: 针对屏幕阅读器和其他基于语音的用户代理。

(2)媒体特性(Media Features) 体特性是媒体查询中用于检测设备具体特性的关键词和值对:

  • widthheight:检测视口或设备的宽度和高度。
  • device-widthdevice-height:检测物理设备屏幕本身的宽度和高度,而非浏览器视口大小。
  • orientation:检测设备的方向,取值为 portrait(竖屏)或 landscape(横屏)。
  • aspect-ratiodevice-aspect-ratio:检测设备宽高比。
  • colorcolor-indexmonochrome:关于颜色深度和灰度级的特性。
  • resolution:检测设备的分辨率或 dpi(每英寸点数)。

(3)常设宽度

  • 320px:智能手机视口的最小宽度
  • 480px:智能手机和平板电脑的大致边界
  • 768px:原始 ipad 的分辨率为 768x1024
  • 1024px:同上
  • 1280px:16:9 720p(HD)显示屏的标准宽度
@media screen and (max-width: 479px) {
  body {
    background-color: #ccc;
  }
}
@media screen and (min-width: 480px) {
  body {
    background-color: #fff;
  }
}

@media screen and (width < 480px) {
  body {
    background-color: #fff;
  }
}
@media screen and (width >= 480px) {
  body {
    background-color: #f0f0f0;
  }
}

二、Flexbox

伸缩布局,一维布局

2.1 基本概念

Flex 基本概念

  • main axis:水平主轴
  • cross axis:垂直的交叉轴
  • flex item:容器中的单元,项目
  • main size:每个项目占据的主轴空间
  • cross size:每个项目占据的交叉轴的空间

2.2 Flex 容器(父)

(1) 指定某个容器为 flex 布局

.container {
  display: flex | inline-flex;
}
  • flex:块状的
  • inline-flex:行内的
  • 设置 flex 布局,子元素的 float、clear、vertical-align 的属性将会失效。

(2) 设置在 flex 容器上的属性

  • flex-direction:决定主轴的方向(即项目的排列方向)
.container {
  /* row,主轴为水平方向,起点在左端。 */
  /* row-reverse:主轴为水平方向,起点在右端 */
  /* column:主轴为垂直方向,起点在上沿 */
  /* column-reverse:主轴为垂直方向,起点在下沿 */
  flex-direction: row | row-reverse | column | column-reverse;
}
  • flex-wrap:决定容器内项目是否可换行
.container {
  /* nowrap 不换行 */
  /* wrap:项目主轴总尺寸超出容器时换行,第一行在上方 */
  /* wrap-reverse:换行,第一行在下方 */
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • flex-flow: flex-direction 和 flex-wrap 的简写形式
.container {
  /* 默认值为: row nowrap */
  flex-flow: <flex-direction> || <flex-wrap>;
}
  • justify-content:定义项目在主轴的对齐方式
.container {
  /* flex-start 左对齐 */
  /* flex-end:右对齐 */
  /* center:居中 */
  /* space-between:两端对齐,项目之间的间隔相等,即剩余空间等分成间隙。 */
  /* space-around:每个项目两侧的间隔相等,所以项目之间的间隔比项目与边缘的间隔大一倍。 */
  justify-content: flex-start | flex-end | center | space-between | space-around;
}
  • align-items: 定义项目在交叉轴上的对齐方式
.container {
  /* 默认值为 stretch 即如果项目未设置高度或者设为 auto,将占满整个容器的高度。 */
  /* flex-start:交叉轴的起点对齐(上对齐) */
  /* flex-end:交叉轴的终点对齐 */
  /* center:交叉轴的中点对齐 */
  /* baseline: 项目的第一行文字的基线对齐 */
  align-items: flex-start | flex-end | center | baseline | stretch;
}
  • align-content:定义多根轴线的对齐方式,如果项目只有一根轴线,那么该属性将不起作用。
    • 当 flex-wrap 设置为 nowrap 时,项目不换行,容器只存在一根轴线。
    • 当 flex-wrap 设置为 wrap 时,容器可能会出现多条轴线,这时可使用align-content属性。
/* 默认值为 stretch,多条轴线平分容器的垂直方向上的空间 */
/* flex-start:轴线全部在交叉轴上的起点对齐 */
/* flex-end:轴线全部在交叉轴上的终点对齐 */
/* center:轴线全部在交叉轴上的中间对齐 */
/* space-between:轴线两端对齐,之间的间隔相等,即剩余空间等分成间隙。 */
/* space-around:每个轴线两侧的间隔相等,所以轴线之间的间隔比轴线与边缘的间隔大一倍。 */
.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

2.3 Flex 项目(子)

设置中 item 上的属性。

  • order: 定义项目在容器中的排列顺序,数值越小,排列越靠前,默认值为 0
.item {
  order: <integer>;
}
  • flex-basis:定义在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间
.item {
  /* 默认值:auto,即项目本来的大小 */
  /* 当主轴为水平方向的时候,当设置了 flex-basis,项目的宽度设置值会失效,flex-basis 需要跟 flex-grow 和 flex-shrink 配合使用才能发挥效果。 */
  flex-basis: <length> | auto;
}
  • flex-grow: 定义项目的放大比例 当所有的项目都以 flex-basis 的值进行排列后,仍有剩余空间,这时候 flex-grow 就会发挥作用。
.item {
  /* 默认值为 0,即如果存在剩余空间,也不放大 */
  flex-grow: <number>;
}
  • flex-shrink: 定义项目的缩小比例
.item {
  /* 默认值: 1,即如果空间不足,该项目将缩小,负值对该属性无效。 */
  flex-shrink: <number>;
}
  • flex: flex-grow, flex-shrink 和 flex-basis 的简写
.item {
  /* 假设三个属性同样取默认值,则 flex 的默认值是 0 1 auto。 */
  flex: none | [ < "flex-grow" > < "flex-shrink" >? || < "flex-basis" >];
}
  • align-self:允许单个项目有与其他项目不一样的对齐方式 单个项目覆盖 align-items 定义的属性
.item {
  /* 默认值为 auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch */
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

PS: flex 布局文档FLEXBOX FROGGY

三、CSS Grid

网格布局,CSS 二维布局

3.1 基本概念

  • 容器:采用网格布局的区域,container。
  • 项目:容器内部采用网格定位的子元素,item。
  • 行:容器里面的水平区域,row。
  • 列:容器里面的垂直区域,column。
  • 单元格:行和列的交叉区域,cell。
  • 网格线:划分网格的线,grid line。水平网格线划分出行,垂直网格线划分出列。

3.2 容器

(1)指定容器采用网格布局

/* 设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效。 */
div {
  display: grid | inline-grid;
}

(2)容器上的属性

1)grid-template-columnsgrid-template-rows

grid-template-columns 属性定义每一列的列宽 grid-template-rows 属性定义每一行的行高

.container {
  display: grid;
  /* 绝对值 */
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;

  /* 百分比 */
  grid-template-columns: 33.33% 33.33% 33.33%;
  grid-template-rows: 33.33% 33.33% 33.33%;

  /* repeat() */
  grid-template-columns: repeat(3, 33.33%);
  grid-template-rows: repeat(3, 33.33%);
  /* 六列 */
  grid-template-columns: repeat(2, 100px 20px 80px);

  /* auto-fill 关键字,自动填充 */
  grid-template-columns: repeat(auto-fill, 100px);
  /* 与auto-fill的行为基本是相同的。只有当容器足够宽,可以在一行容纳所有单元格,并且单元格宽度不固定的时候,才会有行为差异:auto-fill会用空格子填满剩余宽度,auto-fit则会尽量扩大单元格的宽度。 */
  grid-template-columns: repeat(auto-fit, 100px);

  /* fr 关键字(fraction 的缩写,意为"片段"),片段之间的比例关系 */
  grid-template-columns: 1fr 1fr;
  /* fr可以与绝对长度的单位结合使用 */
  grid-template-columns: 150px 1fr 2fr;

  /* minmax() */
  /* 函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。 */
  grid-template-columns: 1fr 1fr minmax(100px, 1fr);

  /* auto 关键字 */
  /* auto关键字表示由浏览器自己决定长度 */
  grid-template-columns: 100px auto 100px;

  /* 网格线的名称 */
  /* c1 c2 c3 c4 */
  grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
  grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}

2)grid-row-gap、grid-column-gap、grid-gap 设置间隔

.container {
  grid-row-gap: 20px;
  grid-column-gap: 20px;
  grid-gap: <grid-row-gap> <grid-column-gap>;
}

3)grid-template-areas 设置区域

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-template-areas:
    "a b c"
    "d e f"
    "g h i";
}

4)grid-auto-flow :放置顺序,"先行后列","先列后行"

/* row-先行后列 */
/* column-先列后行 */
.container {
  grid-auto-flow: column | row;
  /* dense 尽可能填满空格 */
  grid-auto-flow: row dense;
  grid-auto-flow: column dense;
}

5)justify-items、align-items、place-items

  • justify-items:设置单元格内容的水平位置(左中右)
  • align-items:设置单元格内容的垂直位置(上中下)
  • place-items:前面两个结合
.container {
  /* start:对齐单元格的起始边缘 */
  /* end:对齐单元格的结束边缘 */
  /* center:单元格内部居中 */
  /* stretch:拉伸,占满单元格的整个宽度(默认值) */
  justify-items: start | end | center | stretch;
  align-items: start | end | center | stretch;
  place-items: <align-items> <justify-items>;
}

6)justify-content、align-content、place-content

  • justify-content属性是整个内容区域在容器里面的水平位置(左中右)
  • align-content属性是整个内容区域的垂直位置(上中下)
  • place-content属性是 align-content 属性和 justify-content 属性的合并简写形式
.container {
  /* start - 对齐容器的起始边框 */
  /* end - 对齐容器的结束边框 */
  /* center - 容器内部居中 */
  /* stretch - 项目大小没有指定时,拉伸占据整个网格容器 */
  /* space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍 */
  /* space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔 */
  /* space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔 */
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;
  place-content: <align-content> <justify-content>;
}

7)grid-auto-columns、grid-auto-rows

  • grid-auto-columns 属性和 grid-auto-rows 属性用来设置,浏览器自动创建的多余网格的列宽和行高。
  • 写法与 grid-template-columnsgrid-template-rows 完全相同。
  • 如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。

8)grid-template、grid

  • grid-template:是 grid-template-columns、grid-template-rows 和 grid-template-areas 这三个属性的合并简写形式
  • grid:是 grid-template-rows、grid-template-columns、grid-template-areas、 grid-auto-rows、grid-auto-columns、grid-auto-flow 这六个属性的合并简写形式

3.3 项目

(1)项目属性

1)grid-column-start、grid-column-end、grid-row-start、grid-row-end

  • grid-column-start:左边框所在的垂直网格线
  • grid-column-end:右边框所在的垂直网格线
  • grid-row-start:上边框所在的水平网格线
  • grid-row-end:下边框所在的水平网格线
.item-1 {
  /* 跨两列 */
  grid-column-start: 2;
  grid-column-end: 4;
  /* span 跨多少个网格 */
  grid-column-start: span 2;
}

2)grid-column、grid-row

  • grid-column属性是 grid-column-start 和 grid-column-end 的合并简写形式
  • grid-row属性是 grid-row-start 属性和 grid-row-end 的合并简写形式
.item {
  grid-column: <start-line> / <end-line>;
  grid-row: <start-line> / <end-line>;
}
.item-1 {
  grid-column: 1 / 3;
  grid-row: 1 / 2;
}
/* 等同于 */
.item-1 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

3)grid-area

  • 指定项目放在哪一个区域
  • 还可用作 grid-row-start、grid-column-start、grid-row-end、grid-column-end 的合并简写形式
.item-1 {
  grid-area: e;
  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
  grid-area: 1 / 1 / 3 / 3;
}

4)justify-self、align-self、place-self

  • justify-self:设置单元格内容的水平位置(左中右),跟 justify-items 属性的用法完全一致,但只作用于单个项目。
  • align-self:设置单元格内容的垂直位置(上中下),跟 align-items 属性的用法完全一致,也是只作用于单个项目 - place-self:是 align-self 属性和 justify-self 属性的合并简写形式。
.item {
  /* start:对齐单元格的起始边缘 */
  /* end:对齐单元格的结束边缘 */
  /* center:单元格内部居中 */
  /* stretch:拉伸,占满单元格的整个宽度(默认值) */
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
  place-self: center center;
}

PS:网格布局GRID GARDEN

四、可伸缩矢量图形(SVG)和响应式图片

4.1 SVG

使用 SVG 替代传统位图以保持图像在各种分辨率下的清晰度。

4.2 响应式图片

结合 HTML5 的 srcset 属性和 sizes 属性,可以按需加载适合当前设备分辨率的图片资源。

<img
  srcset="
    /path/to/img-44w.png  1x,
    /path/to/img-66w.png  1.5x,
    /path/to/img-88w.png  2x,
    /path/to/img-132w.png 3x
  "
/>
.selector {
  height: 44px;
  width: 44px;
  /* 2x fallback for browsers which do not support image-set() */
  background-image: url(/path/to/img-88w.png);
  /* Safari only supports -webkit-image-set() */
  background-image: -webkit-image-set(
    url(/path/to/img-44w.png) 1x,
    url(/path/to/img-66w.png) 1.5x,
    url(/path/to/img-88w.png) 2x,
    url(/path/to/img-132w.png) 3x
  );
  /* Standard syntax */
  background-image: image-set(
    url(/path/to/img-44w.png) 1x,
    url(/path/to/img-66w.png) 1.5x,
    url(/path/to/img-88w.png) 2x,
    url(/path/to/img-132w.png) 3x
  );
}
<img
  srcset="
    /path/to/img-320w.jpg   320w,
    /path/to/img-480w.jpg   480w,
    /path/to/img-640w.jpg   640w,
    /path/to/img-960w.jpg   960w,
    /path/to/img-1280w.jpg 1280w
  "
  sizes="(min-width: 768px) 480px, 100vw"
/>

五、响应式框架与工具

Tailwind CSS、Bootstrap 等框架是基于响应式设计开发的,它们会根据屏幕宽度自动调整布局。