网站开发中,通常需要对不同的分辨率进行适配,通常有哪些实现手段呢?
工具箱
兼容性无敌的传统老三样:float、auto margin、xxx-align
响应式开发工具箱
- 单位(rem/v系)、媒体查询、设计尺寸、浮动套装、flex & grid 大法
- 栅格系统、分而治之(结构复杂,分站点开发)、css预处理、js、调试工具
扩展一:CSS 命名的两种风格:语义化 or 结构化
扩展二:呼吸感是指你这个设计无法呼吸,看着憋死了,指太紧凑了
像素
- 设备像素:不同设备物理像素各不相同
- 逻辑像素:可自行设定的,比如一个设备像素当做个逻辑像素用,反之亦然
- 设备像素密度:每英寸上拥有多少像素 pixels per inch(PPI)
- 设备像素比:devicePixelRatio = 设备像素/css像素
- 厂商和标准所做的努力
- css像素:独立设备像素,浏览器厂商获取设备像素后,根据一个关系算换出来的单位,这个关系就是设备像素比
- viewport
视口
- 理想视口:设备厂商说了算
- 布局视口:设备厂商说了算,早期为了 PC 端页面在手机端也能正常查看,通常布局视口会比理想视口大一些
- 布局视口虽然是设备定义的的,但可以通过 viewport 标签调整布局视口大小,是布局视口成为理想视口
实现等比缩放效果:flexible.js
- 根据设备的 dpr 值改变 viewport 的值
- 使用 rem 实现等比缩放
- 本质上使用用 hack 手段通过 rem 模拟 vw 特性
实践原则
- 明确断点和对应显示内容
- 大屏幕优先还是小屏幕优先
确定临界点
直接参考 Bootstrap 的设置,其规则如下
< 576px
竖屏手机>= 576px
横屏手机>= 768px
平板>= 992px
桌面>= 1200px
大屏>= 1600px
超大屏
创建 mixins
确定临界点后,就是统一团队的使用规范,答案就是使用 mixins,既能方便使用,同时还能帮助我们达到统一的目的。我们注意到 Bootstrap 是提供了 SCSS 的一系列 mixins 的,使用规则如下
@include media-breakpoint-up(xs|sm|md|lg|xl) { ... }
@include media-breakpoint-down(xs|sm|md|lg|xl) { ... }
@include media-breakpoint-between(xs|sm|md|lg|xl, xs|sm|md|lg|xl) { ... }
在 Sass 的实现原理大概如下,通过 content 关键字即可
// Mixin
@mixin responsive($maxWidth) {
@media only screen and (max-width: $maxWidth) {
@content;
}
}
// Usage
.bacon {
width: 100%;
@include responsive(450px) {
float: left;
margin-top: 10px;
}
}
那么如何在 Less 中达到类似的目的呢。需要使用到 v.1.7 提供的 rulesets
// Mixin
.responsive(@maxWidth; @rules) {
@media only screen and (max-width: @maxWidth) {
@rules();
}
}
// Usage
.bacon {
width: 100%;
.responsive(450px, {
float: left;
margin-top: 10px;
});
}
Less Mixins
确定好边界点之后,就是创建 mixin utils 啦,编写的过程中发现,xs 不好设置变量值,因为其是 < 576
的规则,因此直接翻看 Bootstrap 源码了。发现其定义如下
(xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)
现在屏幕都变大了,因此还需要加上我们的超大屏 1600 的边界点,具体的 Less 代码如下
@offset: 0.02px;
/** 竖屏手机设备 (0, 576) */
@breakpoint-xs: 0;
/** 横屏手机设备 [576, 768) */
@breakpoint-sm: 576px;
/** 平板设备 [768, 992) */
@breakpoint-md: 768px;
/** 桌面设备 [992, 1200) */
@breakpoint-lg: 992px;
/** 大屏幕设备 [1200, 1600) */
@breakpoint-xl: 1200px;
/** 超大屏幕设备 [1600, +) */
@breakpoint-xxl: 1600px;
.media-breakpoint-up(@point; @rules) {
@var: 'breakpoint-@{point}';
@media (min-width: @@var) {
@rules();
}
}
.media-breakpoint-down(@point; @rules) {
@var: 'breakpoint-@{point}';
@media (max-width: @@var - @offset) {
@rules();
}
}
.media-breakpoint-between(@lower, @upper, @rules) {
@lowerVar: 'breakpoint-@{lower}';
@upperVar: 'breakpoint-@{upper}';
@media (min-width: @@lowerVar) and (max-width: @@upperVar - @offset) {
@rules();
}
}
响应式组件
有些情况,我们并不能通过 CSS 完全搞定我们的需要,可能还是需要借助 JS 来帮助。这里可以借助社区组件 react-media
,为统一团队规范,我们再套一层,如下
import React from 'react';
import Media from 'react-media';
const GLOBAL_MEDIA_QUERIES = {
xs: '(max-width: 575.98px)',
sm: '(min-width: 576px) and (max-width: 767.98px)',
md: '(min-width: 768px) and (max-width: 991.98px)',
lg: '(min-width: 992px) and (max-width: 1199.98px)',
xl: '(min-width: 1200px) and (max-width: 1599.98px)',
xxl: '(min-width: 1600px)',
};
type Matches = {
xs: boolean;
sm: boolean;
md: boolean;
lg: boolean;
xl: boolean;
xxl: boolean;
};
interface MediaQueryProps {
render?: () => React.ReactNode;
children?: (matches: Matches) => React.ReactNode | React.ReactNode;
}
function MediaQuery({ render, children }: MediaQueryProps) {
return (
<Media render={render} queries={GLOBAL_MEDIA_QUERIES}>
{children}
</Media>
);
}
export default MediaQuery;
react-responsive 目前是更好的方案
场景总结
针对经典的布局方式,如上中下布局、顶部-侧边布局、双飞翼布局,在响应式的表现主要体现在头部导航栏、侧边栏和内容区域。
header
- 内容差异大,通过 js 渲染不同的 dom
- float: left|none
- flex-direction: column|row
siderbar
- breakpoint + collapsed
- 负 margin 或负 left
content 主要是控制列表的展示
- inline-block
- 栅格系统
- flex
- grid