aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/css/will-change/index.html
blob: 8ae9374a378d2457b9a55e0645702e147eef3791 (plain)
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
---
title: will-change
slug: Web/CSS/will-change
translation_of: Web/CSS/will-change
---
<div>{{ CSSRef() }}{{SeeCompatTable}}</div>

<p><span class="seoSummary"><a href="/zh-CN/docs/Web/CSS">CSS</a> 属性 <code>will-change</code> 为web开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。</span> 这种优化可以将一部分复杂的计算工作提前准备好,使页面的反应更为快速灵敏。</p>

<p>用好这个属性并不是很容易:</p>

<ul>
 <li>
  <p id="Don't_apply_will-change_to_too_many_elements"><strong>不要将 will-change 应用到太多元素上</strong>:浏览器已经尽力尝试去优化一切可以优化的东西了。有一些更强力的优化,如果与 <code>will-change</code> 结合在一起的话,有可能会消耗很多机器资源,如果过度使用的话,可能导致页面响应缓慢或者消耗非常多的资源。</p>
 </li>
 <li>
  <p><strong>有节制地使用:</strong>通常,当元素恢复到初始状态时,浏览器会丢弃掉之前做的优化工作。但是如果直接在样式表中显式声明了 <code>will-change</code> 属性,则表示目标元素可能会经常变化,浏览器会将优化工作保存得比之前更久。所以最佳实践是当元素变化之前和之后通过脚本来切换 <code>will-change</code> 的值。</p>
 </li>
 <li>
  <p><strong>不要过早应用 will-change 优化:</strong>如果你的页面在性能方面没什么问题,则不要添加 <code>will-change</code> 属性来榨取一丁点的速度。 <code>will-change</code> 的设计初衷是作为最后的优化手段,用来尝试解决现有的性能问题。它不应该被用来预防性能问题。过度使用 <code>will-change</code> 会导致大量的内存占用,并会导致更复杂的渲染过程,因为浏览器会试图准备可能存在的变化过程。这会导致更严重的性能问题。</p>
 </li>
 <li>
  <p id="Give_it_sufficient_time_to_work"><strong>给它足够的工作时间:</strong>这个属性是用来让页面开发者告知浏览器哪些属性可能会变化的。然后浏览器可以选择在变化发生前提前去做一些优化工作。所以给浏览器一点时间去真正做这些优化工作是非常重要的。使用时需要尝试去找到一些方法提前一定时间获知元素可能发生的变化,然后为它加上 <code>will-change 属性。</code></p>
 </li>
</ul>

<p>{{cssinfo}}</p>

<h2 id="语法">语法</h2>

<pre class="twopartsyntaxbox"><a href="/zh-CN/docs/CSS/Value_definition_syntax" title="CSS/Value_definition_syntax">Formal syntax</a>: {{csssyntax("will-change")}}
</pre>

<pre>will-change: auto
will-change: scroll-position
will-change: contents
will-change: transform        // Example of &lt;custom-ident&gt;
will-change: opacity          // Example of &lt;custom-ident&gt;
will-change: left, top        // Example of two &lt;animateable-feature&gt;

will-change: unset
will-change: initial
will-change: inherit
</pre>

<h3 id="取值">取值</h3>

<dl>
 <dt><code>auto</code></dt>
 <dd>表示没有特别指定哪些属性会变化,浏览器需要自己去猜,然后使用浏览器经常使用的一些常规方法优化。</dd>
</dl>

<p><code>&lt;animateable-feature&gt;</code> 可以是以下值:</p>

<dl>
 <dt><code>scroll-position</code></dt>
 <dd>表示开发者希望在不久后改变滚动条的位置或者使之产生动画。</dd>
 <dt><code>contents</code></dt>
 <dd>表示开发者希望在不久后改变元素内容中的某些东西,或者使它们产生动画。</dd>
 <dt><code>&lt;custom-ident&gt;</code></dt>
 <dd>表示开发者希望在不久后改变指定的属性名或者使之产生动画。如果属性名是简写,则代表所有与之对应的简写或者全写的属性。</dd>
</dl>

<h2 id="示例">示例</h2>

<pre class="brush: css">.sidebar {
  will-change: transform;
}
</pre>

<p>以上示例在样式表中直接添加了 <code>will-change</code> 属性,会导致浏览器将对应的优化工作一直保存在内存中,这其实是不必要的,前面我们已经看过为什么应该避免这样的做法。下面是另一个展示如何使用脚本正确地应用 <code>will-change</code> 属性的示例,在大部分的场景中,你都应该这样做。</p>

<pre class="brush: js">var el = document.getElementById('element');

// 当鼠标移动到该元素上时给该元素设置 will-change 属性
el.addEventListener('mouseenter', hintBrowser);
// 当 CSS 动画结束后清除 will-change 属性
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
  // 填写上那些你知道的,会在 CSS 动画中发生改变的 CSS 属性名们
  this.style.willChange = 'transform, opacity';
}

function removeHint() {
  this.style.willChange = 'auto';
}</pre>

<p>但是,如果某个应用在按下键盘的时候会翻页,比如相册或者幻灯片一类的,它的页面很大很复杂,此时在样式表中写上 <code>will-change</code> 是合适的。这会使浏览器提前准备好过渡动画,当键盘按下的时候就能立即看到灵活轻快的动画。</p>

<pre class="brush: css">.slide {
  will-change: transform;
}</pre>

<h2 id="参考">参考</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{ SpecName('CSS Will Change', '#will-change', 'will-change') }}</td>
   <td>{{ Spec2('CSS Will Change') }}</td>
   <td>Initial definition</td>
  </tr>
 </tbody>
</table>

<h2 id="浏览器兼容">浏览器兼容</h2>

<p>{{ CompatibilityTable() }}</p>

<div id="compat-desktop">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Chrome</th>
   <th>Firefox (Gecko)</th>
   <th>Internet Explorer</th>
   <th>Opera</th>
   <th>Safari (WebKit)</th>
  </tr>
  <tr>
   <td>Basic support</td>
   <td>{{CompatChrome(36)}}</td>
   <td>{{CompatGeckoDesktop(36)}} [1]</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatOpera(24)}}</td>
   <td>{{CompatNo}}</td>
  </tr>
 </tbody>
</table>
</div>

<div id="compat-mobile">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Android</th>
   <th>Firefox Mobile (Gecko)</th>
   <th>IE Phone</th>
   <th>Opera Mobile</th>
   <th>Safari Mobile</th>
  </tr>
  <tr>
   <td>Basic support</td>
   <td>37</td>
   <td>{{CompatGeckoMobile(36)}} [1]</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
  </tr>
 </tbody>
</table>
</div>

<p>[1] 在 Firefox 31 到 35 中,需要在 <code>about:config</code> 中开启 <code>layout.css.will-change.enabled</code> 选项。</p>