构建响应式布局,CSS该有的视角--CSS篇(二)
传统布局的缺陷
在网页设计中,各元素的相对位置影响着整体页面的美观。为了方便用户使用,许多产品的官网都会开发PC端和手机端。但是,传统的布局设计不足以满足市面上形形色色的电子设备,导致一个页面在不同设备上显示的效果天差地别。难道我们要为每一种不同的设备打造不同的网页吗?显然这么做是不明智的。
传统的布局采用px
作为单位描述元素的几何属性,例如长、宽、高等等。这么写在许多地方会有问题,可以看看下面的例子。
这是一个简单的天气预报例子,使用的是px
作为单位。在设备是iPhone6/7/8的情况下,页面元素的布局还算协调。但是换成iPad Pro,效果就极其拉跨。
为了解决这个布局,我们需要采用响应式布局,让页面元素的几何属性响应不同设备屏幕的几何属性。
响应式设计
在响应式设计当中,rem
和em
是重要的工具之一。在此基础上,我们还需要提供媒体查询
的手段来识别用户设备屏幕属性,以便动态设置上级元素字体大小。
一、认识rem和em
响应式布局,简单来说,就是利用父元素属性影响子元素属性的特性。采用一个弹性单位,使得我们改变根元素(通常是html标签)的某些数据就能够影响下面所有子元素的几何属性。
在响应式设计中,rem
和em
是两个重要的单位。
rem
全称是root em,用来描述子元素属性是相对于根元素字体大小。例如根元素字体大小为20px,如果某个子元素宽度为1rem,那么表示子元素宽度实际为20px。
em
表明子元素属性是相对于父元素,这常常用于父子元素之间相对属性需要严格绑定的场景。例如显示文章的场景,让文章标题和正文的字体能够根据父元素的大小自动调整。看下面一个例子:
这里的标题和段落字体大小虽然同步变化,但是字体的大小不适应屏幕的变化。这是因为我们还不能识别用户设备屏幕宽度,可以考虑CSS的媒体查询或JS实现。
既然是考虑灵活的布局方式,在适当的地方使用
%
单位也是一个明智的选择。
二、媒体查询
媒体查询是一种CSS功能,开发者可以针对不同的设备制定不同的样式规则。
基本语法
媒体查询的基本语法如下:
//参数为条件,例如max-width : 800px
@media not|only mediatype and (expressions) {
//CSS代码
}
其中mediatype可以省略,默认是为screen expression是一组表达式,用于指定媒体查询生效的条件。
示例
假设我们需要针对不同屏幕来应用不同的样式,可以这样写:
/* 默认样式 */
html {
font-size: 16px; /* 默认字体大小 */
}
/* 当屏幕宽度小于等于 600px 时 */
@media (max-width: 600px) {
html {
font-size: 14px; /* 减小字体大小 */
}
}
/* 当屏幕宽度大于等于 900px 时 */
@media (min-width: 900px) {
html {
font-size: 18px; /* 增加字体大小 */
}
}
在这个例子中,我们定义了三个场景:
- 默认情况下,字体大小 16 px
- 屏幕宽度
<=600
px 字体大小变为 14 px - 屏幕宽度
>=900
px 字体大小变为 18 px
结合rem
rem
+媒体查询是实现响应式布局的一个常用方案。一般来说,以下央视推荐放入媒体查询:
- 字体大小
- 间距
- 布局元素的高度和宽度
- 图片的宽度
- 元素的可见性
上面天气预报的例子部分样式代码长这样:
//预报框
.group{
height: 80px;
line-height: 40px;
/* rgba(245, 242, 242, 0.3) */
background-image:repeating-linear-gradient(to right,#404222,#98adad) ;
font-size: 13px;
padding: 0 10px;
margin-bottom: 10px;
border-radius: 5px;
position: relative;
opacity: 0.8;
}
也就是这个界面:
我们采用rem+媒体查询的方式改写代码后:
@media (min-width: 768px) { /* 对于较大的屏幕 */
html {
/*设置根字体大小*/
font-size: 40px;
}
.group {
height: 4rem;
line-height: 2rem;
background-image: repeating-linear-gradient(to right, #404222, #98adad);
font-size: 0.65rem;
padding: 0 0.5rem;
margin-bottom: 0.5rem;
border-radius: 0.25rem;
position: relative;
opacity: 0.8;
}
.temp {
font-size: 0.65rem;
display: block;
margin: 0;
color: rgb(255, 255, 255);
}
}
@media (max-width: 767px) { /* 对于较小的屏幕 */
html {
font-size: 20px;
}
.group {
height: 4rem;
line-height: 2rem;
background-image: repeating-linear-gradient(to right, #404222, #98adad);
font-size: 0.65rem;
padding: 0 0.5rem;
margin-bottom: 0.5rem;
border-radius: 0.25rem;
position: relative;
opacity: 0.8;
}
.temp {
font-size: 0.65rem;
display: block;
margin: 0;
color: rgb(255, 255, 255);
}
}
这里的字体大小实���为26px,如果不使用媒体查询,那么将默认所有设备都一致,采用默认字体大小16px。
在一般情况下,媒体查询中我们会写入需要响应式布局的元素属性,同时还会在全局提供一份默认样式,默认样式包含所有需要用到的样式。
媒体查询能够覆盖全局的默认样式。
在实际项目中,通常会选择一些标准的断点值来适配常见的设备尺寸,例如320px、480px、768px、1024px等。此外,为了提高代码的可维护性,还将常用的断点值定义为CSS变量或者使用预处理器(如Sass)来管理这些值。
三、JS实现响应式布局
rem+媒体查询的方式的确实是十分简单,但是对于断点的选择,也就是媒体查询的条件是一个不小的问题。如果我们想实现更具细粒度的响应式布局,那么单纯的CSS就满足不了需求。
我们需要考虑JS的方式来实现响应式布局。
具体思路:
- 获取用户设备屏幕宽度
- 按比例计算出对应根字���大小
- 使用rem编写css
可以看到这个方法也十分简单,核心就是获取用户屏幕宽度,通过比例设置根字体大小。不过既然是动态的获取,我们还需要添加DOMContentLoaded
事件。
具体代码:
//实现js读取当前用户屏幕宽度 设置根字体大小
(function(doc){
//根节点
let docEl = doc.documentElement;
//设置时机 DOM结构加载完毕
doc.addEventListener('DOMContentLoaded',recalc)
function recalc() {
//获取设备宽度 window上没有clientWidth 不带边框 offsetWidth 带边框的宽度
let width = docEl.clientWidth;
//设置docEl的字体大小
docEl.style.fontSize = 20 * (width/320) + 'px';
}
})(document)//文档对象
实现这样一个小功能十分简单,但是却可以得到十分高效完美的体验。
对于CSS部分,我们只需要在编写全局样式时使用rem作为单位即可。
lib-flexible插件
lib-flexible
插件能够解决移动端的适配问题。
1.引入
在项目的入口文件(main.js)中引入即可使用。
npm i lib-flexible --save
如果使用的是commonJS模块化,可以这样做:
require('lib-flexible/flexible')
2.原理
lib-flexible
的核心思想是基于屏幕宽度动态设置根字体的大小,通常会将字体大小设置为屏幕的1/10。
3.结合PostCSS
如果觉得直接在样式中使用rem不方便阅读,还可以考虑另一个插件系统:PostCSS。它用于处理CSS代码。我们考虑使用其内部的postcss-px-to-viewport
,这是一个将px
单位自动转换为rem
的插件。
- 安装
npm install postcss-px-to-viewport --save-dev
- 配置PostCSS 在项目的根目录创建或者修改postcss.config.js文件:
module.exports = {
plugins: {
'postcss-px-to-viewport': {
viewportWidth: 375, // 视口宽度,对应设计稿的宽度
unitPrecision: 5, // 转换后的精度,即小数点位数
viewportUnit: 'rem', // 希望转换后的单位
selectorBlackList: ['.ignore-'], // 可以忽略某些样式
minPixelValue: 1, // 小于或等于1px则不转换为rem
mediaQuery: false, // 是否在媒体查询的css代码中也转换px为rem
replace: true, // 是否转换后删除原样式
exclude: undefined, // 可以设定忽略某些文件夹下的文件,例如'node_modules'
include: undefined, // 包含某些文件夹下的文件,例如'app'
},
},
};
如此一来,我们可以按照传统编写css的方式写,利用lib-flexible+postcss,轻松实现移动端的适配。
总结
上面分享了rem+媒体查询
和JS+插件
两种实现响应式布局的方式,再来进行一次简单对比:
1.使用场景
rem
单位 + 媒体查询
需要根据设备屏幕大小调整字体大小和其他元素时。
只需要简单动态的响应式布局时。
lib-flexible
+PostCS
需要高度的动态响应式布局,如像素适配等。
大型项目,需要自动计算和换算单位。
2.优缺点
-
rem
单位 + 媒体查询-
优点:
直观且利于理解,设备的针对性强,不依赖于第三方库。
-
缺点:
断点频繁时,代码冗杂。
-
-
lib-flexible
+PostCS
-
优点:
自动化程度高,适配效果好。
-
缺点:
额外的工具学习成本,某些情况下会过度适配。
以上就是简单总结,如果你觉得本文对你有帮助,请点个赞!这将是我持续创作的动力,感谢。
-
转载自:https://juejin.cn/post/7396523906277277705