2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
5 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
6 Code distributed by Google as part of the polymer project is also
7 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
11 `core-scroll-header-panel` contains a header section and a content section. The
12 header is initially on the top part of the view but it scrolls away with the
13 rest of the scrollable content. Upon scrolling slightly up at any point, the
14 header scrolls back into view. This saves screen space and allows users to
15 access important controls by easily moving them back to the view.
17 __Important:__ The `core-scroll-header-panel` will not display if its parent does not have a height.
19 Using [layout attributes](http://www.polymer-project.org/docs/polymer/layout-attrs.html), you can easily make the `core-scroll-header-panel` fill the screen
21 <body fullbleed layout vertical>
22 <core-scroll-header-panel flex>
24 <div>Hello World!</div>
26 </core-scroll-header-panel>
29 or, if you would prefer to do it in CSS, just give `html`, `body`, and `core-scroll-header-panel` a height of 100%:
35 core-scroll-header-panel {
39 `core-scroll-header-panel` works well with `core-toolbar` but can use any element
40 that represents a header by adding a `core-header` class to it. Use the attribute
41 or class `content` to delineate the content section.
43 <core-scroll-header-panel>
44 <core-toolbar>Header</core-toolbar>
45 <div content>Content goes here...</div>
46 </core-scroll-header-panel>
48 @group Polymer Core Elements
49 @element core-scroll-header-panel
53 <link rel="import" href="../polymer/polymer.html">
55 <polymer-element name="core-scroll-header-panel">
58 <link rel="stylesheet" href="core-scroll-header-panel.css">
60 <div id="mainContainer" on-scroll="{{scroll}}">
62 <content id="mainContent" select="[content], .content"></content>
66 <div id="headerContainer">
68 <div class="bg-container">
69 <div id="condensedHeaderBg"></div>
70 <div id="headerBg"></div>
73 <content id="headerContent" select="core-toolbar, .core-header"></content>
80 Polymer('core-scroll-header-panel', {
83 * Fired when the content has been scrolled.
89 * Fired when the header is transformed.
91 * @event core-header-transform
96 * If true, the header's height will condense to `_condensedHeaderHeight`
97 * as the user scrolls down from the top of the content area.
99 * @attribute condenses
106 * If true, no cross-fade transition from one background to another.
108 * @attribute noDissolve
115 * If true, the header doesn't slide back in when scrolling back up.
117 * @attribute noReveal
124 * If true, the header is fixed to the top and never moves away.
133 * If true, the condensed header is always shown and does not move away.
135 * @attribute keepCondensedHeader
139 keepCondensedHeader: false,
142 * The height of the header when it is at its full size.
144 * By default, the height will be measured when it is ready. If the height
145 * changes later the user needs to either set this value to reflect the
146 * new height or invoke `measureHeaderHeight()`.
148 * @attribute headerHeight
154 * The height of the header when it is condensed.
156 * By default, `_condensedHeaderHeight` is 1/3 of `headerHeight` unless
159 * @attribute condensedHeaderHeight
162 condensedHeaderHeight: 0
172 'headerMargin fixed': 'setup'
175 domReady: function() {
176 this.async('measureHeaderHeight');
180 return this.$.headerContent.getDistributedNodes()[0];
184 return this.$.mainContainer;
187 measureHeaderHeight: function() {
188 var header = this.header;
190 this.headerHeight = header.offsetHeight;
194 headerHeightChanged: function() {
195 if (!this.condensedHeaderHeight) {
196 // assume _condensedHeaderHeight is 1/3 of the headerHeight
197 this._condensedHeaderHeight = this.headerHeight * 1 / 3;
199 this.condensedHeaderHeightChanged();
202 condensedHeaderHeightChanged: function() {
203 if (this.condensedHeaderHeight) {
204 this._condensedHeaderHeight = this.condensedHeaderHeight;
206 if (this.headerHeight) {
207 this.headerMargin = this.headerHeight - this._condensedHeaderHeight;
211 condensesChanged: function() {
212 if (this.condenses) {
215 // reset transform/opacity set on the header
216 this.condenseHeader(null);
221 var s = this.scroller.style;
222 s.paddingTop = this.fixed ? '' : this.headerHeight + 'px';
223 s.top = this.fixed ? this.headerHeight + 'px' : '';
225 this.transformHeader(null);
231 transformHeader: function(y) {
232 var s = this.$.headerContainer.style;
233 this.translateY(s, -y);
235 if (this.condenses) {
236 this.condenseHeader(y);
239 this.fire('core-header-transform', {y: y, height: this.headerHeight,
240 condensedHeight: this._condensedHeaderHeight});
243 condenseHeader: function(y) {
244 var reset = y == null;
245 // adjust top bar in core-header so the top bar stays at the top
246 if (this.header.$ && this.header.$.topBar) {
247 this.translateY(this.header.$.topBar.style,
248 reset ? null : Math.min(y, this.headerMargin));
250 // transition header bg
251 var hbg = this.$.headerBg.style;
252 if (!this.noDissolve) {
253 hbg.opacity = reset ? '' : (this.headerMargin - y) / this.headerMargin;
255 // adjust header bg so it stays at the center
256 this.translateY(hbg, reset ? null : y / 2);
257 // transition condensed header bg
258 var chbg = this.$.condensedHeaderBg.style;
259 if (!this.noDissolve) {
260 chbg = this.$.condensedHeaderBg.style;
261 chbg.opacity = reset ? '' : y / this.headerMargin;
262 // adjust condensed header bg so it stays at the center
263 this.translateY(chbg, reset ? null : y / 2);
267 translateY: function(s, y) {
268 s.transform = s.webkitTransform = y == null ? '' :
269 'translate3d(0, ' + y + 'px, 0)';
272 scroll: function(event) {
277 var sTop = this.scroller.scrollTop;
279 var y = Math.min(this.keepCondensedHeader ?
280 this.headerMargin : this.headerHeight, Math.max(0,
281 (this.noReveal ? sTop : this.y + sTop - this.prevScrollTop)));
283 if (this.condenses && this.prevScrollTop >= sTop && sTop > this.headerMargin) {
284 y = Math.max(y, this.headerMargin);
287 if (!event || !this.fixed && y !== this.y) {
288 requestAnimationFrame(this.transformHeader.bind(this, y));
291 this.prevScrollTop = sTop;
295 this.fire('scroll', {target: this.scroller}, this, false);