React-native搭建

一、安装native-cli
npm install -g react-native-cli

二、初始化项目
react-native init proname

三、配置Android环境
0.jdk安装
1.下载sdk
2.ndk通过sdk tool下载,会在sdk目录新增ndk-bundle目录
3.配置环境变量(添加多个ANDROID 是因为Android studio用到)
ANDROID_HOME D:\Android\sdk(对应sdk目录)
ANDROID_SDK_HOME D:\Android\sdk
ANDROID_SDK_ROOT D:\Android\sdk
NDK_ROOT D:\Android\sdk\ndk-bundle
PATH 新增(D:\Android\sdk\tools;D:\Android\sdk\platform-tools;)

四、启动虚拟机(或者插入手机)
emulator @Nexus_6_API_23

五、运行项目
react-native run-android

六、其它操作
1.启动对应端口的服务
react-native start –host 192.168.1.5 –port 8081
2.通过adb模拟菜单按键事件(对于某些手机无响应,必须打开当前app的 桌面悬浮窗 权限)
adb shell input keyevent 82

七、常见错误处理

移动端开发-rem

对于手机开发,适配是一个非常麻烦的事情,大家一般都是是呀百分百或者缩放来做,但是这种方法还是会导致实际效果跟设计稿差别很大。
借鉴腾讯的做法,使用先计算当前尺寸对应设计稿的1像素比例,在rem来写尺寸大小。这个方法个人到现在发现是最好的一种
只需要按照图片或者容器在设计稿的尺寸来写,就能很完美的呈现
1、在head标签里引入下面代码


//全局字体rem
(function(window, document, widSize) {
'use strict';
var hotcss = {};
(function() {
var viewportEl = document.querySelector('meta[name="viewport"]'),
dpr = window.devicePixelRatio || 1,
maxWidth = 540;

dpr = dpr >= 3 ? 3 : ( dpr >=2 ? 2 : 1 );

document.documentElement.setAttribute('data-dpr', dpr);
hotcss.dpr = dpr;

document.documentElement.setAttribute('max-width', maxWidth);
hotcss.maxWidth = maxWidth;

var scale = 1 / dpr,
content = 'width=device-width, initial-scale=' + scale + ', minimum-scale=' + scale + ', maximum-scale=' + scale + ', user-scalable=no';

if (viewportEl) {
viewportEl.setAttribute('content', content);
} else {
viewportEl = document.createElement('meta');
viewportEl.setAttribute('name', 'viewport');
viewportEl.setAttribute('content', content);
document.head.appendChild(viewportEl);
}

})();
hotcss.mresize = function() {
//var innerWidth = document.documentElement.getBoundingClientRect().width || window.innerWidth;
var clientWidth = document.documentElement.clientWidth,
clientHeight = document.documentElement.clientHeight;

//横屏
clientWidth = (clientWidth>clientHeight)? clientHeight: clientWidth;
console.log(clientWidth);
////优化pc和平板体验
if (hotcss.maxWidth && (clientWidth / hotcss.dpr > hotcss.maxWidth)) {
clientWidth = hotcss.maxWidth * hotcss.dpr;
}
console.log(clientWidth);

var htmlSize = clientWidth / widSize * 100;
htmlSize = htmlSize < 50 ? 50 : htmlSize;
document.documentElement.style.fontSize = htmlSize + 'px';
};

setTimeout(function() {
hotcss.mresize();
//防止某些机型怪异现象,异步再调用一次
}, 333);
//绑定resize的时候调用
hotcss.mresize();

})(window, document, 750);


2、在css填写容器宽高时,(假设设计尺寸宽是640)直接填写图片或者设计的 尺寸值/100 + rem。(eg:图片尺寸200x100px,可以直接写width:2rem;height:1rem;)
这种方式 在不同手机下显示尺寸都是跟设计稿完美对应的,唯一需要修改的就是高度不一样,元素之间的间隔需要做修改
3、高度不一样,调整间隙可以使用媒体查询配合

js数字类型64位浮点数的换算方法

## 参考链接:https://medium.com/dailyjs/javascripts-number-type-8d59199db1b6

# 转换函数


function to64bitFloat(number) {
var i, result = "";
var dv = new DataView(new ArrayBuffer(8));

dv.setFloat64(0, number, false);

for (i = 0; i < 8; i++) { var bits = dv.getUint8(i).toString(2); if (bits.length < 8) { bits = new Array(8 - bits.length).fill('0').join("") + bits; } result += bits; } return result; } [/code] # 概念:
64位比特又可分为三个部分:

符号位S:第 1 位是正负数符号位(sign),0代表正数,1代表负数
指数位E:中间的 11 位存储指数(exponent),用来表示次方数
尾数位M:最后的 52 位是尾数(mantissa),超出的部分自动进一舍零(这个是导致大数和小数计算误差的原因);
v = (-1)^S x 2^E-1023 x (M+1);

一.假如装换43.125
整数部分43转换为二进制:101011 (通过除2求余直到商为0,再顺序倒过来)
小数部分转换为二进制:001 (通过乘2取整数部分,直到小数部分为0)
二进制为: 101011.001。科学计数法为:1.01011001*2^5;

# 通过换算的科学计数法来计算64位浮点数表示法
符号位: 0;原理:正数为0,负数为0

指数位:10000000100;计算方式就是1023+5,1028转换为二进制,不够11位,则前面补0;原理:指数位11位,则最大值是0-2^11-1(0-2047),但是科学计数法中的指数是可以为负数的,所以再减去一个中间数 1023,[0,1022]表示为负,[1024,2047] 表示为正;

尾数位:01011001...; 原理:取科学计数法的小数部分,舍去整数1,因为m位默认首部是1,所以舍去。

符号位 指数位 尾数位
0 10000000100 0101100100000000000000000000000000000000000000000000

二.假如装换0.1
整数部分0转换为二进制:0
小数部分转换为二进制:00 0110 0110... (0110无限循环)
二进制为: 0.0001100110...。科学计数法为:1.10 0110 0110...*2^-4;

# 通过换算的科学计数法来计算64位浮点数表示法
符号位: 0;原理:正数为0,负数为0

指数位:0 1111111011;计算方式就是1023+-4,1019转换为二进制,不够11位,则前面补0;原理:指数位11位,则最大值是0-2^11-1(0-2047),但是科学计数法中的指数是可以为负数的,所以再减去一个中间数 1023,[0,1022]表示为负,[1024,2047] 表示为正;

尾数位:10 0110 0110...; 原理:取科学计数法的小数部分,舍去整数1,因为m位默认首部是1,所以舍去,还原回来也要手动补1。

符号位 指数位 尾数位
0 0 1111111011 10 0110 0110...

Ubuntu 搭建 GitLab

1.首先是安装一些依赖服务

sudo apt-get install curl openssh-server ca-certificates postfix
2.官方的建议是使用脚本直接执行安装

sudo curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
sudo apt-get install gitlab-ce

3.打开/etc/gitlab/gitlab.rb,将external_url = ‘http://git.example.com’修改为自己的域名地址:http://example.com,默认为80端口,如要使用其他端口后面加上端口号,如:http://127.0.0.1:8080。

然后执行:
sudo gitlab-ctl reconfigure
启动完成后浏览器访问配置好的地址,应该出现重置管理员密码的界面。

6.检查GitLab是否安装好并且已经正确运行,输入下面的命令

sudo gitlab-ctl status
如果得到类似下面的结果,则说明GitLab运行正常

run: gitlab-workhorse: (pid 1148) 884s; run: log: (pid 1132) 884s
run: logrotate: (pid 1150) 884s; run: log: (pid 1131) 884s
run: nginx: (pid 1144) 884s; run: log: (pid 1129) 884s
run: postgresql: (pid 1147) 884s; run: log: (pid 1130) 884s
run: redis: (pid 1146) 884s; run: log: (pid 1133) 884s
run: sidekiq: (pid 1145) 884s; run: log: (pid 1128) 884s
run: unicorn: (pid 1149) 885s; run: log: (pid 1134) 885s

汉化

1.下载社区提供的汉化包,在 https://gitlab.com/xhang/gitlab/ 中找到相应的汉化分支。
sudo wget wget -cO gitlab-9.0_zh.tar.gz https://gitlab.com/xhang/gitlab/repository/archive.tar.gz?ref=9-0-stable-zh

2.解压包
sudo tar zxvf gitlab-9.0_zh.tar.gz

3.停止 GitLab 服务
sudo gitlab-ctl stop

4.备份 gitlab-rails 目录,该目录下主要是web应用部分,也是当前项目仓库的起始版本,也是汉化包要覆盖的目录。
sudo tar zcvf /opt/gitlab/embedded/service/gitlab-rails-bak.tar.gz gitlab-rails

5.将解压后的汉化补丁覆盖原来的
sudo cp -rf gitlab-9-0-stable-zh/* gitlab-rails/

6.启动服务
sudo gitlab-ctl start

7.重新执行配置命令
sudo gitlab-ctl reconfigure

汉化完成

owncloud简单的优化

1、查看回收站的文件大小
du -sh /var/www/html/files/hfhleo/files_trashbin/*

2、修改回收站保存的时间
vim /var/www/html/yunpan/config/config.php

'trashbin_retention_obligation' => 'auto,5',

2、修改版本保存的时间
vim /var/www/html/yunpan/config/config.php

'versions_retention_obligation' => 'auto,5',

使用forever设置node服务开机启动

1.新建启动脚本 nodeForever.sh 放到/etc/init.d 目录下面
touch /etc/init.d/nodeForever.sh
脚步内容:

#!/bin/sh
### BEGIN INIT INFO
# Provides: xiaoshuo
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: leo service
# Description: leo service daemon
### END INIT INFO

forever start /var/www/html/files/hfhleo/files/web/node/n1/app.js

2、设置可执行
chmod +x /etc/init.d/nodeForever.sh

3、脚本放到启动脚本中去
cd /etc/init.d
sudo update-rc.d /etc/init.d/nodeForever.sh defaults 100
语法:sudo update-rc.d defaults
是这个脚本的启动的顺序号,去这个etc文件夹下面的这几个文件夹中看看,选个合适的数字

4、关于forever的一些注意事项
开机自动启动的forever启动的node进程用forever list命令并不能查到,想要查应该用linux系统的命令
ps -ax

Promise.all实现多个同步的异步

1.创建路由,使用phantomjs抓取页面
const BookInfo = require(‘./containers/BookInfo’);

router.get('/bookInfo', async (ctx, next) => {
//var keys = escape(ctx.request.body.val);
var bid = ctx.request.query.bid;
var authorId = ctx.request.query.authorId;

let data = {};
//获取小说详细信息
let nowBook = function(){ return BookInfo.getBookinfo({
url: encodeURI(`https://book.qidian.com/info/${bid}`),
userAgent: "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
});
}
//获取小说其他书籍
let otherBook = function(){ return BookInfo.getOtherBook({
url: encodeURI(`https://my.qidian.com/author/${authorId}`),
userAgent: "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
});
}

var p1 = new Promise(function(resolve, reject) {
let ddd = BookInfo.getBookinfo({
url: encodeURI(`https://book.qidian.com/info/${bid}`),
userAgent: "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
});
resolve(ddd)
});
var p2 = new Promise(function(resolve, reject) {
let ddd = BookInfo.getOtherBook({
url: encodeURI(`https://my.qidian.com/author/${authorId}`),
userAgent: "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
});
resolve(ddd)
});
let results = await Promise.all([p1, p2]);
console.log(results)
data = results[0].result;
data.authorBooks = results[1].result;

ctx.body = {
status: 1,
data: data
}

});

2.使用phantomjs抓取

const phantom = require('phantom');

const getBookinfo = async (ops)=> {
console.log(Date.now())
let data = {};
//创建实例
let instance = await phantom.create();
//创建页面容器
let page = await instance.createPage();
//设置
page.setting("userAgent", ops.userAgent)
//判断是否访问成功
let status = await page.open(ops.url),
code = 1;
if (status !== 'success') {
//访问失败修改状态码
code = -1;
} else {
//获取当前时间
var start = Date.now();

var result = await page.evaluate(function() {
///获取最新的讨论
var commentCon = [];
$('.discuss-list li.cf').each(function(i, elem) {
var bb = $(elem).find('.discuss-info');
commentCon.push({
ico: "https:"+$(elem).find('.user-photo img').attr('src')+".png",
name: bb.find('.blue').text(),
//xin: (bb.find('.score-min').attr('class')).split('star')[1],
extend: bb.find('h5 a').text(),
time: bb.find('.info ').children('span').text()
})

});
return ({
introduce: $('.book-content-wrap .book-intro p').text(),
//评论数
comment: parseInt($('#J-discusCount').text().split("(").join("")),
/////前15条评论内容
commentCon: commentCon,
ptotal: parseInt($('#J-catalogCount').text().split("(").join(""))
})
})
data = {
status: code,
url: ops.url,
time: Date.now() - start,
result: result
}
}
//退出实例
await instance.exit();

return data;
};

const getOtherBook = async (ops)=> {
console.log(Date.now())
let data = {};
//创建实例
let instance = await phantom.create();
//创建页面容器
let page = await instance.createPage();
//设置
page.setting("userAgent", ops.userAgent)
//判断是否访问成功
let status = await page.open(ops.url),
code = 1;
if (status !== 'success') {
//访问失败修改状态码
code = -1;
} else {
//获取当前时间
var start = Date.now();
var result = await page.evaluate(function() {
return $('.author-work .author-item').map(function() {
return ({
id: $(this).find('.author-item-title a').attr('data-bid'),
workTime: $(this).find('.author-item-time').text(),
imgUrl: $(this).find('.author-item-book img').attr('src'),
name: $(this).find('.author-item-title a').text(),
introduce: $(this).find('.author-item-content').text(),
pageNumbe: $(this).find('.author-item-exp').text(),
nowPage: $(this).find('.author-item-update a').text(),
nowTime: $(this).find('.author-item-update span').text()
})
}).toArray();
})
data = {
status: code,
url: ops.url,
time: Date.now() - start,
result: result
}
}
//退出实例
await instance.exit();

return data;
};

module.exports = {
getBookinfo: getBookinfo,
getOtherBook: getOtherBook
}

常用的react native组件-react-navigation

注:个人积累,慢慢补齐

1、import StackNavigator


import {
StackNavigator,
} from 'react-navigation';

2、navigationOptions设置
在Component里面定义:


static navigationOptions = ({ navigation }) => ({
title: navigation.state.params.movie.title,
headerStyle: styles.Navigator,
titleStyle: styles.Navigator_txt,
headerTintColor: "rgba(255, 255, 255, 0.8)"
});

可以通过navigation参数获取导航切换的 this.props.navigation
参数获取: this.props.navigation.state.params.movie

3、定义screen


const Navigator_MovieList = StackNavigator({
Main: {screen: MovieList},
MovieDetail: {screen: MovieDetail}
});
export { Navigator_MovieList as default };

当前的组件StackNavigator后再导出,

4、navigate对象操作


const {navigate} = this.props.navigation;
navigate('MovieDetail', {movie: movie})

使用navigation后在props有navigation,使用navigate方法可以切换导航的页面(movie是参数)

常用的react native组件-react-native-vector-icons

1、安装react-native-vector-icons
npm install react-native-vector-icons –save

2、编辑 android/app/build.gradle


project.ext.vectoricons = [
iconFontNames: [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ] // Name of the font files you want to copy
]

apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

3、拷贝modules下面的fonts文件夹
拷贝到 android/app/src/main/assets/fonts

4、修改 android/settings.gradle
添加


rootProject.name = 'MyApp'

include ':app'

+ include ':react-native-vector-icons'
+ project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')

5、编辑 android/app/build.gradle

apply plugin: 'com.android.application'

android {
...
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
+ compile project(':react-native-vector-icons')
}

6、编辑 MainApplication.java(android/app/src/main/java/…)

package com.myapp;

+ import com.oblador.vectoricons.VectorIconsPackage;

....

@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
+ , new VectorIconsPackage()
);
}

}

7、rnpm
使用react-native link

8、使用

import Icon from 'react-native-vector-icons/FontAwesome';
const myIcon = (<Icon name="rocket" size={30} color="#900" />)

注:修改link的组件
react-native-vector-icons//字体图标

react-native-image-picker//读入照片

react-native-camera//相机

react-native-linear-gradient//颜色渐变

react-native-search-bar//search bar
react-native-tableview//原生的tableview,可以在list右侧显示索引

前端规范-css

css规范

[强制] 属性定义后必须以分号结尾。
示例:
/* good */
.selector {
margin: 0;
}

/* bad */
.selector {
margin: 0
}
[建议] 选择器的嵌套层级应不大于 3 级,位置靠后的限定条件应尽可能精确。
示例:
/* good */
#username input {}
.comment .avatar {}

/* bad */
.page .header .login #username input {}
.comment div * {}
[建议] 在可以使用缩写的情况下,尽量使用属性缩写。
示例:
/* good */
.post {
font: 12px/1.5 arial, sans-serif;
}

/* bad */
.post {
font-family: arial, sans-serif;
font-size: 12px;
line-height: 1.5;
}
[建议] 选择器的嵌套层级应不大于 3 级,位置靠后的限定条件应尽可能精确。
示例:
/* good */
#username input {}
.comment .avatar {}

/* bad */
.page .header .login #username input {}
.comment div * {}
3.2 属性缩写
[建议] 在可以使用缩写的情况下,尽量使用属性缩写。
示例:
/* good */
.post {
font: 12px/1.5 arial, sans-serif;
}

/* bad */
.post {
font-family: arial, sans-serif;
font-size: 12px;
line-height: 1.5;
}
3.4 清除浮动
[建议] 当元素需要撑起高度以包含内部的浮动元素时,通过对伪类设置 clear 或触发 BFC 的方式进行 clearfix。尽量不使用增加空标签的方式。
解释:
触发 BFC 的方式很多,常见的有:
• float 非 none
• position 非 static
• overflow 非 visible
如希望使用更小副作用的清除浮动方法,参见 A new micro clearfix hack 一文。
另需注意,对已经触发 BFC 的元素不需要再进行 clearfix。
3.5 !important
[建议] 尽量不使用 !important 声明。
[建议] 当需要强制指定样式且不允许任何场景覆盖时,通过标签内联和 !important 定义样式。
解释:
必须注意的是,仅在设计上 确实不允许任何其它场景覆盖样式 时,才使用内联的 !important 样式。通常在第三方环境的应用中使用这种方案。下面的 z-index 章节是其中一个特殊场景的典型样例。
3.6 z-index
[建议] 将 z-index 进行分层,对文档流外绝对定位元素的视觉层级关系进行管理。
解释:
同层的多个元素,如多个由用户输入触发的 Dialog,在该层级内使用相同的 z-index 或递增 z-index。
建议每层包含100个 z-index 来容纳足够的元素,如果每层元素较多,可以调整这个数值。
[建议] 在可控环境下,期望显示在最上层的元素,z-index 指定为 999999。
解释:
可控环境分成两种,一种是自身产品线环境;还有一种是可能会被其他产品线引用,但是不会被外部第三方的产品引用。
不建议取值为 2147483647。以便于自身产品线被其他产品线引用时,当遇到层级覆盖冲突的情况,留出向上调整的空间。
[建议] 在第三方环境下,期望显示在最上层的元素,通过标签内联和 !important,将 z-index 指定为 2147483647。
解释:
第三方环境对于开发者来说完全不可控。在第三方环境下的元素,为了保证元素不被其页面其他样式定义覆盖,需要采用此做法。
4.2 数值
[强制] 当数值为 0 – 1 之间的小数时,省略整数部分的 0。
示例:
/* good */
panel {
opacity: .8;
}

/* bad */
panel {
opacity: 0.8;
}
4.4 长度
[强制] 长度为 0 时须省略单位。 (也只有长度单位可省)
示例:
/* good */
body {
padding: 0 5px;
}

/* bad */
body {
padding: 0px 5px;
}
4.5 颜色
[强制] RGB颜色值必须使用十六进制记号形式 #rrggbb。不允许使用 rgb()。
解释:
带有alpha的颜色信息可以使用 rgba()。使用 rgba() 时每个逗号后必须保留一个空格。
示例:
/* good */
.success {
box-shadow: 0 0 2px rgba(0, 128, 0, .3);
border-color: #008000;
}

/* bad */
.success {
box-shadow: 0 0 2px rgba(0,128,0,.3);
border-color: rgb(0, 128, 0);
}
[强制] 颜色值可以缩写时,必须使用缩写形式。
示例:
/* good */
.success {
background-color: #aca;
}

/* bad */
.success {
background-color: #aaccaa;
}
[强制] 颜色值不允许使用命名色值。
示例:
/* good */
.success {
color: #90ee90;
}

/* bad */
.success {
color: lightgreen;
}
[建议] 颜色值中的英文字符采用小写。如不用小写也需要保证同一项目内保持大小写一致。
示例:
/* good */
.success {
background-color: #aca;
color: #90ee90;
}

/* good */
.success {
background-color: #ACA;
color: #90EE90;
}

/* bad */
.success {
background-color: #ACA;
color: #90ee90;
}
4.6 2D 位置
[强制] 必须同时给出水平和垂直方向的位置。
解释:
2D 位置初始值为 0% 0%,但在只有一个方向的值时,另一个方向的值会被解析为 center。为避免理解上的困扰,应同时给出两个方向的值。background-position属性值的定义
示例:
/* good */
body {
background-position: center top; /* 50% 0% */
}

/* bad */
body {
background-position: top; /* 50% 0% */
}
5.1 字体族
[强制] font-family 属性中的字体族名称应使用字体的英文 Family Name,其中如有空格,须放置在引号中。
解释:
所谓英文 Family Name,为字体文件的一个元数据,常见名称如下:
字体 操作系统 Family Name
宋体 (中易宋体) Windows SimSun
黑体 (中易黑体) Windows SimHei
微软雅黑 Windows Microsoft YaHei
微软正黑 Windows Microsoft JhengHei
华文黑体 Mac/iOS STHeiti
冬青黑体 Mac/iOS Hiragino Sans GB
文泉驿正黑 Linux WenQuanYi Zen Hei
文泉驿微米黑 Linux WenQuanYi Micro Hei
示例:
h1 {
font-family: “Microsoft YaHei”;
}
[强制] font-family 不区分大小写,但在同一个项目中,同样的 Family Name 大小写必须统一。
示例:
/* good */
body {
font-family: Arial, sans-serif;
}

h1 {
font-family: Arial, “Microsoft YaHei”, sans-serif;
}

/* bad */
body {
font-family: arial, sans-serif;
}

h1 {
font-family: Arial, “Microsoft YaHei”, sans-serif;
}
5.2 字号
[强制] 需要在 Windows 平台显示的中文内容,其字号应不小于 12px。
解释:
由于 Windows 的字体渲染机制,小于 12px 的文字显示效果极差、难以辨认。
5.3 字体风格
[建议] 需要在 Windows 平台显示的中文内容,不要使用除 normal 外的 font-style。其他平台也应慎用。
解释:
由于中文字体没有 italic 风格的实现,所有浏览器下都会 fallback 到 obilique 实现 (自动拟合为斜体),小字号下 (特别是 Windows 下会在小字号下使用点阵字体的情况下) 显示效果差,造成阅读困难。
5.4 字重
[强制] font-weight 属性必须使用数值方式描述。
解释:
CSS 的字重分 100 – 900 共九档,但目前受字体本身质量和浏览器的限制,实际上支持 400 和 700 两档,分别等价于关键词 normal 和 bold。
浏览器本身使用一系列启发式规则来进行匹配,在 <700 时一般匹配字体的 Regular 字重,>=700 时匹配 Bold 字重。
但已有浏览器开始支持 =600 时匹配 Semibold 字重 (见此表),故使用数值描述增加了灵活性,也更简短。
示例:
/* good */
h1 {
font-weight: 700;
}

/* bad */
h1 {
font-weight: bold;
}