苹果的 OS 在不断发展,Safari 亦越变强大性感,在最新的 9.0 版本当中,Safari 增加了不少新的特性,这里主要介绍一下和 Web 前端密切相关的。

Viewport Changes

关于新 Safari 对 Viewport 的影响我们先看下面一段引自苹果开发者官方文档的说明:

Viewport meta tags using “width = content-width” cause the page to scale down to fit content that overflows the viewport bounds. You can override this behavior by adding “shrink-to-fit = no” to your meta tag as shown below. The added value will prevent the page from scaling to fit the viewport.

可以看到 Safari 将会对有内容溢出 Viewport 区域的页面进行缩放适配,使溢出的内容完整展示而不出现滚动条,而在 Viewport 设置中引入了一个新属性 shrink-to-fit = no,该属性可以禁止这种缩放行为的发生。

下面我们具体看一下该体贴行为对页面的影响。

在 Safari 9.0 之前的版本,当 viewport meta 标签的 content 属性有设置的时候,如果页面内容溢出 viewport 的定义区域,那么页面将会出现滚动条,如下面的页面,该页面的 viewport 设置为:

1
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" >

NotFixed

截图如下:

image

然而在 Safari 9.0 的版本,即使 viewport 设置了 initial-scale=1.0user-scalable=no,Safari 不仅重置了设定好的最小缩放值限制,而且还重新恢复了用户对页面进行缩放的操作权限,上述页面在 Safari 9.0 中的截图如下:

image

从上面的截图可以看到,Safari的缩放行为对页面视觉破坏性还是比较厉害的,如果溢出的内容很多的话,页面就会被缩得更小了。

在 viewport 设置添加 shrink-to-fit = no 这个属性后,设置如下:

1
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no,shrink-to-fit = no" >

Safari 就不会再对页面进行缩放处理,恢复之前版本的处理方式,

Fixed

截图如下:

image

在日常的需求中,尽管内容溢出页面的情况不会太常见,但为了增强页面的容错能力,保证页面视觉的正常显示,在 viewport 设置中应该加上 shrink-to-fit = no 新属性。

Safari内容拦截扩展

Safari 9.0 新增了内容拦截扩展,该扩展程序能够便捷高效地拦截 cookies、图片、资源文件、弹窗等内容,不仅可以在 OS X 上使用,在 iOS 上也同样适用。

iOS

内容拦截扩展程序负责提供一个 JSON 文件给 Safari,这个 JSON 文件包含了一个数组,数组里面可以配置相关规则(主要由 triggers 和 actions 组成 )拦截指定的内容,Safari 会将该 JSON 文件转换成字节代码,转换后的字节代码被应用到所有加载资源,有效地避免了用户浏览器的信息泄露到扩展程序。

内容拦截扩展程序的核心就是通过 JSON 文件的配置和传送,Safari 接收到之后就可以根据 JSON 的配置对相应的加载资源进行适配完成拦截。

Xcode内设有内容拦截应用模版(Content Blocker App Extension template),里面有一个 blockerList.json JSON 文件,默认设置是这样的:

1
2
3
4
5
6
7
8
9
10
[
{
"action": {
"type": "block"
},
"trigger": {
"url-filter": "webkit.org/images/icon-gold.png"
}
}
]

表示对站点 webkit.org 的一张名为 icon-gold.png 的图片进行拦截。

除了可以从加载资源上拦截外,还可以通过 CSS 选择器对元素进行隐藏,如下面的配置会将站点所有 class 名为 “ads” 的 div 进行 display: none !important; 样式处理。

1
2
3
4
5
6
7
8
9
10
11
[
{
"action": {
"selector": "div.ads",
"type": "css-display-none"
},
"trigger": {
"url-filter": ".*"
}
}
]

注意:由于 32 位架构的设备性能限制,iOS上的内容拦截扩展只适用在 64 位架构的设备上,苹果从 A7 处理器开始采用 64位架构,因此 iPhone 5s + 的机器才可能使用此扩展应用

关于参数 action 和 trigger 的更多介绍可以参阅:

image

Introduction to WebKit Content Blockers

Safari Content Blocking in iOS 9: a tutorial by example

一个简单的内容拦截扩展应用

实现一个拦截扩展应用很简单,现在我们以 拍拍小店首页 为例,拦截顶部广告区域:

image

Update Xcode 到最新版本,打开 Xcode,新建立一个 iOS Single View Application 项目(blocker-demo),如图所示:

image

然后新建立一个 Target,在 Application Extension 模版中选中 Content Blocker Extension:

image

完成之后,就可以在项目中看到刚才新增的 Target 文件夹(blocker),可以找到一个名为 blockerList.json的 JSON 文件,在里面就可以配置需要拦截内容的规则了,如图所示:

image

(顶部广告区域的 class 名为 mod_ad, 例子中的配置将会将顶部广告区域隐藏。)

然后以整个项目为编译对象,选择需要测试的模块器(这里选择了 iPhone6)运行程序 , 切记不要选中 content blocker 的 Target 为编译对象运行,在模拟器上不能生效

运行后我们看到白茫茫的一片,模拟器默认打开了刚才新建立的应用,这时候我们需要回到主界面(command + shift + h)进入系统设置界面, 到 Safari >Content Blockers 里面启动内容拦截扩展,如图所示:

image

启动 Safari,打开拍拍小店首页,这时候我们可以看到,启动内容拦截扩展之后,顶部的广告区域被隐藏了

image

用 Safari 的 Web 检查器看了一下页面,发现用户样式表里针对顶部广告区域多了一个 display: none !important;样式

image

最后需要将程序打包,才能在真机运行,貌似需要 688RMB 的开发者帐号,土豪们可以尽情试一试。

OS X

在 OS X Safari 的扩展创建器(Extension Builder)加入拦截 JSON 文件(如下图)或者在 Safari 扩展对象中使用新增的 setContentBlocker API 就可以实现内容拦截功能了

image

需要注意的是,用于拦截内容的 onbeforeload 事件和 canLoad 信息已被弃用

更多有关 Safari 内容拦截扩展介绍:

Safari Content Blocking in iOS 9: a tutorial by example

iOS 9之Safari广告拦截器(Content Blocker)

System Font Support

-apple-system

苹果操作系统会从两种不同外观和大小的字体进行自动转换去调节系统新字体 “San Francisco”,可以通过 CSS 规则

font-family: -apple-system, sans-serif;

让系统智能选择适配操作系统的字体。

可以看一下下面两张在系统 OS X 10.11.1 下的对比图:

没有添加 -apple-system 属性值:

image

添加了 -apple-system 属性值:

image

可以看到添加了 -apple-system,字体变得更圆润锐利

建议:在 font-family 属性加上 -apple-system 属性值。

图片看不出差别的同学请用 OS X Safari 9.0 打开以下链接:

System Font Support

image

更多关于 System Font Support 介绍 :Using the System Font in Web Content

附:《在吐槽iOS 9的新字体之前,你应该了解这些》

iOS text-style keywords

Safari 9.0除了支持 -apple-system 新字体特性之外,在 iOS 平台提供了更丰富更具活力的文本样式,该文本样式不仅仅是特定的字体,包括所有的 font 样式,如字重和字号,因此只能以 font 来定义:

  • font: -apple-system-body;
  • font: -apple-system-headline;
  • font: -apple-system-subheadline;
  • font: -apple-system-caption1;
  • font: -apple-system-caption2;
  • font: -apple-system-footnote;
  • font: -apple-system-short-body;
  • font: -apple-system-short-headline;
  • font: -apple-system-short-subheadline;
  • font: -apple-system-short-caption1;
  • font: -apple-system-short-footnote;
  • font: -apple-system-tall-body;

加上这些属性在 iOS 上会有不同的表现:

image

有兴趣的同事去 Demo 页看一下:

image

CSS Scroll Snapping

2015年3月26日,W3C的CSS工作组发布了CSS滚动界限点模块(CSS Scroll Snap Points Level 1)的首份工作草案(First Public Working Draft)。在浏览可以连续上下滚动或左右滚动的连续页面或一组图片时,通过触摸屏的触摸滑动或鼠标滚轴的滚动操作可以获得较好用户体验。

Safari 9.0 的新特性支持强大的 CSS Scroll Snap,利用这个特性,我们可以用CSS轻松实现网站常见的轮播图滚动特效

我们先看一下 Demo 感受一下 ,请用 Safari 9.0 打开

image

使用 Scroll Snap 需要的结构包含装载滚动元素的容器和需要滚动的元素:

<div class="scroll_container">
    <div class="scroll_elements"></div>
    <div class="scroll_elements"></div>
    <div class="scroll_elements"></div>
    <div class="scroll_elements"></div>
</div>

Scroll Snap 一共有5个CSS属性可使用,分别是

  • scroll-snap-type:定义滚动界限的类型,有三个属性值可选, none | mandatory | proximity,初始值为 none目前 WebKit 只支持 mandatory

  • scroll-snap-points-x:定义滚动容器 X 轴方向的 scroll sanp 点,有两个属性值可选,none| repeat(<length>),初始值为 none

  • scroll-snap-points-y:定义滚动容器 Y 轴方向的 scroll sanp 点,有两个属性值可选,none | repeat(<length>),初始值为 none

  • scroll-snap-destination:定义滚动元素在滚动容器的对齐坐标点,属性值为 <position>,初始值为:0px 0px

  • scroll-snap-coordinate:定义滚动元素与滚动容器对齐点重合的坐标点,属性值为 none | <position>,初始值为 none

属性 scroll-snap-typescroll-snap-points-xscroll-snap-points-yscroll-snap-destination 应用在容器元素

属性 scroll-snap-coordinate 应用在滚动元素

滚动容器 scroll snap 坐标点 和 滚动元素 scroll snap 坐标点分别如下图红色十字和黄色十字所示:

image

此时的设置是:

1
2
3
4
5
6
7
8
.scroll_container{
-webkit-scroll-snap-type: mandatory;
-webkit-scroll-snap-destination: 50% 50%;
}
.scroll_elements{
-webkit-scroll-snap-coordinate: 50% 50%;
}

属性详细使用情况请参阅 CSS Scroll Snap Points Module Level 1

需要注意的

  • 该草案还在不断修进改进,WebKit 目前只支持带 -webkit- 前辍的写法

  • 要启用 scroll snap 效果,滚动容器必须具有非 none 值的属性 scroll-snap-type

  • 滚动容器 scroll-snap-points-xscroll-snap-points-y 的属性设置会忽略滚动元素 scroll-snap-coordinate 属性设置

  • 滚动容器 scroll-snap-destination 属性与滚动元素 scroll-snap-coordinate 总是成对出现的

  • 滚动内容发生改变(如滚动容器大小、滚动元素大小、节点的改变等)使得滚动元素的 scroll snap 点不在滚动容器的 scroll snap 点的时候,滚动偏移值会发生改变。

  • 不同尺寸的滚动元素混合在一起发生滚动的时候,在 X 或 Y 轴方向上离滚动容器 scroll snap 点最近的滚动元素 scroll snap 点方向轴将会与滚动容器 scroll snap 点的方向轴重合(存在滚动区域的时候)。

更多关于 scroll-snap 属性 Demo 可查看 Scroll Snapping with CSS Snap Points

Initial Letter Support

Safari 9.0 支持 CSS initial-letter(要带 -webkit- 前辍) 属性了,以前我们通过伪元素 ::first-letter实现首字下沉的效果,但是局限性比较多:

  • 首字母的高度需要通过调整字号大小实现,比较难精确到需要设置的高度

  • 段落字号改变的时候,首字母字号并不能自适应改变,因此并不能自适应实现对齐

image

CSS initial-letter 属性能很好的解决这些问题,我们先看一下它的属性值:

  • normal – 初始值

  • [<number> <integer>] – 定义首字母的大小和下沉位置

    • <number> 首字母的大小,大小值为正数值,字高占据的行数为单位,如 “2” 表示首字母高大小占据段落两行

    • <integer> 首字母下沉的位置,大小值为不为0的整数,若缺省,则以第一个参数 <number>数值为准

initial-letter属性应用在伪元素 ::first-letter 或容器第一个行内子元素

w3文档介绍的 EXAMPLE 截图引用如下:

image

实验 Demo 如下:

image

Backdrop Filters

CSS背景滤镜属性 backdrop-filter 可以让元素的背景或元素层级以下的元素加上滤镜效果,以下的属性值在 Safari 9.0 得到了全面支持:

  • blur(<length>):模糊,原始效果值为 0px,不接受负值

  • brightness([ <number> | <percentage> ]):亮度,原始效果值为 1100%,不接受负值

  • contrast([ <number> | <percentage> ]):对比度,原始效果值为 1100%,不接受负值

  • drop-shadow( <length>{2,3} <color>?):投影,原始效果值为所有长度值为 0,长度值至少2个,最多3个,注意:不支持投影扩展值和混合投影

  • grayscale([ <number> | <percentage> ] ):灰度,原始效果值为 0,最大值为 1100%,不接受负值

  • hue-rotate( <angle>):相位,原始效果值为 0deg

  • invert( [ <number> | <percentage> ]):反相,原始效果值为 0,最大值为 1100%,不接受负值

  • opacity([ <number> | <percentage> ] ):透明度,原始效果值为 1,最大值为 1100%,不接受负值

  • saturate([ <number> | <percentage> ]):饱和度,原始效果值为 1,不接受负值

  • sepia([ <number> | <percentage> ]):乌贼墨,原始效果值为 0,最大值为 1100%,不接受负值

滤镜属性 filter 同样具有以上的属性值,与背景滤镜backdrop-filter 不同的是,filter 作用于元素本身(文本、背景等)以其子元素,而 backdrop-filter 只作用于元素本身的背景(文本及其子元素不受影响)以及其层级下面的其它元素,具体的测试参考下面的 Demo

image

image

更多关于 backdrop-filter

WebKit.org:Introducing Backdrop Filters

w3c文档:typedef-filter-function-list

CSS3 Feature Queries

Safari 9.0 支持了 CSS3 功能查询 @supports,可以对 CSS 属性(包括但不限于带前辍的属性,如 -webkit-,-moz- 等)进行检测

单个条件查询

1
2
3
4
5
6
/* 检测是否支持 display:flexbox,如果支持侧执行中括号的内容 */
@supports ( display: flexbox ) {
.selector{
...
}
}

多个单件查询

可以使用逻辑关键字 notandor 进行多个单件查询

1
2
3
4
5
6
7
8
@supports ( box-shadow: 2px 2px 2px black ) or
( -moz-box-shadow: 2px 2px 2px black ) or
( -webkit-box-shadow: 2px 2px 2px black ) or
( -o-box-shadow: 2px 2px 2px black ) {
.selector{
...
}
}

需要注意的地方

  • @supports 后面总是跟着一个空格符和一个括号,逻辑关键字前后总有一个空格符。因此,写查询条件的时候

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /* 错误的写法 */
    @supports display: flexbox {
    // ...
    }
    @supports(display: flexbox){
    // ...
    }
    @supports (display: flexbox)and(-webkit-scroll-snap-type:mandatory) {
    // ...
    }
    /* 正确的写法 */
    @supports (display: flexbox) {
    //...
    }
    @supports (display: flexbox) and (-webkit-scroll-snap-type:mandatory) {
    // ...
    }
  • 多个单件查询,当有多个逻辑关键字混合使用的时候,查询语句最外层最多只有一个逻辑关键字:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* 错误的写法 */
    @supports (A) or (B) and (C) {
    //...
    }
    /* 正确的写法 */
    @supports (A) or ((B) and (C)) {
    //...
    }
    @supports ((A) or (B)) and (C) {
    //...
    }

@supports 更详细说明可参考:at-supports

Demo测试

CSS4 Selectors

以下 CSS4 选择器在 Safari 9.0 完全支持了:

  • 属性选择器忽略大小写标识(Case-insensitive attribute selectors)
  • :any-link
  • :lang
  • :matches
  • :not
  • :nth-child
  • :placeholder-shown

Case-insensitive

一般情况下,选择符中属性名和值的大小写敏感性取决于文档语言的敏感性,为了使其匹配忽略大小写敏感性以及其文档语言的敏感性,可以在属性选择器的关闭符]前加上标识符 i,这样不管在什么文档,都能忽略大小写敏感性,如以下例子:

结构:

<div class="box" title="BOX">Box</div>

样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* .box初始背景色为白色 */
.box{
width: 100px;
height: 100px;
margin: 10px;
color: #fff;
text-align: center;
line-height: 100px;
word-break: break-all;
word-wrap: break-word;
background: #fff;
}
/* 属性值大小写敏感,完全匹配,.box背景变黑色 */
.box[title="BOX"]{
background: #000;
}
/* 用了 CSS4 的 Case-insensitive 属性选择器,若浏览器支持,大小写不再敏感,能完成匹配,.box背景生效变为灰色 */
.box[title="box" i]{
background: #ccc;
}

关于 Case-insensitive 更详细介绍:w3介绍文档 - Case-insensitive

测试 Demo

image

伪类 :any-link

w3文档介绍大概的描述是这样的:

如果元素有定义伪类 :link:visited:any-link将会对其进行匹配。

于是写了 Demo 验证了一下

HTML:

<a href="http://aotu.io/" title="" class="lk">凹凸Team链接</a>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
.lk{
display: block;
width: 100px;
height: 30px;
line-height: 30px;
text-align: center;
}
/* 黑色背景 */
.lk:link{
background: #000;
color: #fff;
}
/* 黄色背景 */
.lk:visited{
background: #ff0;
color: #333;
}
/* 红色背景 */
.lk:any-link{
background: #ff3737;
color: #fff;
}
/* 白色背景 */
.lk:hover{
background: #fff;
color: #333;
}
/* 灰色背景 */
.lk:active{
background: #ccc;
color: #333;
}

结果发现:

  • :any-link Safari 9.0 生效了,Chrome、Firefox 并没有生效。

  • 伪类 :any-link 的确会对已定义有的伪类:link:visited匹配,并重新覆盖元素相同的CSS属性, 而 :hover:active 并没有匹配成功,:hover:active 依然生效

  • CSS代码解析的时候渲染 :any-link 前就渲染了 :link:visited,因此匹配成功了,而 :hover:active 出现在 :any-link 后面,并不能匹配成功

若加上 -webkit- 前辍,Chrome 亦能生效。

如果将 :any-link 出现位置改变,:any-link 始终匹配出现在他之前的 Link 相关伪类,有兴趣的同学可以试一下。

小小总结了一下:

  • :any-link Safari 9.0 不需要加前辍,Chrome、Firefox 浏览器需要加 -webkit--moz- 前辍。

  • :any-link 匹配有效性和书写顺序有关,:any-link 只对出现在其之前的 Link 伪类匹配生效。

建议

写 a 标签样式的时候,在 :hover:active 前应该加上 :any-link 伪类样式,覆盖系统默认的 :link:visited伪类样式。如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
a{
...
}
a:-webkit-any-link{
...
}
a:-moz-any-link{
...
}
a:any-link{
...
}
a:hover{
...
}
a:active{
...
}

关于 :any-link 更详细介绍: w3介绍文档 - :any-link

实验 Demo

image

伪类 :matches()

:matches() 是一种类似函数的伪类,可以将不同的选择器以数组形式混合形成一个选择器组,我们可以将之看作是CSS的一种语法糖,请看下面的例子:

:matches(section, article, aside, nav) h1 {
  color: #BADA55;
}

/* 相当于下面的代码 */
section h1,
article h1, 
aside h1,
nav h1 {
  color: #BADA55;
}

更方便书写一些复杂的选择器,如:

:matches(section, article, aside, nav) :matches(h1, h2, h3, h4, h5, h6) {
    color: #BADA55;
}

/* 相当于下面的代码 */
section h1, section h2, section h3, section h4, section h5, section h6, 
article h1, article h2, article h3, article h4, article h5, article h6, 
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6, 
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
    color: #BADA55;
}

减少重复的书写:

.links:matches(:hover, :focus, :active) {
    color: #BADA55;
}

/* 相当于下面的代码 */
.links:hover, .links:focus, .links:active {
    color: #BADA55;
}    

注意::matches()不能嵌套而且不能与 :not() 一起使用,以下的写法都是不允许的:

/* Doesn't work */
:matches(:not(...))

/* Doesn't work */
:not(:matches(...))

/* Doesn't work */
:matches(:matches(...))

更多关于 :matches() 可参考

CSS-tricks ::matches()

W3文档:matches

伪类 :placeholder-shown

如果元素 E 设置了属性 placeholder,属性值不为空并出现在页面的时候,那么E:placeholder-shown 就能匹配到该元素,当 placeholder 文本在页面消失的时候,匹配到的相应样式也会消失,如以下 Demo 所示:

image

伪类 :nth-child,:not,:lang

详细用法有兴趣的同学可以到 w3文档 查阅:

:lang - #the-lang-pseudo

:not - #negation

:nth-child - #the-nth-child-pseudo

Unprefixed CSS Properties

以下CSS属性在 Safari 9.0 已完全支持,不用再带 -webkit- 前辍:

  • transition
  • transition-delay
  • transition-duration
  • transition-property
  • transition-timing-function
  • animation
  • cursor: zoom-in
  • cursor: zoom-out
  • perspective
  • perspective-origin
  • transform
  • transform-origin
  • transform-style
  • @keyframes
  • animation-name
  • animation-duration
  • animation-timing-function
  • animation-iteration-count
  • animation-direction
  • animation-play-state
  • animation-delay
  • animation-fill-mode
  • order
  • align-content
  • align-items
  • align-self
  • justify-content
  • flex
  • flex-basis
  • flex-direction
  • flex-flow
  • flex-grow
  • flex-shrink
  • flex-wrap
  • break-after
  • break-before
  • break-inside
  • columns
  • column-count
  • column-fill
  • column-gap
  • column-rule
  • column-rule-color
  • column-rule-style
  • column-rule-width
  • column-span
  • column-width
  • alt

Responsive Design Mode

Safari 9.0 推出了响应式设计模式,command + option + R 或在“开发 – 进入响应式设计模式”可以进入,界面如下图:

image

这里有:

  • 现主流 iPhone/iPad 机型尺寸
  • iOS8.1系统模拟(iphone、ipad、ipod touch)
  • 苹果系主流分辨率
  • Safari 9.0.1 Mac
  • Chrome – Mac/Windows
  • FireFox – Mac/Windows
  • IE7 - IE10 –Windows( 好样的!)
  • 页面精度

点击选中的机型图标还可以以不同的方式展示,如 iPhone 的横屏,iPad 的分屏等

响应式设计模式 Chrome 浏览器早早就有,但单从苹果产品的调试去看,个人更喜欢 Safari 的响应式设计模式,无论从外观、体验以及专注度,都要优于 Chrome,Safari一直在进步,从不怀疑 Apple Developer 的级数。

image

Web Inspector Redesign

之前所了解到的 Web Inspector 版本:

image

(从苹果开发者文档介绍了解到的,没使用过,目测是 Safari 4.0 or 之前的)

image

(直接 google 图片了解到的,没使用过,目测是 Safari 6.0 重新设计那款)

Safari 9.0 的 Web 检查器经过了重新设计,更直观易用,用户体验更棒。

开发任务 Tab 切换更简易快捷,新的渲染时间线框架更容易更细致检测到页面渲染的情况

image

元素查看,样式修改调试方便,直接点光标直接处于编辑状态了,不明白 Chrome 的为什么点了默认全选,编辑态还有一个输入框的形态,Apple 的极简设计理念无处不在,处处体现着苹果 Design 的基因

image

断点调试器也哗啦啦地好看易用:

image

更多的内容有兴趣的同学去体验一下吧,这里就不一一烧图了。

如果说 Chrome Web Inspector 是一名角斗士,那么 Safari Web Inspector 就是一名会写诗的角斗士