[CSS] 响应式设计
响应式设计基本原则
1. 流式布局
- 页面需要适应当前视口宽度(甚至高度);
- 需要适配视口的元素,使用
%
单位(或者vh
、vw
),而不是px
; - 使用
max-width
取代width
。
2. 响应式单位
- 对于大部分长度,使用
rem
单位取代px
,可以简化整个布局的自动缩放。
3. 灵活的图像
- 默认情况下,改变视口大小的时候,图片不会自动缩放;
- 使用
%
单位设置图片的大小,并配合max-width
使用。 - 为不同尺寸的屏幕提供不同分辨率的图片。
4. 媒体查询
- 媒体查询可以在特定的视口尺寸下应用特定的CSS样式。(特定的视口尺寸成为断点)
- 媒体查询需要搭配上面三个原则才能实现响应式布局。
响应式设计策略
桌面端与移动端的优先
响应式设计有两种思路:桌面端优先和移动端优先,它们的区别是先实现一种布局,再使用媒体查询设置断点,实现不同屏幕尺寸下的布局,逐渐过渡到另一端。即由大到小和由小到大的区别。
在设置媒体查询的断点时:
-
桌面端优先:使用
max-width
;如下图,我们首先假设我们开发的桌面端网页应用宽度是大于1200px的,然后,我们开始考虑小尺寸屏幕的情况,设置
max-width: 1200px
的媒体查询,匹配所有宽度≤1200px的屏幕。进一步细化后,最终设置max-width: 900px
和max-width: 600px
。 -
移动端优先:使用
min-width
.
注:一种尺寸的屏幕可能会同时匹配上多个媒体查询中的CSS选择器,媒体查询并不会改变选择器的具体程度,因此最后的媒体查询会覆盖前面的媒体查询。
移动端优先的优缺点
优点:
- 完全针对移动用户进行了优化(移动端应用具有便捷性,市场需求量大,现代互联网的许多流量都来自于手机,属于优点);
- 移动端的设计会更注重内容,而不是纯粹的美学设计。
缺点:
- 逐步转变到桌面版本的时候,布局会显得很空洞和过于简化;
- 由于优先考虑移动端,“画板”小,创作自由度低,难以创建有区别度的产品;
- 特定领域的用户可能更关注桌面端应用而不是移动端。
断点的选择
- BAD:使用流行设备的尺寸作为断点,这种策略针对流行的设备做了最大程度的优化,但是忽略了其它设备;同时,这种策略极度依赖设备尺寸,如果设备开发商突然修改了设备尺寸,则需要大范围修改代码。
- GOOD:在互联网上查询尽可能多的设备尺寸,将他们聚集在一起,并选择中间的稀疏的尺寸作为断点。这种策略适用性广,难度适中,推荐使用。
- PERFECT:完全忽略设备的尺寸,只关注网页的内容和设计,当屏幕大小到达某个尺寸后开始崩坏,则添加断点。这种策略实现难度过大。
在Screen Resolution Stats Worldwide | Statcounter Global Stats可以查看2023年屏幕尺寸的使用量占比。
这些数据可以协助确定断点,通常需要考虑4种或5种尺寸:手机、纵向平板、横向平板、桌面端、(大型桌面端)。
下图中的断点分别是:600px,900px,1200px,1800px。
能否使用hover?
我们使用响应式设计的初衷是为了用户使用不同屏幕尺寸的设备都能获得良好的体验。但是到目前位置我们区分设备的指标只有简单的屏幕宽度。
事实上,横向平板和桌面端在大部分时候的布局都是类似的,但是它们的操作方式却截然不同,前者使用触屏,后者使用鼠标与键盘。
同时,现代UI设计者在桌面端的设计可能结合hover(鼠标悬浮)与缩放、翻转等动画,这种交互设计使得部分按钮或文本等内容在初始状态下是隐藏的,而横向平板的触屏操作却无法查看这些内容。
当然,这种情况通常发生在桌面端优先的设计策略中,并且在兼容横向平板界面时,遗漏了对于交互、页面内容的兼容。
由此可见,仅通过屏幕宽度区分设备的媒体查询是存在缺陷的,媒体查询应进一步地检查设备能否使用hover。
媒体查询 匹配能否使用hover的设备
@media (hover:none){
/* 这里匹配不能hover的设备 */
}
@media (hover:hover){
/* 这里匹配可以hover的设备 */
}
SaSS实现响应式 案例
以 桌面端优先 为例,断点选择如下:
0 - 600px
:手机600 - 900px
:平板竖向900 - 1200px
:平板横向[1200 - 1800]
:默认样式,普通桌面端1800px +
:大型桌面
使用mixin
封装一个媒体查询管理器:
@mixin respond($breakpoint){
@if $breakpoint == phone {
@media only screen and (max-width: 37.5em) { @content; } // 600px
}
@if $breakpoint == tab-port {
@media only screen and (max-width: 56.25em) { @content; } // 900px
}
@if $breakpoint == tab-land {
@media only screen and (max-width: 75em) { @content; } // 1200px
}
@if $breakpoint == big-desktop {
@media only screen and (min-width: 112.5em) { @content; } // 1800px
}
}
需要注意的是,媒体查询里的em
和rem
单位都只和浏览器默认字体大小(16px
)有关,和根节点的字体大小无关。
上面这段代码中使用em
而不是直接使用px
是因为用户可能会更改浏览器的默认字体大小,使用em
更加灵活。
only screen
使得媒体查询更加严谨,当用户打算打印页面时,这些媒体查询不应该生效。
使用:
设置根节点的字体大小,使用上面封装的mixin匹配不同的屏幕尺寸。
这里font-size
使用百分比而不是直接使用px
与上文同理(用户可能修改浏览器默认字体大小)。
html{
// This defines what 1rem is
font-size: 62.5%; // 1rem = 10px, 10/16 = 62.5%
@include respond(tab-land){ // width < 1200?
font-size: 56.25%; // 1rem = 9px, 9/16 = 56.25%
}
@include respond(tab-port){ // width < 900?
font-size: 50%; // 1rem = 8px, 8/16 = 50%
}
@include respond(big-desktop){
font-size: 75%; // 1rem = 12px, 12/16 = 75%
}
}
注:媒体查询需要注意代码顺序,应该先media(max-width: 900px)
,再media(max-width: 600px)
,这样当屏幕尺寸小于600px时,虽然两个媒体查询都能匹配到,但是更加“精细”的后者可以正确地覆盖前者。
如何实现响应式?
假设我们以桌面端优先,那么此时CSS代码都是基于桌面端屏幕尺寸的。
打开浏览器开发者工具,使用设备工具栏,拖动界面尺寸,观察到哪一个断点开始页面开始崩坏,然后着手为该部分CSS代码添加额外的代码:
需要注意由于选择桌面端优先,并且配置媒体查询的时候使用max-width
,在写不同尺寸的CSS代码的时候应注意由大到小的顺序。
如上图,先tab-port
(平板竖向)再phone
(移动端)。
响应式图像
应用场景:
- 不同尺寸的屏幕:桌面端大屏幕需要较大较清晰的图片,移动端小屏幕对清晰度要求不高且注重图片在网络传输过程中的流量消耗;
- 屏幕分辨率不同(与尺寸无关):为低分辨率屏幕(1x)和高分辨率屏幕(2x)分别准备不同的图片。
HTML实现
实现方式:
<picture class="footer__logo">
<source srcset="img/logo-green-small-1x.png 1x, img/logo-green-small-2x.png 2x"
media="(max-width: 37.5em)">
<img srcset="img/logo-green-1x.png 1x, img/logo-green-2x.png 2x" alt="Full logo"
src="img/logo-green-2x.png">
</picture>
-
首先,
source
和img
的分离可以实现匹配不同的屏幕尺寸,source
支持配置media
,与媒体查询一致,这里设置的(max-width: 37.5em)
匹配上手机的尺寸,当使用手机屏幕访问时浏览器会自动选择source
的图片,否则使用img
的图片。 -
其次,使用
srcset
可以匹配不同分辨率(像素密度)的屏幕,语法格式为:图片路径1 像素密度1, 图片路径2 像素密度2
,如上述代码,低分辨率屏幕匹配1x
标记,使用img/logo-*-1x.png
图片,高分辨率屏幕匹配2x
标记的图片,这一选择过程由浏览器自动完成。 -
另外,可以通过设置多个
source
匹配多种屏幕尺寸,但没必要,一般为手机尺寸单独设置一个source
就足够了。 -
最后,
img
需要继续设置src
,避免旧版浏览器无法正确识别srcset
属性。
CSS实现
使用媒体查询也可以匹配不同分辨率的屏幕。
@media (min-resolution: 192dpi) {
/* 这里匹配高分辨率屏幕 */
}
192dpi
是苹果视网膜屏幕的数据,每英寸屏幕192像素点,超过这个数据的屏幕则认为是高分辨率屏幕。
一般会在这里设置使用较大的图片,但是目前手机基本都是高分辨率屏幕,也会匹配到这里的大图片,不太合理。
因此,可以添加媒体查询的条件:
@media (min-resolution: 192dpi) and (min-width: 600px){
/* 这里匹配除了手机以外的高分辨率屏幕 */
}
另外,大图片不仅应用于高分辨率屏幕,低分辨率屏幕尺寸足够大时也应该使用大图片,如下:
@media (min-resolution: 192dpi) and (min-width: 600px),
(min-width: 2000px){
/* 这里匹配除了手机以外的高分辨率屏幕,或者尺寸足够大的低分辨率屏幕 */
}
考虑到min-resolution
在safari不可用,使用-webkit-min-device-pixel-ratio
:
@media (min-resolution: 192dpi) and (min-width: 37.5em),
(-webkit-min-device-pixel-ratio: 2) and (min-width: 37.5em),
(min-width: 125em){
...
}