o2team / h5skills Goto Github PK
View Code? Open in Web Editor NEW移动端开发技巧集合
移动端开发技巧集合
单行文字超出省略号
.example {
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-scaple: nowrap;
}
多行文字超出省略号
.example {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; /* 指定超过2行省略号 */
text-overflow: ellipsis;
overflow: hidden;
}
<p class="gradient_txt">渐变文字渐变文字渐变文字渐变文字</p>
.gradient_txt {
background-color: #890ffa;
background-image: gradient(linear, left top, right top, from(#890ffa), to(#d80078));
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
<p class="hollow_txt">镂空文字镂空文字镂空文字镂空文字</p>
.hollow_txt {
font-size: 50px;
-webkit-text-stroke: 1px #000;
-webkit-text-fill-color: transparent;
}
flex属性是 flex-grow、flex-shrink、flex-basis 三者属性的简写,后两个属性可忽略。
默认值为 flex: 0 1 auto:
。意思为,有剩余空间也不会放大、空间不足则自动等比例缩小、此 flex 元素初始所占宽度为元素本来的宽度。
还有两个快捷值,auto(1 1 auto)和none(0 0 auto)
公式:
第一步:计算剩余空间
父容器宽度 - 所有子元素的初始宽度之和(这里子元素的初始宽度为 flex-basis 属性的值,而 flex-basis 属性的值默认为 auto,即此子元素自身的宽度)
第二步:计算每一份 flex-grow 的宽度。
上一步得到的剩余空间 /(所有子元素 flex-grow 值的和)
第三步:所有 flex-grow 值非0的子元素瓜分剩余空间
此元素放大后宽度 = 此元素原本宽度 +( flex-grow 值 * 每一份 flex-grow 的宽度)
公式:
第一步:计算超出空间
所有子元素的初始宽度之和(flex - basis 属性的值)- 父容器宽度
第二步:计算每一份 flex-shrink 宽度。
上一步得到的超出空间 / (所有子元素 flex-shrink 值的和)
第三步:各子元素分担一下压力。。
此元素缩小后宽度 = 此元素原本宽度 -( flex-shrink 值 * 每一份 flex-shrink 的宽度)
按我们 _function.scss 组件里的 %flex 的 flex: 1;
。意思为会按子元素本身大小算作子元素 flex 宽度,父元素空间有剩余则平分剩余空间来放大,父元素空间不足则平分空间缩小。
所以当所有的子元素宽度相等时,无论是1%宽度还是100%宽度或任意宽度时,经计算后呈现的效果都是一致的,平分父元素空间。
判断用户屏幕大概有这几种方法:
1、CSS Media Queries
内联样式
@media screen and (orientation:portrait) {
//竖屏
}
@media screen and (orientation:landscape) {
//横屏
}
外联样式
<!-- 竖屏 -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="..." />
<!-- 横屏 -->
<link rel="stylesheet" media="all and (orientation:landscape)" href="..." />
2、window.matchMedia()
var mql = window.matchMedia("(orientation: portrait)");
function onMatchMeidaChange(mql){
if(mql.matches) {
// 竖屏
}else {
// 横屏
}
}
onMatchMeidaChange(mql);
mql.addListener(onMatchMeidaChange);
3、window.innerHeight/window.innerWidth
function detectOrient(){
if(window.innerHeight >= window.innerWidth) {
// 竖屏
}else {
// 横屏
}
}
detectOrient();
window.addEventListener('resize',detectOrient);
4、window.orientation
switch(window.orientation) {
case 0:
displayStr += "Portrait";
break;
case -90:
displayStr += "Landscape (right, screen turned clockwise)";
break;
case 90:
displayStr += "Landscape (left, screen turned counterclockwise)";
break;
case 180:
displayStr += "Portrait (upside-down portrait)";
break;
}
function detectOrient(){
if (Math.abs(window.orientation) === 90) {
// 横屏
} else {
// 竖屏
}
}
detectOrient();
window.addEventListener('orientationchange',detectOrient);
更详细的内容请移步至:探讨判断横竖屏的最佳实现
所谓 “Sticky Footer”,指的是:如果页面内容不足够长时,页脚固定在浏览器窗口的底部;如果内容足够长时,页脚固定在页面的最底部。
总而言之,就是页脚一直处于最底,效果大致如图所示:
假设我们页面的 HTML 结构是这样:
<div class="wrapper">
<div class="content"><!-- 页面主体内容区域 --></div>
<div class="footer"><!-- 需要做到 Sticky Footer 效果的页脚 --></div>
</div>
通过绝对定位处理应该是常见的方案,只要使得页脚一直定位在主容器预留占位位置。
html, body {
height: 100%;
}
.wrapper {
position: relative;
min-height: 100%;
padding-bottom: 50px;
box-sizing: border-box;
}
.footer {
position: absolute;
bottom: 0;
height: 50px;
}
这个方案需指定 html、body 100% 的高度,且 content 的 padding-bottom 需要与 footer 的 height 一致。
通过计算函数 calc 计算(视窗高度 - 页脚高度)赋予内容区最小高度,不需要任何额外样式处理,代码量最少、最简单。
.content {
min-height: calc(100vh - 50px);
}
.footer {
height: 50px;
}
如果不需考虑 calc() 以及 vh 单位的兼容情况,这是个很理想的实现方案。
同样的问题是 footer 的高度值需要与 content 其中的计算值一致。
通过 table 属性使得页面以表格的形态呈现。
html, body {
height: 100%;
}
.wrapper {
display: table;
width: 100%;
min-height: 100%;
}
.content {
display: table-row;
height: 100%;
}
需要注意的是,使用 table 方案存在一个比较常见的样式限制,通常 margin、padding、border 等属性会不符合预期。
笔者不建议使用这个方案。当然,问题也是可以解决的:别把其他样式写在 table 上。
Flexbox 是非常适合实现这种效果的,使用 Flexbox 实现不仅不需要任何额外的元素,而且允许页脚的高度是可变的。
虽然大多数 Flexbox 布局常用于水平方向布局,但别忘了实际上它也可用于垂直布局,所以你需要做的是将垂直部分包装在一个 Flex 容器中,并选择要扩展的部分,他们将自动占用其容器中的所有可用空间。
html {
height: 100%;
}
body {
min-height: 100%;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
}
需要注意的是想要兼容各种系统设备,需要兼顾 flex 的兼容写法。
实现如图效果,标签一直跟随在文字后面。如果文字超出一行,文字裁断省略,标签保留在最右。
HTML:
<div class="jd">
<span>小米官方旗舰店</span>
<em>京东自营</em>
</div>
CSS:
.jd {
margin-right: 60px; /* 对应是标签的宽度 */
white-space: nowrap;
span, em {
display: inline-block;
vertical-align: middle;
}
span {
max-width: 100%;
/* 单行文字超出省略 */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
em {
width: 60px; /* 标签的宽度 */
}
}
X5内核最新版本支持了全屏播放视频的功能,效果如下,这是在线demo,有安卓的同学可以试试:
判断浏览器ua,如果有" TBS/036849 "字符且版本号大于036849
在video标签加上x5-video-player-type="h5"属性
<!-- 视频播放的时候会自动进入全屏状态 -->
<video id="test_video" src="xxx" x5-video-player-type="h5" x5-video-player-fullscreen="true"/>
<!-- x5-video-player-fullscreen加不加我看不出什么区别,官方文档也没有说得很详细 -->
全屏的时候会触发以下事件:
window.onresize = function(){
//do something
}
注意:弹出/收起键盘、退出全屏 的时候也会触发该事件,注意兼容
不用特别设置,在微信浏览器里打开localhost页面即可
new Date()的使用方法有:
使用new Date(time) 将时间转换成 Date 对象 ,便于与后台接口通信。注意:time格式需要为 1999/12/31 23:59 (不能为1999-12-30 23:43),否则在一些机型下可能会报错。
new Date()转换之后的数据,可以直接使用下面的api
new Date(x).getDay //获取一周中的某一天 (0 ~ 6)。
new Date(x).getMonth()+1 //获取月份
new Date(x).getDate //获取日期
new Date(x).getHours() //获取小时
new Date(x).getMinutes() //获取分钟
new Date(x).toLocaleDateString()); // 转换为本地日期格式,视环境而定,输出:2017年07月04日
new Date(x).toLocaleString()); // 转换为本地日期和时间格式,视环境而定,输出:2017年07月04日 上午10:03:05
//参数 日期
getWeek(day) {
const weekArr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
return weekArr[day];
}
getWeek(new Date(x).getDay())
etime.setHours(etime.getHours()+1, etime.getMinutes());
function getFull(n) {
return (n > 9 ? '' : '0') + n;
}
var x = getFull(3); //03
var y = getFull(11); //11
Date.prototype.Format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
调用:
var time1 = new Date().Format("yyyy-MM-dd");
var time2 = new Date().Format("yyyy-MM-dd hh:mm:ss");
在我们的传统方法中,对于这种不定宽要居中的元素,我们一般采取两层的结构,以下:
<div class="more_btn"><span>查看更多</span></div>
.more_btn {
text-align: center;
}
.more_btn span {
display: inline-block;
padding: 0 30px;
height: 40px;
line-height: 40px;
background: #4caf50;
color: #fff;
font-size: 14px;
text-align: center;
border-radius: 4px;
}
使用 width: fit-content
属性来简化结构
<div class="more_btn">查看更多</div>
.more_btn {
margin: auto;
padding: 0 30px;
width: -webkit-fit-content;
width: fit-content; /* 关键 : 宽度等于内容宽度 */
height: 40px;
line-height: 40px;
background: #4caf50;
color: #fff;
font-size: 14px;
text-align: center;
border-radius: 4px;
}
A pseudo-element is made of two colons (::) followed by the name of the pseudo-element.
This :: notation is introduced by the current document in order to establish a discrimination between pseudo-classes and pseudo-elements. For compatibility with existing style sheets, user agents must also accept the previous one-colon notation for pseudo-elements introduced in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and :after). This compatibility is not allowed for the new pseudo-elements introduced in this specification.
大概的意思是伪元素是由两个 ::
和伪元素组成的,引入两个 ::
的目的为了区分伪元素和伪类的,对于一些老旧的的项目,比如需要兼容 IE8 及以下的浏览器建议还是使用 :
,对于不需要支持低版本浏览器和移动端项目的建议使用 ::
来做区分。
::after
、::before
、::first-letter
、::first-line
、::selection
等是伪元素
:active
、:hover
、 :focus
、 :visited
、:checked
、:disabled
、:empty
等称为伪类
W3C明确表示,CSS没有版本只能等级(level)。
Cascading Style Sheets does not have versions in the traditional sense; instead it has levels. Each level of CSS builds on the previous, refining definitions and adding features. The feature set of each higher level is a superset of any lower level, and the behavior allowed for a given feature in a higher level is a subset of that allowed in the lower levels. A user agent conforming to a higher level of CSS is thus also conformant to all lower levels.
上文摘录自:https://www.w3.org/TR/2015/NOTE-css-2015-20151013/#css-levels
通常称呼 css版本 由level+revision(级别和修订号) 组合而来。例如:css 2.1,2是level号,1是修订号,表示是css2的第一个修订版本。
也就是说 1.0, 2.0 类似这样的版本号是不存在的,因为不可能有第0个修订版本。
css 1 只有一个版本: https://www.w3.org/TR/CSS1/
css第一个规范的地址:https://www.w3.org/TR/REC-CSS1-961217.html 很有意思,表格完全没有图片,像是dos时代的产品
css 2 目前有三个版本:css 2, css2.1, css2.2(css2.2是2016.04.12才出的修订版)
css 2.1 是 css 2的衍生版。
CSS 2.1 is derived from and is intended to replace CSS2.
来自:Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification
*注:css 2.2是level 2最新修订片,所以现在的主流是 2.1,关于 css 2.2 的介绍查看:https://www.w3.org/TR/CSS22/ *
css 3 只有一个版本:css 3。从css 3开始,css工作组开始引用模块化的管理方式,如下:
CSS Level 3 builds on CSS Level 2 module by module, using the CSS2.1 specification as its core. Each module adds functionality and/or replaces part of the CSS2.1 specification. The CSS Working Group intends that the new CSS modules will not contradict the CSS2.1 specification: only that they will add functionality and refine definitions. As each module is completed, it will be plugged in to the existing system of CSS2.1 plus previously-completed modules.
From this level on modules are levelled independently: for example Selectors Level 4 may well be completed before CSS Line Module Level 3. Modules with no CSS Level 2 equivalent start at Level 1; modules that update features that existed in CSS Level 2 start at Level 3.
文章摘录自:https://www.w3.org/TR/2015/NOTE-css-2015-20151013/#css
大意是:css 3的规范以独立的模块的形式存在,规范的修订以增量的存在(而不是以修订版的形式发布,潜台词是 css 3以后不会有修订版,即css 3.x永远不会存在)。
在 《css 快照2015》(即当前最新的css官方文档)的介绍里直白地说明了这点:
When the first CSS specification was published, all of CSS was contained in one document that defined CSS Level 1. CSS Level 2 was defined also by a single, multi-chapter document. However for CSS beyond Level 2, the CSS Working Group chose to adopt a modular approach, where each module defines a part of CSS, rather than to define a single monolithic specification. This breaks the specification into more manageable chunks and allows more immediate, incremental improvement to CSS.
CSS Level 4 and beyond There is no CSS Level 4. Independent modules can reach level 4 or beyond, but CSS the language no longer has levels. ("CSS Level 3" as a term is used only to differentiate it from the previous monolithic versions.)
上文摘录自:CSS Snapshot 2015
css的级别有且只有三个 css1, css2, css3。现在或以后都不可能有css4,CSS 3做为专用术语用于与之前的版本做区别。
先贴一些各种系统的默认字体数据:
ios:
ios9+中文:PingFang SC(苹方)
ios9+英文/数字:San Francisco
其他ios中文:STHeiTi(华文黑体)
其他ios英文/数字:Helvetica
mac:
10.5:华文黑体(STXihei/STHeiti)
10.6-10.10:黑体-简(Heiti SC),华文黑体的改进版;在10.6后自带了冬青黑Hiragino Sans GB,但不是默认字体
10.11:El Capitan后默认字体改为PingFang SC(苹方),英文/数字改为San Francisco
注意:电脑的字体和网页css字体没有必然关系,而且浏览器自身一般支持设定字体,贴出来仅供参考。
android:
中文:Droidsansfallback
英文/数字:Roboto(4.0+),Droid Sans(4.0以下)
顺便说一下几个字体的规律:
字体预览demo:http://jdc.jd.com/demo/font_test/index.html
由于手机系统一般只有一种中文字体,所以定义css字体时一般只要考虑英文/数字的字体。以下是我总结出来可供参考的几个字体设置:
参考样式1:
//全部ios英文&数字统一Helvetica,ios9+中文苹方,其他ios中文华文细黑,安卓默认中英文
body {
font-family: Helvetica,sans-serif;
}
参考样式2:
//ios9+中文苹方,英文/数字San Francisco,其他ios中文华文细黑,英文Helvetica,安卓默认中英文
body {
font-family: -apple-system,Helvetica,sans-serif;
}
下面的数据均在2016年5月25日采集。
站点 | 字体 | ios9+ | 其余ios | 安卓 |
---|---|---|---|---|
手机天猫 | Helvetica,sans-serif | 中文:苹方,英/数:Helvetica | 中文:华文细黑,英/数:Helvetica | 默认中英文字体 |
手机淘宝 | sans-serif | 中文:苹方,英/数:苹方 | 中文:华文细黑,英/数:华文细黑 | 默认中英文字体 |
h5微博timeline页面 | PingFang-SC-Regular,Helvetica,sans-serif | 中文:苹方,英/数:苹方 | 中文:华文细黑,英/数:Helvetica | 默认中英文字体 |
微信文章页 | -apple-system-font,"Helvetica Neue","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif | 中文:苹方,英/数:San Francisco | 中文:华文细黑,英/数:Helvetica Neue | 默认中英文字体 |
其中微信文章页因为要兼容pc和mac,所以用了比较多字体。
中文Web字体方案 z4rd/demo#3
alloyteam移动开发规范 http://alloyteam.github.io/Spirit/modules/Standard/#font
如何保证网页的字体在各平台都尽量显示为最高质量的黑体? https://www.zhihu.com/question/19911793
上周,同事反馈了一个使用 mask-border
在华为荣耀3c机子下矢效的BUG。由于本人写过关于 mask 与 mask-border 的文章: https://aotu.io/notes/2016/10/19/css3-mask/ ,并也是主张推广它的人,所以解决这个BUG是当务之急。
*注意了,本文的hack是针对 x5 内核而言 *
出问题的页面使用了我的文章里介绍的方法,但是却出现了如下BUG:
正常的显示是(ip6):
对应的关键代码如下:
.mask::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
z-index: 3;
background-color: #ff0;
pointer-events: none;
mask-border: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8AQMAAAAAMksxAAAABlBMVEUAAADxVZe4xg/eAAAAAXRSTlMAQObYZgAAAFdJREFUKM9j+H/8Pwh8YGhwYWBgYFIQwMdo/3+AgcH+nwBDi4sDA4OSEjbGf7AaoIEsYF1KDJgMuBp85rQfB6qxswPazgAGw44B9SAdAhMRccTEMjxJAACiVld1wtGnfgAAAABJRU5ErkJggg==) 18/9px stretch;
}
经过遂节点排查,居然发现当页面节点比较多的情况下 mask-border 会失效 -_-|||,这感觉是个没有办法解决的BUG。
我自己当前正好有一个年货二期的页面,今天(2016.12.26)在ip6在体验时,发现页面巨卡,但是在安卓下(华为荣耀3c)却又不卡!!!
通过定位发现是 drop-shadow
导致 iOS 下的卡顿,毕竟 drop-shadow
也是一个 filter,滤镜在 iOS 下是比较占资源的!!于是把这个 drop-shadow 去掉后解决了卡顿的BUG。
但是,我意外地发现:如果把滤镜去掉后,安卓下 mask-border 会失效。
如下:
未去滤镜之前的样子如下:
drop-shadow
是一个 filter
那么我加个 blur(0)
是不是可以解决这个BUG?
答案是肯定的!!!
不过,这个 filter: blur(0)
需要放在 mask-border 的父节点上才可以生效。基于这点,针对 低端安卓机 写一个 hack:
.mask {
filter: blur(0);
transform: translate3d(0, 0, 0);
@supports(-webkit-mask-repeat: repeat) {
// 高端安卓 与 ios 能识别
filter: none;
}
}
.mask::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
z-index: 3;
background-color: #ff0;
pointer-events: none;
mask-border: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8AQMAAAAAMksxAAAABlBMVEUAAADxVZe4xg/eAAAAAXRSTlMAQObYZgAAAFdJREFUKM9j+H/8Pwh8YGhwYWBgYFIQwMdo/3+AgcH+nwBDi4sDA4OSEjbGf7AaoIEsYF1KDJgMuBp85rQfB6qxswPazgAGw44B9SAdAhMRccTEMjxJAACiVld1wtGnfgAAAABJRU5ErkJggg==) 18/9px stretch;
}
将这段代码放到 mask-border
失效的页面,成功解决BUG。
笔者在解决BUG的过程中发现,如果 mask-border
的父节点的结构比较复杂的话,单纯使用 filter
也不能解决问题,这个时间需要现加一个 3d 加速才可以完全解决问题,所以我写的hack如下:
%mask-border-hack {
filter: blur(0);
transform: translate3d(0, 0, 0);
@supports(-webkit-mask-repeat: repeat) {
// 高端安卓 与 ios 能识别
filter: none;
}
}
上面hack生效有个前提,mask-border不能使用3d加速
由于观察的情况有限,也不能保证上面代码的 100%有效。我个人建议使用另一种比较保险的做法,就是 mask-border
放在一个单独的 div 下,这样子就可以 100% 保证上面 hack 生效。如下:
不过,我现在观察的情况有限,也不能保证上面代码的 100%有效。我个人建议使用另一种比较保险的做法,就是 mask-border
放在一个单独的 div 下,这样子就可以 100% 保证上面 hack 生效。如下:
<style>
.mask {
filter: blur(0);
transform: translate3d(0, 0, 0);
@supports(-webkit-mask-repeat: repeat) {
// 高端安卓 与 ios 能识别
filter: none;
}
}
.mask::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
z-index: 3;
background-color: #ff0;
pointer-events: none;
mask-border: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8AQMAAAAAMksxAAAABlBMVEUAAADxVZe4xg/eAAAAAXRSTlMAQObYZgAAAFdJREFUKM9j+H/8Pwh8YGhwYWBgYFIQwMdo/3+AgcH+nwBDi4sDA4OSEjbGf7AaoIEsYF1KDJgMuBp85rQfB6qxswPazgAGw44B9SAdAhMRccTEMjxJAACiVld1wtGnfgAAAABJRU5ErkJggg==) 18/9px stretch;
}
</style>
<!-- 把box的::after转移动到 mask 的 ::after 中去,再加 mask 加一个hack -->
<div class=“box”>
<div class=“mask”></div>
</div>
#探究iPhone不同显示模式device-width值变化
为了更好的大屏显示效果,苹果为 iPhone 6、iPhone 6s、iPhone 6 Plus、iPhone 7、iPhone 7 Plus 都新增了“放大显示”模式,并提示用户使用“标准”或者“放大”模式来获得更适合自己的显示效果。
通过观察我们可以发现,iPhone 6 Plus 和 iPhone 7 Plus 在放大模式下的显示内容是和 iPhone 6、iPhone 6s、iPhone 7 的标准模式一样的,这意味着 iPhone 6、iPhone 6s、iPhone 7 放大模式的内容数量,和 iPhone 5s 的显示内容是几乎一致的。
此时,设备视口宽度(device-width)、高度(device-height), 将变为与iphone 5s一致。具体,可以参照 paintcode 的信息图, 如下:
而判断iphone6plus等大屏条件手机如下:
if(window.screen.width >= 375 && window.devicePixelRatio == 3) || (window.screen.width >= 414 && window.devicePixelRatio == 3){
//此为iphone大屏手机ip6p,ip7p
}
而无法准确判断区分iphone5、iphone5s与iphone6、iphone6s。
参考资料:
利用行内块元素(inline-block)可以比较优雅地替代浮动做块平铺显示,也可以避免浮动带来的一些负面影响。如下:
.container{
width: 600px;
height: 60px;
margin: 0 auto;
font-family: -apple-system;
}
span{
display: inline-block;
width: 60px;
height: 60px;
background: #333;
color: #fff;
}
<div class="container">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span>10</span>
</div>
然而,效果并不是想像的那样:
{{:blog:2016:04:1.png?200|}}
因为字体大小不为0,造成空白节点仍然地占用一个 字符串的空间!去空格的方法有两种:
让行内块元素之间紧挨着,不留空白可以解决这个问题,如下:
<div class="container">
<span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span>
</div>
上面的方案显然不优雅。
一般情况下把container的font-size设置为0就可以解决问题了。如下:
.container{
width: 600px;
height: 60px;
margin: 0 auto;
font-size: 0;
font-family: -apple-system;
}
span{
display: inline-block;
width: 60px;
height: 60px;
background: #333;
color: #fff;
font-size: 24px;
}
{{:blog:2016:04:2.png?200|}}
一直都是使用 font-size: 0; 来做行内块无缝平铺的。最近,T4哥(姓李名伟亮号王子谥威廉I),发现需要使用font-size: 0; 在PC safari或iphone手机中不能解决无缝平铺。如下:
{{:blog:2016:04:3.png?200|}}
原因是font-family使用了 -apple-system
造成的。解决的方法有3个:
与非safari环境一样。
使用letter-spacing取负值(-4px)来对冲因为-apple-system
字体带来的空隙。如下:
.container{
width: 600px;
height: 60px;
margin: 0 auto;
font-size: 0;
font-family: -apple-system;
letter-spacing: -4px;
}
span{
display: inline-block;
width: 60px;
height: 60px;
background: #333;
color: #fff;
font-size: 24px;
letter-spacing: 0;
}
从html结构上看,保持了优雅,但是css上觉得怪怪的,letter-spacing是默认继承属性,导致容器和行内块子元素都要声明一个letter-spacing。
{{:blog:2016:04:4.png?200|}}
方法二看似很巧妙地解决了在safari下的问题。不过,抱着怀疑的精神来验证这个方案的完美性,验证的标准很简单 -- -- 无缝。
将行内块的背景做成半透明如下:
.container{
width: 600px;
height: 60px;
margin: 0 auto;
font-size: 0;
font-family: -apple-system;
letter-spacing: -4px;
}
span{
display: inline-block;
width: 60px;
height: 60px;
background: rgba(0,0,0,。3);
color: #fff;
font-size: 24px;
letter-spacing: 0;
}
在PC的safari和ip6的safari的观察结果如下:
{{:blog:2016:04:5.png?200|}}
{{:blog:2016:04:6.jpg?200|}}
很不幸地。。。。letter-spacing并不能完美解决无缝平铺的问题,边缘出现叠加了!!!
可以取巧地在container把font-family的字体改成none,然后再在行内块元素把font-family重置为 -apple-system,如下:
.container{
width: 600px;
height: 60px;
margin: 0 auto;
font-size: 0;
font-family: Helvetica;
}
span{
display: inline-block;
width: 60px;
height: 60px;
background: rgba(0,0,0,。3);
color: #fff;
font-size: 24px;
font-family: -apple-system;
}
{{:blog:2016:04:7.png?200|}}
效果上是可以完美解决,html结构上也可以保持优雅。不过css上看跟letter-spacing方案相近。
本文记于:2016/04/06 17:10
**当前(2017/07/11)主流的safari已经不存在这个问题了。这个问题只存在于 ios8.x **
移动端网页开发中,经常会涉及到一些小按钮或者小标签,比如这种:
对于一般 PC 浏览器以及 iOS 设备的浏览器表现就是我们想要的居中效果,但是大部分 Android 设备的浏览器文字都会稍微向上偏离,如下图所示:
测试表明,字体字号为奇数的两倍时(比如 10px、14px、18px、22px、26px),会出现严重偏移现象。
其实系统之间效果的差异跟我们的字体类型、系统排版引擎、浏览器都有关系,其实不影响用户浏览与操作等体验,我们可以忽略这些问题,对于一些居于使用场景偏离的比较明显的,可以使用下面提到的两种处理方案。
我们可以通过 transform: scale 来处理,比如,字体大小是 8px,我们把字体设定为 16px,然后通过 scale(0.5) 缩放至一倍大小,简单粗暴。
注意:放大两倍会使得容器被撑开占位。
结合行高、对齐的关系,结合伪元素得出的黑科技,亲测效果很理想。
.jd::before {
content: '';
display: inline-block;
vertical-align: middle;
width: 0;
height: 100%;
margin-top: 1px;
}
年货 SNS 在做弹幕的时候发现,在ip6下,弹幕有时候会不做去动画(animation),如下:
概率大概是 50%,前一步测试会发现 mac 下的 safari 也会有这个BUG。其实这个BUG由来已久了,只是一直没遇到过,所以有点好奇它出现的原因。
弹幕是用 js 动态生成并插入页面的,如下:
所以,我猜想:是不是由于 js 在页面加载未完成前插入 DOM 节点造成的BUG。于是把js插入的代码直接插到 DOM上:
测试发现ip6明显好转但却仍然会有一点点的BUG:
但是却意外发现 mac 下的 safari 情况在变糟糕:弹幕动效失效的概率超过7成。也就是当前的猜想是错的。
弹幕动画是在页面载入时就有了,而页面在载入的时候比较耗性能,于是我猜想:页面载入完成后再使用弹幕动画可以解决BUG
页面载入有两个事件:window.load 与 DOMContentLoaded,对两个都进行测试:
DOMContentLoaded:
"interactive" == document.readyState ? showBullet(bulletData) : document.addEventListener("DOMContentLoaded", function() {
showBullet(bulletData); // 显示弹幕
});
window.load:
"complete" == document.readyState ? showBullet(bulletData) : window.addEventListener("load", function() {
showBullet(bulletData); // 显示弹幕
});
测试的结果是使用 DOMContentLoaded 不能解决弹幕BUG,而 window.onload 可以完美解决弹幕的BUG。也不是说猜想2是靠谱的!
在确保页面加载完成后再开启弹幕动画:
window.load:
"complete" == document.readyState ? showBullet(bulletData) : window.addEventListener("load", function() {
showBullet(bulletData); // 显示弹幕
});
什么情况才会出现:2个或多个毗邻的的普通流中的块元素垂直方向上的 margin 会折叠
如何解决margin叠加问题?
日常开发出现情况
有些时候会出现上面一些感觉比较诡异的事情,子元素明明设置了margin值,但是却没有撑开父元素,此时只要给父元素设置overflow:hidden;或者触发BFC即可。
看图更容易理解:
在微信中使用 <input type="file" multiple accept="image/*">
传入照片后,绘制到 Canvas 中时会发现绘制的图像方向不对(手 Q 端貌似不会存在这个问题),这时需要使用 exif.js 来解决。
Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。
<input class="uploadBtn" type="file" multiple accept="image/*">
document.querySelector(".uploadBtn").addEventListener("change", previewImgFile, false);
function previewImgFile() {
var _files = files || event.target.files;
var _index = index || 0;
var reader = new FileReader();
reader.onload = function(event) {
var image = new Image();
image.src = event.target.result;
var orientation;
image.onload = function() {
EXIF.getData(image, function() { // 获取图像的数据
EXIF.getAllTags(this); // 获取图像的全部数据,值以对象的方式返回
orientation = EXIF.getTag(this, "Orientation"); // 获取图像的拍摄方向
var rotateCanvas = document.createElement("canvas"),
rotateCtx = rotateCanvas.getContext("2d");
// 针对图像方向进行处理
switch (orientation) {
case 1 :
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.drawImage(image, 0, 0, image.width, image.height);
break;
case 6 : // 顺时针 90 度
rotateCanvas.width = image.height;
rotateCanvas.height = image.width;
rotateCtx.translate(0, 0);
rotateCtx.rotate(90 * Math.PI / 180);
rotateCtx.drawImage(image, 0, -image.height, image.width, image.height);
break;
case 8 :
rotateCanvas.width = image.height;
rotateCanvas.height = image.width;
rotateCtx.translate(0, 0);
rotateCtx.rotate(-90 * Math.PI / 180);
rotateCtx.drawImage(image, -image.width, 0, image.width, image.height);
break;
case 3 : // 180 度
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.translate(0, 0);
rotateCtx.rotate(Math.PI);
rotateCtx.drawImage(image, -image.width, -image.height, image.width, image.height);
break;
default :
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.drawImage(image, 0, 0, image.width, image.height);
}
var rotateBase64 = rotateCanvas.toDataURL("image/jpeg", 0.5);
});
}
}
reader.readAsDataURL(_files[_index]);
}
1、图片模糊
默认生成的 Canvas 是 1 倍图,在移动端 Retina 屏幕下显示模糊,可以通过 2 倍图的方式解决:
var stageWidth = $(".stage").width(),
stageHeight = $(".stage").height();
var retinaCanvas = document.createElement("canvas");
retinaCanvas.width = stageWidth * 2;
retinaCanvas.height = stageHeight * 2;
retinaCanvas.style.width = stageWidth + "px";
retinaCanvas.style.height = stageHeight + "px";
var ctx = retinaCanvas.getContext("2d");
ctx.scale(2, 2);
html2canvas(document.querySelector(".stage"), {
canvas: retinaCanvas,
onrendered: function(canvas) {
var base64 = canvas.toDataURL(); // 返回 base64
}
});
2、图片偏移
html2canvas 是解析 DOM 元素实际的样式来生成图片,如果对元素位置进行调整,例如设置了 top
、left
或者 margin-top
、margin-left
的样式会导致生成的图片偏移。
ctx.transform(-x, -y); // 计算一下偏移的值,通过 transform 方法来修正回去
3、ICON 模糊
即使是使用了 2 倍图,生成后的图片里的 ICON 还是模糊,可以用 SVG 的方式去代替图片 ICON。
4、不支持设置 border-radius 的元素
如果你需要在一个头像中设置 border-radius: 50%
在转为图片后,你会发现并不成功,解决方法在源码 html2canvas.js
中加入以下代码:
tlh = borderRadius[0][0],
tlv = borderRadius[0][1],
trh = borderRadius[1][0],
trv = borderRadius[1][1],
brh = borderRadius[2][0],
brv = borderRadius[2][1],
blh = borderRadius[3][0],
blv = borderRadius[3][1];
/* S 插入这段代码 */
var halfHeight = Math.floor(height / 2);
tlh = tlh > halfHeight ? halfHeight : tlh;
tlv = tlv > halfHeight ? halfHeight : tlv;
trh = trh > halfHeight ? halfHeight : trh;
trv = trv > halfHeight ? halfHeight : trv;
brh = brh > halfHeight ? halfHeight : brh;
brv = brv > halfHeight ? halfHeight : brv;
blh = blh > halfHeight ? halfHeight : blh;
blv = blv > halfHeight ? halfHeight : blv;
/* E 插入这段代码 */
var topWidth = width - trh,
rightHeight = height - brv,
bottomWidth = width - brh,
leftHeight = height - blv;
我们可以使用正切Math.tan()
操作将角度转变为斜率,那么怎样利用斜率来转换为角度呢?可以利用斜率的反正切函数将它转换为相应的角度。Math.atan()
和Math.atan2()
两个函数可以计算反正切,接下来分析一下具体用法:
Math.atan()接受一个参数:用法如下:
angel = Math.atan(slope) //slope值计算为y/x (斜率比值无法判断 y、x方向,如-1/-1, 1/-1等情况)
//angel为一个角度的弧度值,`slope`为直线的斜率,是一个数字,这个数字可以是负的无穷大到正无穷大之间的任何一个值(tan的取值范围)
不过,利用它进行计算比较复杂。因为它的周期性,一个数字的反正切值不止一个。例如atan(-1)的值可能是45度,也可能是225度。这样就是它的周期性,对于正切函数来说,它的周期是180度,所以两个相差180度的角具有相同的正切和斜率:
tanθ=tan(θ+180)
然而,Math.atan()
只能返回一个角度值,因此确定它的角度非常的复杂,而且,90度和270度的正切是无穷大,因为除数为零,我们也是比较难以处理的,因此我们更多的会采用第二个函数Math.atan2()
进行处理。
Math.atan2()接受两个参数x和y,方法如下:
angel=Math.atan2(y,x)
// x 指定点的 x 坐标的数字。
// y 指定点的 y 坐标的数字。
计算出来的结果angel是一个弧度值,也可以表示相对直角三角形对角的角,其中 x 是临边边长,而 y 是对边边长。
//输入弧度值,return 角度值
function trace(x){
//弧度=角度*Math.PI/180
return 180*x/Math.PI
}
测试如下:
①对比一
x=Math.atan(1)//计算正切值为1的数字对应的弧度值,输出弧度值0.785398163397448 (当斜率值为-7/-7或7/7)
trace(x) //输出45
x=Math.atan2(7,7) //输出弧度值 0.785398163397448
trace(x) //输出45
②对比二
x=Math.atan2(7,-7) //输出弧度值 2.35619449019234
trace(x) //转换为角度值 135
x=Math.atan2(-7,7) //输出弧度值 -0.785398163397448
trace(x) //转换为角度值输出-45
x=Math.atan2(-7,-7) //输出弧度值 -2.35619449019234
trace(x) //转换为角度值输出-135
从这些测试可以看出,通过坐标系的自动调整,可以很自由的计算出处于不同象限的位置相对应的角度.
Math.atan2()
函数返回点(x,y)和原点(0,0)之间直线的倾斜角,那么如何计算任意两点间直线的倾斜角呢?
其实只需要将两点x、y坐标分别相减得到一个新的点(x2-x1,y2-y1),然后利用它求出角度就可以了。使用下面的一个转换可以实现计算出两点间连线的夹角:
//输入弧度值,return 角度值
function trace(x){
//弧度=角度*Math.PI/180
return 180*x/Math.PI
}
var x = Math.atan2(y2-y1,x2-x1); //得到弧度值
trace(x) //获取角度值
具体实例例子:
//测试,计算点(3,3)和(5,5)构成的连线的夹角
x=Math.atan2(5-3,5-3) //输出弧度值 0.785398163397448
trace(x) //输出角度值 45
参考资料:
常规我们写一个导航,每个导航间都有空隙(除了最后一个),以下:
<div class="nav">
<a href="#">首页</a>
<a href="#">购物圈</a>
<a href="#">个人中心</a>
</div>
.nav a {
margin-right: 10px;
}
.nav a:last-child {
margin-right: 0;
}
这一点都不优雅!使用 not
来简化样式
.nav a:not(:last-child) { /* 除了最后一个 */
margin-right: 10px;
}
常见商品组占位图情况:
.cover {
position: relative;
height: 0;
overflow: hidden;
padding-top: 100%;
img {
display: block;
width: 100%;
height: auto;
position: absolute;
top: 0;
left: 0;
}
}
如果是其他比例的商品图与容器比例不符,可以这样处理:
.cover {
position: relative;
height: 0;
overflow: hidden;
padding-top: 100%;
img {
display: block;
position: absolute;
top: 50%;
left: 50%;
max-width: 100%;
max-height: 100%;
transform: translate(-50%,-50%);
}
}
如果商品图需要完全铺满,可以进一步这样处理:
需要配合脚本判断图片宽高,宽大于高时使用类名 .full_h
,高大于宽时使用类名 .full_w
.cover {
position: relative;
height: 0;
overflow: hidden;
padding-top: 100%;
img {
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
&.full_w {width: 100%;}
&.full_h {height: 100%;}
}
}
抛开兼容问题,我们还有一个更适合的属性 object-fit,可以这样处理:
.cover {
position: relative;
height: 0;
overflow: hidden;
padding-top: 100%;
img {
display: block;
position: absolute;
top: 0;
left: 0;
object-fit: contain 或 cover;
}
}
object-fit 兼容表:
在 Git 中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件的方法(如无,则需自己手工建立此文件)。这个文件每一行保存了一个匹配的规则例如:
# 此为注释 – 将被 Git 忽略
*.a # 忽略所有 .a 结尾的文件
!lib.a # 但 lib.a 除外
/TODO # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
build/ # 忽略 build/ 目录下的所有文件
doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
规则很简单,不做过多解释,但是有时候在项目开发过程中,突然心血来潮想把某些目录或文件加入忽略规则,按照上述方法定义后发现并未生效,原因是 .gitignore 只能忽略那些原来没有被 track 的文件,如果某些文件已经被纳入了版本管理中,则修改 .gitignore 是无效的。那么解决方法就是先把本地缓存删除(改变成未 track 状态),然后再提交:
git rm -r --cached .
git add .
git commit -m 'update .gitignore'
转自 梧桐树下 » Git忽略规则及.gitignore规则不生效的解决办法
fixed在某些情况下可能导致容器内的子元素的1px边框线消失,即使使用z-index也无法解决。
解决方法:可以使用translateZ属性来解决
fixed定位的容器内不能带有input,这是常见的bug。
解决方法: 在input聚焦的时候去掉fixed定位状态,改为absolute。
fixed+可滚动的容器内会导致fixed定位的子元素在滚动时定位失效,滚动完成后才正常回到fixed的位置。
解决方法:尽量不要在可滚动的容器内包含fixed定位的子元素。
为了减少翻资料的时间成本,在这里整理一下日常中需要处理的各种特殊字体。
text-shadow: 0 0 0, 0 0 2px;
background: -webkit-gradient(linear, left top, right top, from(#890ffa), to(#d80078));
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: #ffe799;
text-shadow: 0 1px 0px #987400;
text-shadow: #000 2px 0 0, #000 0 2px 0, #000 -1px 0 0, #000 -1px -1px 0;
可以自己调整里面的属性,实现相同的效果~
前段时间研究svg压缩处理优化,针对文本html、xml文件解析成DOM文档对象,一直困扰着我。那么,今天讲讲借助htmlparser2、sax-js、xmldom 解析HTML/XML。
htmlparser2可以用来处理HTML / XML / RSS的解析器,可以接收流文件,并提供回调接口。cheerio底层就是用此原理。
npm install htmlparser2
//解析
var htmlparser = require("htmlparser2");
var parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if(name === "script" && attribs.type === "text/javascript"){
console.log("JS! Hooray!");
}
},
ontext: function(text){
console.log("-->", text);
},
onclosetag: function(tagname){
if(tagname === "script"){
console.log("That's it?!");
}
}
}, {decodeEntities: true});
parser.write("Xyz <script type='text/javascript'>var foo = '<<bar>>';</ script>");
parser.end();
//生成简单的文档对象
var htmlparser = require("htmlparser2");
var rawHtml = "Xyz <script language= javascript>var foo = '<<bar>>';< / script><!--<!-- Waah! -- -->";
var handler = new htmlparser.DomHandler(function (error, dom) {
if (error){
throw new error()
}else{
console.log(dom);
}
});
var parser = new htmlparser.Parser(handler);
parser.write(rawHtml);
parser.done();
监听处理键值对象函数,仅对有效的键值进行处理,否则中断。
解析数据块,触发相应的回调函数
解析buffer数据和清除堆栈结束,触发 onend 回调函数。
重置buffer以及stack,触发 onreset 函数
重置解析器解析数据,触发调用 end。
表示是否是特殊标签<script>
和<style>
应该得到特殊处理, 如果是空"empty" 的标签(如< br >)含有子元素。如果没有特殊处理,则特殊标签将做文本处理。
解析其它XML内容(不包含HTML文件), 设置为true。默认值:false。
设置为true,文档中内容实体部分将解码。默认值为false。
设置为true,所有标签将小写展示。xmlMode不设置情况下,默认值为true。
设置为true,所以属性name将设置为小写。由于影响解析速度,默认值为false。
设置为true,CDATA区域将被认为文本,即使xmlMode选项不启用。注意,xmlMode被设置为true,那么CDATA节总是会被认为是文本。
设置为true,其关闭标签将触发 onclosetag 事件即使xmlMode没有设置为true。注意: xmlMode设置为true,那么自闭标签总是被认可。
htmlparser2主要是提供了对HTML / XML / RSS的解析,效率比较高,而相应生成简单的文档对象,需要借助domhandler模块,只是增加了DOM level 1不便于操作。
sax-style风格处理XML和HTML的解析器,sax js。
npm install sax-js
var sax = require("./lib/sax"),
strict = true, // set to false for html-mode
parser = sax.parser(strict);
parser.onerror = function (e) {
// an error happened.
};
parser.ontext = function (t) {
// got some text. t is the string of text.
};
parser.onopentag = function (node) {
// opened a tag. node has "name" and "attributes"
};
parser.onattribute = function (attr) {
// an attribute. attr has "name" and "value"
};
parser.onend = function () {
// parser stream is done, and ready to have more stuff written to it.
};
parser.write('<xml>Hello, <who name="world">world</who>!</xml>').close();
// stream usage
// takes the same options as the parser
var saxStream = require("sax").createStream(strict, options)
saxStream.on("error", function (e) {
// unhandled errors will throw, since this is a proper node
// event emitter.
console.error("error!", e)
// clear the error
this._parser.error = null
this._parser.resume()
})
saxStream.on("opentag", function (node) {
// same object as above
})
// pipe is supported, and it's readable/writable
// same chunks coming in also go out.
fs.createReadStream("file.xml")
.pipe(saxStream)
.pipe(fs.createWriteStream("file-copy.xml"))
由于sax-js解析的许多方法基本与htmlparser2一致,只是解析效率上比htmlparser2稍差。
XMLDOM是一款非常强大的解析工具,可实现浏览使用的 javascript文档对象模型 (W3C DOM) 。完美兼容DOM Level 2 以及部分 DOM Level 3。支持支持DOMParser和XMLSerializer接口浏览。解析为文档对象
参考资料:
创建和导出SVG的技巧
SVG 导出与优化
npm install xmldom
var DOMParser = require('xmldom').DOMParser;
var doc = new DOMParser().parseFromString(
'<xml xmlns="a" xmlns:c="./lite">\n'+
'\t<child>test</child>\n'+
'\t<child></child>\n'+
'\t<child/>\n'+
'</xml>'
,'text/xml');
//doc相当于document,doc.documentElement相当于document.documentElement
doc.documentElement.setAttribute('x','y');
doc.documentElement.setAttributeNS('./lite','c:x','y2');
var nsAttr = doc.documentElement.getAttributeNS('./lite','x')
console.info(nsAttr)
console.info(doc)
parseFromString(xmlsource,mimeType)
options extension by xmldom(not BOM standard!!)
//added the options argument
new DOMParser(options)
//errorHandler is supported
new DOMParser({
/**
* locator is always need for error position info
*/
locator:{},
/**
* you can override the errorHandler for xml parser
* @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
*/
errorHandler:{warning:function(w){console.warn(w)},error:callback,fatalError:callback}
//only callback model
//errorHandler:function(level,msg){console.log(level,msg)}
})
XMLSerializer 可以将DOM subtree 和 DOM document转换为文本
serializeToString(node)
attribute:
nodeValue|prefix
readonly attribute:
nodeName|nodeType|parentNode|childNodes|firstChild|lastChild|previousSibling|nextSibling|attributes|ownerDocument|namespaceURI|localName
method:
insertBefore(newChild, refChild)
replaceChild(newChild, oldChild)
removeChild(oldChild)
appendChild(newChild)
hasChildNodes()
cloneNode(deep)
normalize()
isSupported(feature, version)
hasAttributes()
method:
hasFeature(feature, version)
createDocumentType(qualifiedName, publicId, systemId)
createDocument(namespaceURI, qualifiedName, doctype)
参考资料:
在制作全屏视频需求时,你会发现 iOS、Android 在这一块多多少少都存在一些问题。
iOS
iOS 通过 webkit-playsinline
、playsinline
实现内嵌全屏,不调用系统全屏,有必要的情况下配合 iphone-inline-video 库使用。
<video src="video.mp4" webkit-playsinline playsinline></video>
/* 隐藏 iOS 视频的播放暂停按钮 */
video::-webkit-media-controls-play-button,
video::-webkit-media-controls-start-playback-button {
opacity: 0;
pointer-events: none;
width: 5px;
}
Android
Android 除非你的域名下微信的白名单,否则你会面临两种选择:
1、使用 X5 自建播放器
2、隐藏导航条的全屏视频
自建播放器就跟废的没两样,全屏偶尔还能用上,通过 x5-video-player-type="h5"
、x5-video-player-fullscreen="true"
可视频全屏,同时顶部的微信标题条也会消失,视频内会有一个全屏的 icon 按钮,退出全屏会使视频暂停
<video src="video.mp4" x5-video-player-type="h5" x5-video-player-fullscreen="true"></video>
最近在一次需要计算关注天数时,发现在 Safari 浏览器使用 new Date() 时出现 NAN 的情况
接口返回的时间格式数据是:"2017-06-11 13:50:30"
let time = '2017-06-11 13:50:30';
Date.parse(new Date(time)); // Safari 下返回 NaN
Date.parse(new Date(time)); // Chrome 下正常返回 1507687810000
问题就出在 Safari 对于这个格式 YYYY-MM-DD HH:MM:SS
无法解析,所以我们需要做的是将其转化为 YYYY/MM/DD HH:MM:SS
let time = '2017-06-11 13:50:30';
Date.parse(new Date(time.replace(/-/g, '/'))); // Safari 下正常返回 1507687810000
.example::-webkit-scrollbar {
width: 0;
height:0;
display: none;
}
但是!
该方法在 iOS 版微信升级到 WKWebView 后有很大的概率无法隐藏滚动条,在旧的 UIWebView 中不存在此问题。
iOS 微信 6.5.3 版本开始支持手动切换 WKWebView 和 UIWebView 的办法:
点击微信会话列表页点击右上角 +
号按钮,选择菜单中的 添加朋友
,在添加朋友界面的搜索框中输入字符串::switchweb
,再点击键盘右下角搜索按钮。切换成功后会提示当前使用的内核是 UIWebview 或是 WKWebview。
校验切换方法:
通过命令成功切换到 WKWebview 后,可通过以下方法验证当前网页使用的是否是 WKWebview 内核。
微信内任意入口进入任意网页,在网页加载成功后向下拉动页面(或点击网页右上角菜单按钮),使之显示出地址栏,当地址栏以 此网页由
开头即为当前使用WKWebview,若以 网页由
则是使用的UIWebview。
svg 中可以控制文本沿指定路径显示,只需要 标签就可以完成。以下是一个实例:
<svg viewBox="0,0,332,48">
<path id="textPath" d="m0.749997,39.860256c92.99817,20.99958 250.99507,-15.99969 327.99356,1.99996" opacity="0.5" stroke-opacity="null" stroke-width="1" stroke=“#000" fill="none"/>
<text fill="#fff" font-size="28" x="0" y="0">
<textPath xlink:href="#textPath">
利益点利益点利益点
</textPath>
</text>
</svg>
有时候,我们需要将文本沿着svg中心点居中。 标签的属性如下:
属性名称 | 属性说明 |
---|---|
x | 起始点 x 轴的座标 |
y | 起始点 y 轴的座标 |
dx | 座标的 x 轴偏移位置 |
dy | 座标的 y 轴偏移位置 |
rotate | 旋转偏移的角度 |
textLength | 元素的长度,这会影响输出的宽度 |
transform | 文字的变形效果,类似 css 中的 transform |
可以使用 x,dx 来定位中心点。但是,却会发现这样做不是文本居中,而是文本从中间开始:
<svg viewBox="0,0,332,48">
<path id="textPath" d="m0.749997,39.860256c92.99817,20.99958 250.99507,-15.99969 327.99356,1.99996" opacity="0.5" stroke-opacity="null" stroke-width="1" stroke=“#000" fill="none"/>
<text fill="#fff" font-size="28" x=“50%" y="0">
<textPath xlink:href="#textPath">
利益点利益点利益点
</textPath>
</text>
</svg>
查阅了一下资料,在这篇文章 http://blog.csdn.net/salmonellavaccine/article/details/43041981 ,看到可以使用 的 text-anchor 和 startOffset 来实现居中的效果。
text-anchor: 文本相对于起始点的对齐方式。使用 middle 是居中。
startOffset: 离起始点的相对位置。
<svg viewBox="0,0,332,48">
<path id="textPath" d="m0.749997,39.860256c92.99817,20.99958 250.99507,-15.99969 327.99356,1.99996" opacity="0.5" stroke-opacity="null" stroke-width="1" stroke=“#000" fill="none"/>
<text fill="#fff" font-size="28">
<textPath xlink:href=“#textPath" text-anchor="middle" startOffset="50%">
利益点利益点利益点
</textPath>
</text>
</svg>
一个有意思的地方:text-anchor 也是 的属性。也就是说, 使用 text-anchor="middle” 和 dx/x = “50%” 也可以实现居中。
有一些通用的样式和函数方法,我们在每个项目里都会用到,但麻烦的是每个项目都要单独把相关的库文件引用进项目,非常不方便,而且文件也比较冗余。终于发现了引用全局变量的方法。
compass watch --import-path D://sass//lib
compass命令带 –import-path 即可添加全局引用库。
sass --update --load-path D://sass//lib
sass命令带 –load-path 即可添加全局引用库。 如果你修改随意修改库文件,可能会对之前的项目造成影响,修改全局库文件时应当谨慎,最好在单独的项目类,重写需要修改的方法。
参考:张鑫旭的《深入理解 CSS 中的层叠上下文和层叠顺序》
元素发生层叠时,一套垂直显示顺序规则。
同一个层叠上下文中:
正 z-index
非 static 定位元素、不依赖 z-index 的层叠上下文元素
inline、inline-block 行内盒
float 盒子
block 块盒
负 z-index
层叠上下文的 background、border
每个元素都有。
层叠上下文元素的层叠水平由其 z-index 确定,相同则后者层叠水平更高。
层叠水平的比较只有在当前层叠上下文元素中才有意义。
总的来说,
同一个层叠上下文,看层叠顺序,层叠顺序一样,则后来者位于上。
不同的层叠上下文,看所在的层叠上下文元素的层叠顺序与层叠水平。
<html>
z-index 为数值(包括0)的非 fixed 定位元素
其他
父元素 display: flex;
或 display: inline-flex;
,同时子元素(必须为直系子元素)的 z-index 不为auto。这时,这个子元素成为层叠上下文元素。
opacity 的值不为1的元素会自动成为层叠上下文元素。
带有 transform 属性的元素会自动成为层叠上下文元素。
带有 filter 属性的元素会自动成为层叠上下文元素。
安卓系统下,fixed 元素内部子元素使用组件 %border-btm-1pt,1像素线会被父元素的背景色盖住。
问题在于 transform-origin:50% 100%;
垂直方向的缩放原点100%。
解决办法,自身加 z-index,只要大于等于0的数值就可以。也可以对父元素加 z-index 创建层叠式上下文。
.example-1 {
-webkit-filter: blur(5px); /* 毛玻璃 */
}
.example-2 {
-webkit-filter: grayscale(0.5); /* 灰度 */
}
.example-3 {
-webkit-filter: sepia(0.5); /* 褐色 */
}
.example-4 {
-webkit-filter: brightness(3); /* 亮度 */
}
.example-5 {
-webkit-filter: hue-rotate(180deg); /* 色相 */
}
.example-6 {
-webkit-filter: invert(1); /* 反色 */
}
.example-7 {
-webkit-filter: opacity(0.5); /* 透明度 */
}
.example-8 {
-webkit-filter: saturate(5); /* 饱和度 */
}
.example-9 {
-webkit-filter: contrast(0.5); /* 对比度 */
}
.example-10 {
-webkit-filter: drop-shadow(10px 10px 5px rgba(0, 0, 0, 0.9)); /* 阴影 */
}
最近在做涉及视频、音频播放和APP、M版的分享的相关活动中,遇到了一些比较坑的问题。
分享出来,让大家一起了解一下。
1、在微信大入口之外的微信环境(分享给好友的链接或朋友圈的链接)可以自动播放视频和音频 ( .play
能触发)。
2、在微信大入口之内,必须要等到微信的 JSBridge Ready 了才能触发 .play
,否则不会自动执行。
document.addEventListener("WeixinJSBridgeReady", function() {
$("#video")[0].play();
});
最好监听了之后,在当前作用域内,立即执行。而不是使用 setTimeout 等计时器,延时执行。这样可能会导致在IOS下偶尔不能触发
.play
(经测试,大概10%~20%的几率不能触发)。
3、在大入口内,且 JSBridge Ready 了,如果使用摇一摇,也无法触发 .play
(经测试,.play
的触发不能直接在监听了 devicemotion
的事件处理内)。需要在摇一摇之前预先加载 .load
document.addEventListener("WeixinJSBridgeReady", function() {
$("#video")[0].load();
_shake.start({
duration: 500,
onShaking: function() { //正在摇
},
onEnd: function() { //一次摇一摇结束
$("#video")[0].play();
}
});
});
4、微信大入口在没有使用 JSBridge,而是通过点击来播放的点击事件,只能是 click
事情,不是
touchstart
事件
//正确的做法
$("#play").on("click",function(){
$("#video")[0].play();
});
//不正确的做法
$("#play").on("touchstart",function(){
$("#video")[0].play();
});
现金
红包
#
以上总结内容转自 @少露
WebP
(function() {
var img = new Image();
img.onload = function() {
if (img.width > 0 && img.height > 0) {
document.documentElement.className = "webp";
window.webpSupport = true;
}
}
img.onerror = function() {}
img.src = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
}());
APNG
(function() {
"use strict";
var apngTest = new Image(),
ctx = document.createElement("canvas").getContext("2d");
apngTest.onload = function () {
ctx.drawImage(apngTest, 0, 0);
self.apng_supported = ctx.getImageData(0, 0, 1, 1).data[3] === 0;
};
apngTest.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";
}());
这次年货,为了增添气氛,很多地方都用了边框,由于边框高度的不固定,给构建着实带了不小的麻烦。
通常我们处理边框的方法,无非以下两种方案:
1.切整张图片,做背景。
2.切上中下,进行拼接处理。
但是遇到,边框多种样式的时候,我可能就需要支招,切得手软,为了解决这些问题,我们尝试了border-image。
使用border-image,我们无非弄明白以下几个属性就能使用了:
border-image-source 用在边框的图片的路径。
border-image-slice 图片边框向内偏移。
border-image-width 图片边框的宽度。
border-image-outset 边框图像区域超出边框的量。
border-image-repeat 图像边框是否应平铺(repeat)、铺满(round)或拉伸(stretch)。
但是在使用过程中,可能会遇到两个这样的问题:
1.border-image使用中会产生多余的边框(手q中,在一些低端的andirod中)。
2.border-image-repeat的属性值,repeat 和 round 如何选择区分。
针对这两个问题,经过一些尝试,尝试发现:
1.border-image使用中会产生多余的边框,是由于边框图片边缘没有预留一定的空间导致的,这里建议预留1px,例图:
边框易产生多余的边框(低端机)
边框不会产生多余的边框
2.repeat 和 round 如何选择区分,round会压缩(或伸展)图片大小使其正好在区域内显示,而repeat是不管三七二十一直接重复的,而且是居中重复,多数情况建议大家可以用round,repeat会导致叠加现象,下面同种情况下实现的效果:
这个是w3cschool里面的例子,我加了round,repeat 比对:
<!DOCTYPE html>
<html>
<head>
<style>
div
{
border:15px solid transparent;
width:300px;
padding:10px 20px;
}
#round
{
-moz-border-image:url(/i/border.png) 30 30 round; /* Old Firefox */
-webkit-border-image:url(/i/border.png) 30 30 round; /* Safari and Chrome */
-o-border-image:url(/i/border.png) 30 30 round; /* Opera */
border-image:url(/i/border.png) 30 30 round;
}
#stretch
{
-moz-border-image:url(/i/border.png) 30 30 repeat; /* Old Firefox */
-webkit-border-image:url(/i/border.png) 30 30 repeat; /* Safari and Chrome */
-o-border-image:url(/i/border.png) 30 30 repeat; /* Opera */
border-image:url(/i/border.png) 30 30 repeat;
}
</style>
</head>
<body>
<div id="round">在这里,图片铺满整个边框。</div>
<br>
<div id="stretch">在这里,图片被拉伸以填充该区域。</div>
<p>这是我们使用的图片:</p>
<img src="/i/border.png">
</body>
</html>
效果:
HTML 规范文档为 images 引入了 crossorigin
属性, 通过设置适当的头信息 CORS
, 可以从其他站点加载 img
图片, 并用在 canvas 中,就像从当前站点(current origin)直接下载的一样.
crossorigin 属性的使用细节, 请参考 CORS settings attributes.
尽管没有CORS授权也可以在 canvas 中使用图像, 但这样做就会污染(taints)画布。 只要 canvas 被污染, 就不能再从画布中提取数据, 也就是说不能再调用 toBlob()
, toDataURL()
和 getImageData()
等方法, 否则会抛出安全错误(security error).
这实际上是为了保护用户的个人信息,避免未经许可就从远程web站点加载用户的图像信息,造成隐私泄漏。
如果用户登陆过QQ等社交网站, 假若不做保护 ,则可能打开某个网站后,该网站利用 canvas 将用户的图片信息获取,上传,进而引发泄露.
首先, 图片服务器必须设置相应的 Access-Control-Allow-Origin
响应头。添加 img 元素的 crossOrigin 属性来请求头。比如Apache服务器,可以拷贝 HTML5 Boilerplate Apache server configs 中的配置信息, 来进行回应:
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
<FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
SetEnvIf Origin ":" IS_CORS
Header set Access-Control-Allow-Origin "*" env=IS_CORS
</FilesMatch>
</IfModule>
</IfModule>
这些设置生效之后, 就可以像本站的资源一样, 保存其他站点的图片到 DOM存储) 之中(或者其他地方)。
var img = new Image,
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
src = "http://example.com/image"; // 具体的图片地址
img.crossOrigin = "Anonymous"; //或 img.crossOrigin = "*";
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage( img, 0, 0 );
localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// 确保缓存的图片也触发 load 事件
if ( img.complete || img.complete === undefined ) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
最近,收到反馈说3D翻转在小米4下展示异常。秉承实事求是的精神,拿了部安卓机子做观测。
观测的机型:华为荣耀3C(没有小米4,华为荣耀3C与米4的异常一致)
异常截图如下:
**图一**rotate3d的具体调用如下:
transform: rotate3d(0,0,0,90deg);
修改为:
transform: rotate3d(1,0,0,0deg);
问题得以解决:
**图二**rotate3d(0,0,0,90deg) 与 rotate3d(1,0,0,90deg) 有什么实质的区别。w3c 相关解释:
specifies a 3D rotation by the angle specified in last parameter about the [x,y,z] direction vector described by the first three parameters. A direction vector that cannot be normalized, such as [0,0,0], will cause the rotation to not be applied.
来源:https://www.w3.org/TR/css-transforms-1/;
根据w3c的说法应该是 rotate3d(0,0,0,90deg) 会不生效。而出问题的安卓机型却把 rotate3d(0,0,0,90deg) 降级为 rotate(90deg) 或 rotateZ(90deg)了。
w3c对rotate3d的用法如下:rotate3d( <number> , <number> , <number> , <angle>
)
为了便于说明,把上式写成 rotate3d(x,y,z,degree);
本人一开始对这个的理解是,x,y,z轴方法的旋转角度为 x * degree, y * degree ,z * degree。而下面的观测结果,打了我一巴掌,以下几个rotate3d的效果是一样的:
观测结果如下:
mac,adnroid和ios的表现都一样,只截mac上的chrome浏览的显示结果
这次观测的结论是: x,y,z的取值是:x?degree:0,y?degree:0,z?degree:0。
如果这个观测结论是正确的话,很容易推断得出,一个立方体只能沿七条线进行3D翻转:
使用以下代码验证第一次观测的结论是否正确:
<style>
.rect{
position: absolute;
width: 100px;
height: 100px;
background-color: #333;
left: 100px;
top: 100px;
-webkit-transform: rotate3d(1,1,0,30deg);/*观测关键代码*/
}
</style>
<div class="rect"></div>
观察结果如下:
**图3**将rotate3d更改为:
-webkit-transform: rotate3d(1,.5,0,30deg);
按上次观测结论,这次观测与上次观测结果应该完全相同。而观测结果却不是,如下:
**图4**第二次观测的结论为:x,y,z轴方法的旋转角度为 x * degree, y * degree, z * degree。(与本人最开始的理解一致)
第一次和第二次观测结果完全不同,但是又各有事实做证,于是我猜测:
1. rotate3d的x,y,z轴的角度值的计算为:x * degree,y * degree,z * degree;
2. 当且仅当x,y,z三个值中有两个值为0时,剩余的非0值取1;
沿用第二次观测的代码,观察下面几种情况:
观测结果如下:
与猜测结果一致。
rotate3d对x,y,z三个轴的取值遵守以下两点:
1. rotate3d的x,y,z轴的角度值的计算为:x * degree,y * degree,z * degree;
2. 当且仅当x,y,z三个值中有两个值为0时,剩余的非0值取1;
基于以上两点,rotate3d 的正确用法是:
1. 单轴翻转使用rotateX,rotateY,rotateZ
2. 使用rotate3d要避免 rotate3d(0,0,0,deg) 的情况
直接放弃rotate3d转用 rotateX,rotateY,rotateZ可以简单直接地避开所有风险点。
总结在使用 LayaAir 游戏引擎制作 H5 游戏中遇到的一些问题。
1、使用 HTMLDivElement 文本绘制
针对某一段文字中,某个数字需要加粗或换颜色的情况,可以使用 HTML 文本,默认情况下 htmlDivElement 的宽度为 200,文字到一定长度会自动换行,可以通过 p.style.wordWrap = false;
强制不换行或者将 width
的值设置为更大解决。
引入 laya.html.min.js
var p = new HTMLDivElement();
Laya.stage.addChild(p);
p.style.font = "-apple-system, Helvetica, sans-serif";
p.style.fontSize = 30;
p.style.wordWrap = false; // 强制不换行
p.width = 600; // 将默认 200 的宽度改为 600
p.innerHTML = "命中率" + "<span style='color: #f00'>" + 50% + "</span>" // 通过这种方式改颜色
2、绝对定位于底部
如果只需做竖屏或者横屏的页面时,我们只需要将 Laya.stage.height
舞台的高度减去元素高度即可,但是如果同时需要兼容横竖屏,导致高度不一,这样定位就稍稍有些不方便了,这时可以使用 UI 中的 Box 容器,他提供了 top
、bottom
、left
、right
等属性,可以方便的定位。
引入 laya.ui.min.js
var Box = Laya.Box;
var Sprite = Laya.Sprite;
var container = new Box(); // 容器
Laya.stage.addChild(container);
container.bottom = 0; // 基于底部定位
container.left = 0;
container.width = 1334;
container.height = 30;
var sp = new Sprite();
container.addChild(sp); // 将元素添加到容器中
sp.graphics.drawRect(0, 0, 200, 30, "#ffff00");
3、drawPath 实现线条末端线帽的样式
目前自定义路径的末端样式 lineCap
在 WebGL 渲染模式下无效,只能在 Canvas 模式下才行。
var sp = new Sprite();
Laya.stage.appChild(sp);
sp.drawPath(50, 50, [
["moveTo", 0, 0],
["LineTo", 100, 0],
["closePath"]
], {
fillStyle: "#00ffff"
}, {
lineWidth: 14,
lineCap: "round" // WebGL 模式下无效
});
4、Matter.js 旋转画布后的鼠标约束
LayaAir 集成了 Matter.js 物理引擎,Matter.js 的鼠标约束是它自身控制的,Matter.js 的显示是由 LayaAir 控制的,使用 LayaAir 旋转画布方向,但 Matter.js 不会旋转,所以会导致鼠标约束失效。解决方案是使用系统的横屏或者去修改 Matter.js 的源码,如果有约束或鼠标约束的事件,不建议旋转画布。
Laya.stage.screenMode = Stage.SCREEN_HORIZONTAL; // 自动横屏旋转画布后会导致 Matter.js 鼠标约束失效
5、使用 LayaAir 缩放后,修正 Matter.js 鼠标约束坐标
Laya.stage.on("resize", this, onResize);
function onResize() {
// 设置鼠标的坐标缩放
// Laya.stage.clientScaleX 代表舞台缩放
// Laya.stage._canvasTransform 代表画布缩放
Matter.Mouse.setScale(mouseConstraint.mouse, {
x: 1 / (Laya.stage.clientScaleX * Laya.stage._canvasTransform.a),
y: 1 / (Laya.stage.clientScaleY * Laya.stage._canvasTransform.d)
});
}
6、监听动画到某一帧
监听动画到达某一帧,需要给动画使用 addLabel
方法添加标签,再监听动画指定标签即可。
var anim = new Animation();
anim.addLabel("now", 2); // 当播放到第二帧时返回 "now" 字符串
anim.play();
anim.on(Event.LABEL, this, function(ev) { // 监听 LABEL 事件
if (ev == "now") {
console.log("到达第二帧");
}
});
7、改变元素层级
改变元素的层级可以使用 zOrder
属性
var sp = new Sprite();
Laya.stage.addChild(sp);
sp.zOrder = 10;
8、操作 Laya.init 生成的 Canvas
Laya.init(width, height, Laya.WebGL); // 返回 DOM 元素 Canvas
9、元素点击区域需要加 size 属性
var sp = new Sprite();
Laya.stage.addChild(sp);
sp.graphics.drawRect(10, 166, 166, 90, "#ffff00");
sp.size(166, 90); // size 的大小等于 sp 的宽高,就是鼠标的点击区域
sp.on("MOUSE_DOWN", this, function() {
console.log("点击触发!");
});
实现商品组内标签模块的适配问题,如图效果:
HTML 结构如下:
<div class="mall_recommend">
<div class="mall_recommend_item mall_recommend_tags">
<div class="tags">
<a href="#"><em>标签</em></a>
...
</div>
</div>
<a class="mall_recommend_item" href="#">
<div class="cover">
<img src="http://fpoimg.com/290x290?bg_color=dddddd">
</div>
<div class="info">...</div>
</a>
</div>
核心 SASS 代码:
.mall_recommend_tags {
position: relative;
/* 这里模拟 cover 的高度 */
&::before {
content: '\20';
display: block;
padding-top: 100%;
height: 0;
overflow: hidden;
}
/* 这里模拟 info 的高度 */
&:after {
content: '\20';
display: block;
width: 100%;
height: 75px; /* .info 高度 */
}
.tags {
position: absolute;
top: 0;
left: 0;
bottom: 0;
overflow: hidden;
width: 100%;
height: 100%;
padding-bottom: 8px; /* 上下元素间隙高度总和 */
a {
/* 代码省略:两栏布局 */
height: 20%; /* 高度占比 */
margin-bottom: 2px;
em {
/* 代码省略:文字水平垂直居中 */
}
}
}
}
修改 iOS 下 input disabled 颜色
input:disabled {
-webkit-text-fill-color: #ddd;
}
设置 input 标签 placeholder 属性的样式
.example::-webkit-input-placeholder {
color: red;
}
取消 input 默认样式
input {
border: none;
background: none;
appearance: none;
border-radius: 0;
}
取消点击 a、button、input 标签后区域半透明遮罩
a, button, input {
-webkit-tap-highlight-color: rgba(255, 0, 0, 0);
}
关闭 iOS 默认输入法首字母大写
<input type="text" autocapitalize="off">
如下图几种场景,实现英文字母与中文字母两端对齐,且英文字符需要做到均分:
可以通过两种方案实现:
通过 flex 布局的 justify-content: space-between;
属性实现两端对齐,项目之间的间隔都相等。
<div class="jd">
<i>J</i>D<i>G</i><i>W</i>
</div>
.jd {
display: flex;
}
.jd i {
width: 1em;
justify-content: space-between;
}
需要均分的字符间需要有一个空格进行字符之间的分离,结合 text-align: justify;
属性以及伪元素。
<div class="jd">J D G W</div>
.jd {
display: block;
text-align: justify;
}
.jd::after {
content: '';
display: inline-block;
width: 100%;
}
inline-block与line的垂直对齐关系很有意思,需要分成两种情况来说。
一行文本在垂直方向上有四条准线:顶线 中线 基线 底线。相对应 vertical-align 的 top middle baseline bottom 四个值。
空文本 inline-block 节点的 baseline 和 bottom 两条线重合,如下:
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>测试</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="format-detection" content="telephone=no" />
<style>
.lh_1{
background-color: red;
font-size: 14px;
line-height: 1;
}
.lh_12{
background-color: blue;
font-size: 14px;
line-height: 1.2;
}
.lh_15{
background-color: green;
font-size: 14px;
line-height: 1.5;
}
.lh_2{
background-color: yellow;
font-size: 14px;
line-height: 2;
}
.lh_3{
background-color: yellow;
font-size: 14px;
/*line-height: 3;*/
height: 42px;
width: 14px;
display: inline-block;
vertical-align: baseline;
}
.gray{
padding: 0 10px;
background-color: #999;
}
</style>
</head>
<body ontouchstart>
<div class="gray">
<span class="lh_1">文案</span>
<span class="lh_12">文案</span>
<span class="lh_15">文案</span>
<span class="lh_2">文案</span>
<span class="lh_3"></span>
</div>
</body>
</html>
观察结果如下:
将 .lh3
修改成:
.lh_3{
background-color: yellow;
font-size: 14px;
/*line-height: 3;*/
height: 42px;
width: 14px;
display: inline-block;
vertical-align: bottom;
}
观察结果如下:
从观察很容易得出: ** 空文本inline-block 的基线和底线重合 **
当inline-block带文本时,inline-block的baseline将会继承自它内部的文本的baseline,如下:
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>测试</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="format-detection" content="telephone=no" />
<style>
.lh_1{
background-color: red;
font-size: 14px;
line-height: 1;
}
.lh_12{
background-color: blue;
font-size: 14px;
line-height: 1.2;
}
.lh_15{
background-color: green;
font-size: 14px;
line-height: 1.5;
}
.lh_2{
background-color: yellow;
font-size: 14px;
line-height: 2;
}
.lh_3{
background-color: yellow;
font-size: 14px;
/*line-height: 3;*/
height: 42px;
width: 32px;
display: inline-block;
vertical-align: baseline;
}
.gray{
padding: 0 10px;
background-color: #999;
}
</style>
</head>
<body ontouchstart>
<div class="gray">
<span class="lh_1">文案</span>
<span class="lh_12">文案</span>
<span class="lh_15">文案</span>
<span class="lh_2">文案</span>
<span class="lh_3">文案</span>
</div>
</body>
</html>
观察如下:
很明显,最右边的inline-block内的文本与左边三个文本是垂直对齐的,所以可以肯定:文本 inline-block 的baseline 继承自它内部的文本。
还可以进一步推论到:文本 inline-block 的baseline继承自它内部最后一行文本的baseline
更改一下 .lh3
的内容
<span class="lh_3">文<br />案</span>
观察结果如下:
inline-block的baseline继承自内部最后一行文本的baseline。
本文没有介绍其它三条线,是因为这三条线跟我们的想象是一样的,顶线,中线和底线对应inline-block在y轴上的 0%,50%,100%,它们不受文本的影响。
图片经过多次压缩后会达到极限,并且压缩后的图片可能受损以至无法使用!如下:
png的极限压缩并不能带来高质量的图片,适应压缩才是王道。
想得到高质量低体积的图片,可以考虑使用 webp。
WebP(发音 weppy,项目主页),是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。根据 Google 的测试,无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使这些 PNG 文件经过其他压缩工具压缩之后,WebP 还是可以减少 28% 的文件大小。
来源: ISUX -- WebP 探寻之路
webp官网给出的文档压缩率并没有这么高,如下:
WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller than comparable JPEG images at equivalent SSIM quality index.
来源:A new image format for the Web
按官方说法,png转成webp最少也能减少 25%的文件大小。
以下是webp各浏览器的支持情况:
来源: [caniuse](http://caniuse.com/#search=webp)另外,微信手Q(X5)的支持情况如下:
来源:[How well x5 browser support HTML5?](http://res.imtt.qq.com/qqbrowser_x5/h5/h5_support.htm)android 4.0以上和X5内核全面支持 webp格式,IOS暂时不支持
线上工具:腾讯智图 、ppms-photo(http://ppms1.jd.com/photo)
本地工具:WebP Converter
WebP Converter 的安装请参见:https://developers.google.com/speed/webp/
mac 可用 homebrew 安装:
sudo brew install webp
使用以下指令转换 webp
cwebp -q 80 image.png -o image.webp
具体参见:https://developers.google.com/speed/webp/docs/cwebp
ppms-photo(http://ppms1.jd.com/photo)自带了图片转换webp格式的功能。只需要在上传图片后,在图片地址的后缀加上 .webp
即可以得到webp格式的图片。
以下是图片 1.png (372K) 上传到 ppms-photo 后生成的图片
添加 .webp
,得到webp格式的图片
ppms-photo 有一个强大的功能:按质量取webp图。
如果想获取质量为75%的图片,可以在.png.webp前加!75获得:
不在过观察过程中发现,ppms-photo转换webp时质量存在一个质量上限值:80%。可以 智图 、ppms-photo or WebP Converter 这个章节中看到数据。
webp默认是有损压缩的,默认质量 75%,同时也是推荐值。
原图 与 75%WebP 对比:
本人观察不出 webp 的质量损失。
质量100%WebP 与 质量75%WebP 文件大小对比:
原图: 1.png 372K
质量100%WebP: 1.png 104K
质量75%WebP: 1.png 16K
视觉对比无差别而文件大小却相差 6~7倍,这个观察结果足使 75% 做为推荐值。
WebP Converter: 0.4.3
智图:2016.07.12(没有版本号,取日期)
ppms-photo:2016.07.12(没有版本号,取日期)
智图与WebP Converter的转换率如下:
质量 | 智图 | ppms-photo | WebPConverter | 质量 | 智图 | ppms-photo | WebPConverter |
---|---|---|---|---|---|---|---|
100% | - | 18.9K | 104K | - | - | - | - |
95% | 83.2K | 19000B | 49552B | 60% | 22.8K | 14224B | 14224B |
90% | 62.7K | 19000B | 31718B | 55% | 20.2K | 13458B | 13458B |
85% | 43.4K | 19000B | 23716B | 50% | 18.8K | 12842B | 12842B |
80% | 40.7K | 19000B | 19000B | 40% | 14.6K | 11490B | 11490B |
75% | 36K | 16188B | 16188B | 30% | 14.2K | 10180B | 10180B |
70% | 30.6K | 15434B | 15434B | 20% | 14K | 8960B | 8960B |
65% | 25K | 14684B | 14684B | 10% | 13.2K | 7528B | 7528B |
原图: 1.png (372K)
ppms-photo跟WebP Converter转换率一样(ppms-photo使用的是WebP Converter),WebP Converter 全面优于智图。
建议使用 WebP Converter 或 ppms-photo 来做为 Webp的转换工具。
按官方或是ISUX描述,可能会有这样的观点:压缩后的图片转webp可得到更小的图片。
做个简单验证:
图片: 1.png (372K)
压缩工具:tinypng
webp: WebP Converter 和 智图
压缩次数 | png | webp | webp(智图) |
---|---|---|---|
0 | 372K | 15.80K | 36K |
3 | 172K | 18.55K | 70.2K |
6 | 156K | 26.28K | 108.3K |
9 | 141K | 33.32K | 140.5K |
12 | 134K | 37.37K | 152.3K |
本节webp的质量为75% |
通过上面的数据,得到一个相反的结论:webp文体大小与图片压缩次数成正比
这个验证同时又一次证明智图是一个很差的webp工具!转换的结果是对ISUX的打脸
使用官方的 WebP Converter 做为转换工具,并且图片转换前不要做任何图片压缩!
不知道各位的切图方法是怎么样的,之前我的方式是把不需要的图层隐藏,然后一点点拖动裁剪工具、四周空出1px,然后保存,如果图层比较多,会先把图层拖到新文件,再裁剪保存;还有其他方法比如command+鼠标左键选中图层、command+c、新建文件然后粘贴、再保存;也有借助切图插件比如cutterman的,但是cutterman不能设置图像周围空出1px,这在rem单位的时候还挺重要的……
都挺麻烦的,其实有更简单快捷的方式切图。
ps2015之后的版本已经提供直接导出图层的功能,而且功能还挺强大,所以可以淘汰类似cutterman的切图插件。
使用方法:
右键图层(图层组)——导出为——弹出面板设置——保存
并且,可以设置图像大小,可以等比缩放icon,适配多倍屏;
还可以设置画布大小,避免单数宽高、设置每个icon四周都留出1px的空白——比如宽度是69,调整为71后ps会自动把1px分布在两边,如果调整为72,则分配左边1px,右边2px。这样通过自动化合并的icon就不会出现被“吃掉”1、2px的问题了
注意:
1、一般比较大的图层点击“导出为”后会一直loading,可以“合并图层”命令先合并再“导出为”
2、如果icon由几个图层组成而设计同学(💣)又没做好分组,那这个方式就不太好使了,要选中多个图层合并后再“导出为”
3、如果用扩展屏幕的同学“导出为”弹窗会像如下这样的话,请安装“sizeup窗口管理app”,“control + option + command + ↓”即可把窗口下移。这个app非常好用,可以快捷键使任意app窗口上下左右分屏、全屏,不买license也可以用。
大家切图保存的时候相信经常会忘记添加“@2x”字符,所以用mac自带的Automator工具写了一个小工具,可以方便批量添加“@2x”.
下载地址:http://storage.360buyimg.com/mtd/home/-2x-workflow1477988002223.zip
安装
:双击文件安装
卸载
:打开/Users/[you name]/Library/Services/,删除文件就行
用法
:选中文件(或文件夹,可多选)——右键——服务——“文件名添加@2x”
适用于
:Finder和PathFinder,PF在服务里找不到的话请重启系统
想用快捷键的同学可以这样设置:
设置——键盘——快捷键——服务——找到“文件名添加@2x”,添加快捷键即可
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.