开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
岁月如梭天天天,
寒来暑往年年年,
指点江山侃侃侃,
掘金文章发发发!
基础知识
什么是像素?
px - 虚拟像素,css像素的单位px是一个相对单位,相对于设备像素而言的。
相对性
- 相对于同一个设备 css像素是可变的
- 相对不同的设备,一个css像素可变
设计稿与实际屏幕的单位
1. DP
- dp - 设备像素 / 物理像素,单位是pt(1pt = 1/72(inch)
- dp是一个绝对单位,屏幕生产完成后固定不变
2. DIP
dip - 设备逻辑像素 === 虚拟像素
3. DPR
- dpr - 设备像素比初始状态下,物理像素与css像素的初始比例关系
- dpr = (设备像素 / css像素) 指的是移动开发中1个css像素具体占用了多少设备像素
4. PPI
- 每英寸像素取值(像素密度)- 衡量单个物理单位内拥有的像素
5. REM / EM - 动态相对单位
- em 是相对于父元素的字体大小,计算得出的单位rem(root em)相对于html元素的字体大小
媒体查询-media
@media mediatype key (media feature) {
// style
}
- mediatype
-
all - 所有设备
-
print - 打印预览
-
screen - 屏幕
-
speech - 语音合成器
- key
- and: 多个媒体特性之和,相当于 且
- not: 排除某个具体的媒体类型,相当于 非
- only: 当且仅当特定的查询
- media feature
- width、min-width、max-width
实际应用
- rem - 根据html的根字体大小动态变化的单位
- media - 根据设备具体宽度动态设置css的工具
- rem + media => 全响应式页面
面试题
- 假设设计稿是750px,那么html中的font-size设置为多大合适呢?
=> rem如何设置合适的比例能够还原设计稿
/* 设计稿是 750px => 屏幕分成15等份 => 每一份50px
320px的设备中 每一份大小 320 / 15 = 21.33px
640px的设备里 每一等份大小 640 / 15 = 52.67px
屏幕宽度 320px ~ 640px */
@media screen and (min-width: 320px) {
html {
font-size: 21.33px;
}
}
- 追问: 设计稿中有一个80px高度的div,css里真实高度是多少?
div高度 => rem的值 => 结合屏幕宽度得到不同的px
屏幕宽度是320px ~ 640px:21.33 * 1.6(80/50) = 35.xxxpx
屏幕宽度750px以上: 50 * 1.6 = 80px
Touch事件
- touchstart - 手指触摸屏幕的时候就会触发
多点触控,已经有一个手指在屏幕上,也会触发 - touchmove - 当手指在屏幕上滑动时候触发
他的触发也是连续的,preventDefault可以阻止
-
touchend - 手指离开屏幕上的时候触发
-
touchcancel - 取消当前操作 => 滚动取消
TouchEvent Object Attributes:
-
- isTrusted - 当前操作是否由用户操作发起 => 区分是否手拖
=> 区分主被动 - changedTouches
touchstart - 列出触摸中新增加的触点
touchmove - 列出与前一次事件比较,发生了变化的触点
touchend - 离开接触面时候的触点
=> 确定变化点 - targetTouches - 正在触摸的DOM元素上手指坐标等的列表
=> 对象处理 - touches: 跟踪触摸的当前对象
=> 对象状态
- isTrusted - 当前操作是否由用户操作发起 => 区分是否手拖
Touch Object Attributes:
-
- Touch.identifier:
标识单词触摸的一个属性,readonly - Touch.screenX | screenY | clientX | clientY | pageX | pageY | radiusX | radiusY | rotationAngle - 位置信息
- Touch.force | target - 手指 / 元素
- Touch.identifier:
常用API
- 窗口类
- orientationchange - 手机是否是横屏的状态
var scrscreenOrientation: = function() {
let self = this;
let orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
window.addEventlistener(
'onorientationchange' in window ? "onorientationchange" : "resize",
function() {
self.angle = orientation.angle;
// 样式调整
// 参数切换
}
)
}
// 竖屏
@media screen and (orientation: potrait) {
// ……
}
// 横屏
@media screen and (orientation: landscape) {
// ……
}
- navigator.language - 语言
this.lang = navigator.language;
function getThisLang() {
const langList = ['cn', 'tw', 'en', 'fr'];
const langListLen = langList.length;
const thisLang = (
navigator.language || navigator.browserLanguage
).toLowerCase();
for (let i = 0; i < langListLen; i++) {
let lang = langList[i];
if (thisLang.includes(lang)) {
return lang;
} else {
return 'en';
}
}
}
- Element.requestFullscreen() - 全屏
fullScreenFun: function() {
let self = this;
let fullscreenEnabled
= document.fullscreenEnabled
|| document.mozFullscreenEnabled
|| document.webkitFullscreenEnabled
|| document.msFullscreenEnabled
if (fullscreenEnabled) {
let de = document.documentElement;
if (self.fullScreenInfo === 'full') {
if (de.requestFullscreen) {
de.requestFullscreen();
} else if (de.mozRequestFullscreen) {
de.mozRequestFullscreen();
} else if (de.webkitRequestFullscreen) {
de.webkitRequestFullscreen();
}
self.fullScreenInfo = 'quitFull'
} else {
if (de.exitFullscreen) {
de.exitFullscreen();
} else if (de.mozExitFullscreen) {
de.mozExitFullscreen();
} else if (de.webkitExitFullscreen) {
de.webkitExitFullscreen();
}
self.fullScreenInfo = 'full'
}
} else {
// ……
}
}
- 硬件类
- navigator.getBattery() - 获取电池状态
getBatteryInfo: function() {
let self = this;
if (navigator.getBattery) {
navigator.getBattery().then(function(battery) {
self.batteryInfo
= battery.charging
? '在充电'
: '不在充电';
console.log(`剩余电量:${battery.level}%`)
battery.addEventListener('chargingchange', function() {
self.batteryInfo
= batter.charging
? '在充电'
: '不在充电';
})
})
} else {
// 不支持状态读取
}
}
- window.navigator.vibrate() - 振动
vibrateFun: function() {
let self = this;
if (navigator.vibrate) {
navigator.vibrate(200);
navigator.vibrate([200, 200, 200, 200, 200]);
} else {
// 不支持振动
}
navigator.vibrate(0);
setInterval(function() {
navigator.vibrate(200);
}, 500)
}
- navigartor.onLine - 网络状态
mounted() {
let self = this;
window.addEventListener('online', onlineChanged);
window.addEventListener('offline', offlinechanged);
},
methods: {
onlineChanged() {
// 在线时操作
},
offlinechanged() {
// 离线时操作
}
}
性能优化
图片优化
- 图片类型选择优化
-
- JPG / JPEG - 有损压缩型、体积小加载快、不支持透明
特长 - 大图片、展示色彩丰富的图片。如:轮播、banner、标题图
缺点 - 不支持透明处理、压缩有模糊 - PNG - 无损压缩、质量高、体积大、支持可透明
特长 - 色彩表现力的图片,对线条处理更细腻。如:复杂图形、logo
缺点 - 体积大 - svg - 文本文件、体积小、不失真、兼容性好
特点 - 不是基于像素点灰阶,而是基于图形的代码描述。如:icon
缺点 - 渲染成本较高,特别是复杂图形
- JPG / JPEG - 有损压缩型、体积小加载快、不支持透明
- 根据网络优化
-
- 对图片url进行预处理 xxxx/ x3 /zhaowa.png
按照质量纬度进行优化 - 弱网环境下,使用低质量图片
按照尺寸纬度进行优化 - 移动端默认加载小图片进行缩放展示
- 对图片url进行预处理 xxxx/ x3 /zhaowa.png
- 图片懒加载优化
-
- 通过data-src和src的切换,实现动态懒加载
- CDN请求数进行优化
-
- 较大体积的图片 - 直接传到CDN
单色图标iconfont、svg图片 - 放置在本地
标签类的图片较小且繁多 - 生成雪碧图之后,上传到CDN
图片体积小于10kb,结合使用场景 - base64
- 较大体积的图片 - 直接传到CDN
- 大图检测
-
- 加载图片上报告警,超过阈值做告警,更换小图片。
- 上传压缩
上传图片前,走压缩平台处理
CSS性能优化
- 选择器类型优化
// 减少使用类选择器以及id选择器去重复修饰元素标签 CSSOM layout-tree
footer #footer .footer {}
// 标签尽量一定位的方式结合标签本身的即便来做定位
- 选择器书写优化
.footer .footer-item-container .footer-item .footer-link .footer-img {
width: 100%;
}
.yy-img {
// 嵌套少
// 权重低 - 计算少,便于使用覆盖
width: 100%
}
// CSS解析的顺序是从右往左的
- 避免使用通配符
* {
padding: 0;
}
- 注释不如直接删掉
.footer {
// 移出无用样式
// width: 100%;
}
- 减少使用高级选择器,性能开销大
[class*="footer-indicator"] {}
[class~="footer-indicator"] {}
- 优化统一选择器
.footer {
display: flex;
}
.footer-item {
display: flex;
}
// =>
.flex-display {
display: flex;
}
- 优化统一属性
.footer {
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px;
margin: 10px 20px 10px 20px;
margin: 10px 20px;
background-color: #fff;
font-size: 12px;
}
- 写法优化上
-
- 避免@import引用加载CSS => scss除外
- 做动画的时候CSS3,其次再去考虑js动画
- 移动端优先考虑flex布局,减少float
写在最后
缺什么少什么或者哪里不对请各位大佬指正!