mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
feat(header, footer): add ios fading header style (#24011)
This commit is contained in:
@ -519,13 +519,13 @@ export class IonFabList {
|
||||
|
||||
export declare interface IonFooter extends Components.IonFooter {}
|
||||
@ProxyCmp({
|
||||
inputs: ['mode', 'translucent']
|
||||
inputs: ['collapse', 'mode', 'translucent']
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-footer',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
inputs: ['mode', 'translucent']
|
||||
inputs: ['collapse', 'mode', 'translucent']
|
||||
})
|
||||
export class IonFooter {
|
||||
protected el: HTMLElement;
|
||||
|
@ -463,6 +463,7 @@ ion-fab-list,prop,activated,boolean,false,false,false
|
||||
ion-fab-list,prop,side,"bottom" | "end" | "start" | "top",'bottom',false,false
|
||||
|
||||
ion-footer,none
|
||||
ion-footer,prop,collapse,"fade" | undefined,undefined,false,false
|
||||
ion-footer,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-footer,prop,translucent,boolean,false,false,false
|
||||
|
||||
@ -482,7 +483,7 @@ ion-grid,css-prop,--ion-grid-width-xl
|
||||
ion-grid,css-prop,--ion-grid-width-xs
|
||||
|
||||
ion-header,none
|
||||
ion-header,prop,collapse,"condense" | undefined,undefined,false,false
|
||||
ion-header,prop,collapse,"condense" | "fade" | undefined,undefined,false,false
|
||||
ion-header,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-header,prop,translucent,boolean,false,false,false
|
||||
|
||||
|
16
core/src/components.d.ts
vendored
16
core/src/components.d.ts
vendored
@ -920,6 +920,10 @@ export namespace Components {
|
||||
"side": 'start' | 'end' | 'top' | 'bottom';
|
||||
}
|
||||
interface IonFooter {
|
||||
/**
|
||||
* Describes the scroll effect that will be applied to the footer. Only applies in iOS mode.
|
||||
*/
|
||||
"collapse"?: 'fade';
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
@ -937,9 +941,9 @@ export namespace Components {
|
||||
}
|
||||
interface IonHeader {
|
||||
/**
|
||||
* Describes the scroll effect that will be applied to the header `condense` only applies in iOS mode. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
|
||||
* Describes the scroll effect that will be applied to the header. Only applies in iOS mode. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
|
||||
*/
|
||||
"collapse"?: 'condense';
|
||||
"collapse"?: 'condense' | 'fade';
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
@ -4606,6 +4610,10 @@ declare namespace LocalJSX {
|
||||
"side"?: 'start' | 'end' | 'top' | 'bottom';
|
||||
}
|
||||
interface IonFooter {
|
||||
/**
|
||||
* Describes the scroll effect that will be applied to the footer. Only applies in iOS mode.
|
||||
*/
|
||||
"collapse"?: 'fade';
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
@ -4623,9 +4631,9 @@ declare namespace LocalJSX {
|
||||
}
|
||||
interface IonHeader {
|
||||
/**
|
||||
* Describes the scroll effect that will be applied to the header `condense` only applies in iOS mode. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
|
||||
* Describes the scroll effect that will be applied to the header. Only applies in iOS mode. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
|
||||
*/
|
||||
"collapse"?: 'condense';
|
||||
"collapse"?: 'condense' | 'fade';
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
|
@ -24,3 +24,10 @@
|
||||
.footer-ios.ion-no-border ion-toolbar:first-of-type {
|
||||
--border-width: 0;
|
||||
}
|
||||
|
||||
// iOS Footer - Collapse Fade
|
||||
// --------------------------------------------------
|
||||
|
||||
.footer-collapse-fade ion-toolbar {
|
||||
--opacity-scale: inherit;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core';
|
||||
import { Component, ComponentInterface, Element, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { componentOnReady } from '../../utils/helpers';
|
||||
|
||||
import { handleFooterFade } from './footer.utils';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
@ -13,6 +16,16 @@ import { getIonMode } from '../../global/ionic-global';
|
||||
}
|
||||
})
|
||||
export class Footer implements ComponentInterface {
|
||||
private scrollEl?: HTMLElement;
|
||||
private contentScrollCallback: any;
|
||||
|
||||
@Element() el!: HTMLIonFooterElement;
|
||||
|
||||
/**
|
||||
* Describes the scroll effect that will be applied to the footer.
|
||||
* Only applies in iOS mode.
|
||||
*/
|
||||
@Prop() collapse?: 'fade';
|
||||
|
||||
/**
|
||||
* If `true`, the footer will be translucent.
|
||||
@ -24,9 +37,56 @@ export class Footer implements ComponentInterface {
|
||||
*/
|
||||
@Prop() translucent = false;
|
||||
|
||||
render() {
|
||||
componentDidLoad() {
|
||||
this.checkCollapsibleFooter();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.checkCollapsibleFooter();
|
||||
}
|
||||
|
||||
private checkCollapsibleFooter = () => {
|
||||
const mode = getIonMode(this);
|
||||
if (mode !== 'ios') { return; }
|
||||
|
||||
const { collapse } = this;
|
||||
const hasFade = collapse === 'fade';
|
||||
|
||||
this.destroyCollapsibleFooter();
|
||||
|
||||
if (hasFade) {
|
||||
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
|
||||
const contentEl = (pageEl) ? pageEl.querySelector('ion-content') : null;
|
||||
|
||||
this.setupFadeFooter(contentEl);
|
||||
}
|
||||
}
|
||||
|
||||
private setupFadeFooter = async (contentEl: HTMLIonContentElement | null) => {
|
||||
if (!contentEl) { console.error('ion-footer requires a content to collapse. Make sure there is an ion-content.'); return; }
|
||||
|
||||
await new Promise(resolve => componentOnReady(contentEl, resolve));
|
||||
const scrollEl = this.scrollEl = await contentEl.getScrollElement();
|
||||
|
||||
/**
|
||||
* Handle fading of toolbars on scroll
|
||||
*/
|
||||
this.contentScrollCallback = () => { handleFooterFade(scrollEl, this.el); };
|
||||
scrollEl.addEventListener('scroll', this.contentScrollCallback);
|
||||
|
||||
handleFooterFade(scrollEl, this.el);
|
||||
}
|
||||
|
||||
private destroyCollapsibleFooter() {
|
||||
if (this.scrollEl && this.contentScrollCallback) {
|
||||
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
|
||||
this.contentScrollCallback = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { translucent, collapse } = this;
|
||||
const mode = getIonMode(this);
|
||||
const translucent = this.translucent;
|
||||
return (
|
||||
<Host
|
||||
role="contentinfo"
|
||||
@ -38,6 +98,8 @@ export class Footer implements ComponentInterface {
|
||||
|
||||
[`footer-translucent`]: translucent,
|
||||
[`footer-translucent-${mode}`]: translucent,
|
||||
|
||||
[`footer-collapse-${collapse}`]: collapse !== undefined,
|
||||
}}
|
||||
>
|
||||
{ mode === 'ios' && translucent &&
|
||||
|
36
core/src/components/footer/footer.utils.ts
Normal file
36
core/src/components/footer/footer.utils.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { readTask, writeTask } from '@stencil/core';
|
||||
|
||||
import { clamp } from '../../utils/helpers';
|
||||
|
||||
export const handleFooterFade = (scrollEl: HTMLElement, baseEl: HTMLElement) => {
|
||||
readTask(() => {
|
||||
const scrollTop = scrollEl.scrollTop;
|
||||
const maxScroll = scrollEl.scrollHeight - scrollEl.clientHeight;
|
||||
|
||||
/**
|
||||
* Toolbar background will fade
|
||||
* out over fadeDuration in pixels.
|
||||
*/
|
||||
const fadeDuration = 10;
|
||||
|
||||
/**
|
||||
* Begin fading out maxScroll - 30px
|
||||
* from the bottom of the content.
|
||||
* Also determine how close we are
|
||||
* to starting the fade. If we are
|
||||
* before the starting point, the
|
||||
* scale value will get clamped to 0.
|
||||
* If we are after the maxScroll (rubber
|
||||
* band scrolling), the scale value will
|
||||
* get clamped to 1.
|
||||
*/
|
||||
const fadeStart = maxScroll - fadeDuration;
|
||||
const distanceToStart = scrollTop - fadeStart;
|
||||
|
||||
const scale = clamp(0, 1 - (distanceToStart / fadeDuration), 1);
|
||||
|
||||
writeTask(() => {
|
||||
baseEl.style.setProperty('--opacity-scale', scale.toString());
|
||||
})
|
||||
});
|
||||
}
|
@ -3,6 +3,10 @@
|
||||
Footer is a root component of a page that sits at the bottom of the page.
|
||||
Footer can be a wrapper for ion-toolbar to make sure the content area is sized correctly.
|
||||
|
||||
## Fade Footer
|
||||
|
||||
The `collapse` property can be set to `'fade'` on a page's `ion-footer` to have the background color of the toolbars fade in as users scroll. This provides the same fade effect that is found in many native iOS applications.
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
@ -25,6 +29,13 @@ Footer can be a wrapper for ion-toolbar to make sure the content area is sized c
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
<!-- Fade Footer -->
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
```
|
||||
|
||||
|
||||
@ -50,6 +61,13 @@ export const FooterExample: React.FC = () => (
|
||||
<IonTitle>Footer</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonFooter>
|
||||
|
||||
{/*-- Fade Footer --*/}
|
||||
<IonFooter collapse="fade">
|
||||
<IonToolbar>
|
||||
<IonTitle>Footer</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonFooter>
|
||||
</>
|
||||
);
|
||||
```
|
||||
@ -69,7 +87,7 @@ export class FooterExample {
|
||||
return [
|
||||
<ion-content></ion-content>,
|
||||
|
||||
// Footer without a border
|
||||
{/*-- Footer without a border --*/}
|
||||
<ion-footer class="ion-no-border">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer - No Border</ion-title>
|
||||
@ -80,6 +98,13 @@ export class FooterExample {
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>,
|
||||
|
||||
{/*-- Fade Footer --*/}
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
];
|
||||
}
|
||||
@ -105,6 +130,13 @@ export class FooterExample {
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
<!-- Fade Footer -->
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -122,7 +154,8 @@ export default defineComponent({
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ----------- |
|
||||
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----------- |
|
||||
| `collapse` | `collapse` | Describes the scroll effect that will be applied to the footer. Only applies in iOS mode. | `"fade" \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `translucent` | `translucent` | If `true`, the footer will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). Note: In order to scroll content behind the footer, the `fullscreen` attribute needs to be set on the content. | `boolean` | `false` |
|
||||
|
||||
|
10
core/src/components/footer/test/fade/e2e.ts
Normal file
10
core/src/components/footer/test/fade/e2e.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
test('footer: fade', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/footer/test/fade?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
89
core/src/components/footer/test/fade/index.html
Normal file
89
core/src/components/footer/test/fade/index.html
Normal file
@ -0,0 +1,89 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Footer - Fade</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<style>
|
||||
.red {
|
||||
background-color: #ea445a;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #76d672;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background-color: #3478f6;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
background-color: #ffff80;
|
||||
}
|
||||
|
||||
.pink {
|
||||
background-color: #ff6b86;
|
||||
}
|
||||
|
||||
.purple {
|
||||
background-color: #7e34f6;
|
||||
}
|
||||
|
||||
.black {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.orange {
|
||||
background-color: #f69234;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
<div class="ion-page">
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Mailboxes</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Mailboxes</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<div class="grid ion-padding">
|
||||
<div class="grid-item red"></div>
|
||||
<div class="grid-item green"></div>
|
||||
<div class="grid-item blue"></div>
|
||||
<div class="grid-item yellow"></div>
|
||||
<div class="grid-item pink"></div>
|
||||
<div class="grid-item purple"></div>
|
||||
<div class="grid-item black"></div>
|
||||
<div class="grid-item orange"></div>
|
||||
</div>
|
||||
</ion-content>
|
||||
<ion-footer collapse="fade" translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Updated Just Now</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
</div>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
@ -13,4 +13,11 @@
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
<!-- Fade Footer -->
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
```
|
||||
|
@ -13,4 +13,11 @@
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
<!-- Fade Footer -->
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
```
|
||||
|
@ -18,6 +18,13 @@ export const FooterExample: React.FC = () => (
|
||||
<IonTitle>Footer</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonFooter>
|
||||
|
||||
{/*-- Fade Footer --*/}
|
||||
<IonFooter collapse="fade">
|
||||
<IonToolbar>
|
||||
<IonTitle>Footer</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonFooter>
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
@ -10,7 +10,7 @@ export class FooterExample {
|
||||
return [
|
||||
<ion-content></ion-content>,
|
||||
|
||||
// Footer without a border
|
||||
{/*-- Footer without a border --*/}
|
||||
<ion-footer class="ion-no-border">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer - No Border</ion-title>
|
||||
@ -21,6 +21,13 @@ export class FooterExample {
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>,
|
||||
|
||||
{/*-- Fade Footer --*/}
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
];
|
||||
}
|
||||
|
@ -14,6 +14,13 @@
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
<!-- Fade Footer -->
|
||||
<ion-footer collapse="fade">
|
||||
<ion-toolbar>
|
||||
<ion-title>Footer</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -33,7 +33,13 @@
|
||||
--border-width: 0;
|
||||
}
|
||||
|
||||
// iOS Header - Collapse
|
||||
// iOS Header - Collapse Fade
|
||||
// --------------------------------------------------
|
||||
.header-collapse-fade ion-toolbar {
|
||||
--opacity-scale: inherit;
|
||||
}
|
||||
|
||||
// iOS Header - Collapse Condense
|
||||
// --------------------------------------------------
|
||||
.header-collapse-condense {
|
||||
z-index: 9;
|
||||
@ -71,6 +77,15 @@
|
||||
padding-bottom: 13px;
|
||||
}
|
||||
|
||||
|
||||
.header-collapse-main {
|
||||
--opacity-scale: 1;
|
||||
}
|
||||
|
||||
.header-collapse-main ion-toolbar {
|
||||
--opacity-scale: inherit;
|
||||
}
|
||||
|
||||
.header-collapse-main ion-toolbar.in-toolbar ion-title,
|
||||
.header-collapse-main ion-toolbar.in-toolbar ion-buttons {
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Component, ComponentInterface, Element, Host, Prop, h, writeTask } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { inheritAttributes } from '../../utils/helpers';
|
||||
import { componentOnReady, inheritAttributes } from '../../utils/helpers';
|
||||
|
||||
import { cloneElement, createHeaderIndex, handleContentScroll, handleToolbarIntersection, setHeaderActive, setToolbarBackgroundOpacity } from './header.utils';
|
||||
import { cloneElement, createHeaderIndex, handleContentScroll, handleHeaderFade, handleToolbarIntersection, setHeaderActive, setToolbarBackgroundOpacity } from './header.utils';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
@ -16,8 +16,6 @@ import { cloneElement, createHeaderIndex, handleContentScroll, handleToolbarInte
|
||||
}
|
||||
})
|
||||
export class Header implements ComponentInterface {
|
||||
|
||||
private collapsibleHeaderInitialized = false;
|
||||
private scrollEl?: HTMLElement;
|
||||
private contentScrollCallback?: any;
|
||||
private intersectionObserver?: any;
|
||||
@ -27,12 +25,12 @@ export class Header implements ComponentInterface {
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* Describes the scroll effect that will be applied to the header
|
||||
* `condense` only applies in iOS mode.
|
||||
* Describes the scroll effect that will be applied to the header.
|
||||
* Only applies in iOS mode.
|
||||
*
|
||||
* Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
|
||||
*/
|
||||
@Prop() collapse?: 'condense';
|
||||
@Prop() collapse?: 'condense' | 'fade';
|
||||
|
||||
/**
|
||||
* If `true`, the header will be translucent.
|
||||
@ -48,12 +46,12 @@ export class Header implements ComponentInterface {
|
||||
this.inheritedAttributes = inheritAttributes(this.el, ['role']);
|
||||
}
|
||||
|
||||
async componentDidLoad() {
|
||||
await this.checkCollapsibleHeader();
|
||||
componentDidLoad() {
|
||||
this.checkCollapsibleHeader();
|
||||
}
|
||||
|
||||
async componentDidUpdate() {
|
||||
await this.checkCollapsibleHeader();
|
||||
componentDidUpdate() {
|
||||
this.checkCollapsibleHeader();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
@ -61,13 +59,17 @@ export class Header implements ComponentInterface {
|
||||
}
|
||||
|
||||
private async checkCollapsibleHeader() {
|
||||
const mode = getIonMode(this);
|
||||
|
||||
if (mode !== 'ios') { return; }
|
||||
|
||||
const { collapse } = this;
|
||||
const hasCondense = collapse === 'condense';
|
||||
const hasFade = collapse === 'fade';
|
||||
|
||||
// Determine if the header can collapse
|
||||
const hasCollapse = this.collapse === 'condense';
|
||||
const canCollapse = (hasCollapse && getIonMode(this) === 'ios') ? hasCollapse : false;
|
||||
if (!canCollapse && this.collapsibleHeaderInitialized) {
|
||||
this.destroyCollapsibleHeader();
|
||||
} else if (canCollapse && !this.collapsibleHeaderInitialized) {
|
||||
|
||||
if (hasCondense) {
|
||||
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
|
||||
const contentEl = (pageEl) ? pageEl.querySelector('ion-content') : null;
|
||||
|
||||
@ -78,10 +80,31 @@ export class Header implements ComponentInterface {
|
||||
cloneElement('ion-back-button');
|
||||
});
|
||||
|
||||
await this.setupCollapsibleHeader(contentEl, pageEl);
|
||||
await this.setupCondenseHeader(contentEl, pageEl);
|
||||
} else if (hasFade) {
|
||||
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
|
||||
const contentEl = (pageEl) ? pageEl.querySelector('ion-content') : null;
|
||||
const condenseHeader = (contentEl) ? contentEl.querySelector('ion-header[collapse="condense"]') as HTMLElement | null : null;
|
||||
await this.setupFadeHeader(contentEl, condenseHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private setupFadeHeader = async (contentEl: HTMLIonContentElement | null, condenseHeader: HTMLElement | null) => {
|
||||
if (!contentEl) { console.error('ion-header requires a content to collapse. Make sure there is an ion-content.'); return; }
|
||||
|
||||
await new Promise(resolve => componentOnReady(contentEl, resolve));
|
||||
const scrollEl = this.scrollEl = await contentEl.getScrollElement();
|
||||
|
||||
/**
|
||||
* Handle fading of toolbars on scroll
|
||||
*/
|
||||
|
||||
this.contentScrollCallback = () => { handleHeaderFade(this.scrollEl!, this.el, condenseHeader); };
|
||||
scrollEl!.addEventListener('scroll', this.contentScrollCallback);
|
||||
|
||||
handleHeaderFade(this.scrollEl!, this.el, condenseHeader);
|
||||
}
|
||||
|
||||
private destroyCollapsibleHeader() {
|
||||
if (this.intersectionObserver) {
|
||||
this.intersectionObserver.disconnect();
|
||||
@ -99,10 +122,11 @@ export class Header implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
private async setupCollapsibleHeader(contentEl: HTMLIonContentElement | null, pageEl: Element | null) {
|
||||
private async setupCondenseHeader(contentEl: HTMLIonContentElement | null, pageEl: Element | null) {
|
||||
if (!contentEl || !pageEl) { console.error('ion-header requires a content to collapse, make sure there is an ion-content.'); return; }
|
||||
if (typeof (IntersectionObserver as any) === 'undefined') { return; }
|
||||
|
||||
await new Promise(resolve => componentOnReady(contentEl, resolve));
|
||||
this.scrollEl = await contentEl.getScrollElement();
|
||||
|
||||
const headers = pageEl.querySelectorAll('ion-header');
|
||||
@ -116,10 +140,7 @@ export class Header implements ComponentInterface {
|
||||
if (!mainHeaderIndex || !scrollHeaderIndex) { return; }
|
||||
|
||||
setHeaderActive(mainHeaderIndex, false);
|
||||
|
||||
mainHeaderIndex.toolbars.forEach(toolbar => {
|
||||
setToolbarBackgroundOpacity(toolbar, 0);
|
||||
});
|
||||
setToolbarBackgroundOpacity(mainHeaderIndex.el, 0);
|
||||
|
||||
/**
|
||||
* Handle interaction between toolbar collapse and
|
||||
@ -145,8 +166,6 @@ export class Header implements ComponentInterface {
|
||||
this.collapsibleMainHeader.classList.add('header-collapse-main');
|
||||
}
|
||||
});
|
||||
|
||||
this.collapsibleHeaderInitialized = true;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -5,7 +5,7 @@ import { clamp } from '../../utils/helpers';
|
||||
const TRANSITION = 'all 0.2s ease-in-out';
|
||||
|
||||
interface HeaderIndex {
|
||||
el: HTMLElement;
|
||||
el: HTMLIonHeaderElement;
|
||||
toolbars: ToolbarIndex[] | [];
|
||||
}
|
||||
|
||||
@ -64,11 +64,19 @@ export const handleContentScroll = (scrollEl: HTMLElement, scrollHeaderIndex: He
|
||||
});
|
||||
};
|
||||
|
||||
export const setToolbarBackgroundOpacity = (toolbar: ToolbarIndex, opacity?: number) => {
|
||||
export const setToolbarBackgroundOpacity = (headerEl: HTMLIonHeaderElement, opacity?: number) => {
|
||||
/**
|
||||
* Fading in the backdrop opacity
|
||||
* should happen after the large title
|
||||
* has collapsed, so it is handled
|
||||
* by handleHeaderFade()
|
||||
*/
|
||||
if (headerEl.collapse === 'fade') { return; }
|
||||
|
||||
if (opacity === undefined) {
|
||||
toolbar.background.style.removeProperty('--opacity');
|
||||
headerEl.style.removeProperty('--opacity-scale');
|
||||
} else {
|
||||
toolbar.background.style.setProperty('--opacity', opacity.toString());
|
||||
headerEl.style.setProperty('--opacity-scale', opacity.toString());
|
||||
}
|
||||
};
|
||||
|
||||
@ -88,9 +96,7 @@ const handleToolbarBorderIntersection = (ev: any, mainHeaderIndex: HeaderIndex,
|
||||
*/
|
||||
const scale = (ev[0].intersectionRatio > 0.9 || scrollTop <= 0) ? 0 : ((1 - ev[0].intersectionRatio) * 100) / 75;
|
||||
|
||||
mainHeaderIndex.toolbars.forEach(toolbar => {
|
||||
setToolbarBackgroundOpacity(toolbar, (scale === 1) ? undefined : scale);
|
||||
});
|
||||
setToolbarBackgroundOpacity(mainHeaderIndex.el, (scale === 1) ? undefined : scale);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -136,7 +142,7 @@ export const handleToolbarIntersection = (ev: any, mainHeaderIndex: HeaderIndex,
|
||||
if (hasValidIntersection && scrollTop > 0) {
|
||||
setHeaderActive(mainHeaderIndex);
|
||||
setHeaderActive(scrollHeaderIndex, false);
|
||||
setToolbarBackgroundOpacity(mainHeaderIndex.toolbars[0]);
|
||||
setToolbarBackgroundOpacity(mainHeaderIndex.el);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -160,3 +166,37 @@ export const scaleLargeTitles = (toolbars: ToolbarIndex[] = [], scale = 1, trans
|
||||
titleDiv.style.transform = `scale3d(${scale}, ${scale}, 1)`;
|
||||
});
|
||||
};
|
||||
|
||||
export const handleHeaderFade = (scrollEl: HTMLElement, baseEl: HTMLElement, condenseHeader: HTMLElement | null) => {
|
||||
readTask(() => {
|
||||
const scrollTop = scrollEl.scrollTop;
|
||||
const baseElHeight = baseEl.clientHeight;
|
||||
const fadeStart = (condenseHeader) ? condenseHeader.clientHeight : 0;
|
||||
|
||||
/**
|
||||
* If we are using fade header with a condense
|
||||
* header, then the toolbar backgrounds should
|
||||
* not begin to fade in until the condense
|
||||
* header has fully collapsed.
|
||||
*
|
||||
* Additionally, the main content should not
|
||||
* overflow out of the container until the
|
||||
* condense header has fully collapsed. When
|
||||
* using just the condense header the content
|
||||
* should overflow out of the container.
|
||||
*/
|
||||
if ((condenseHeader !== null) && (scrollTop < fadeStart)) {
|
||||
baseEl.style.setProperty('--opacity-scale', '0');
|
||||
scrollEl.style.setProperty('clip-path', `inset(${baseElHeight}px 0px 0px 0px)`);
|
||||
return;
|
||||
}
|
||||
|
||||
const distanceToStart = scrollTop - fadeStart;
|
||||
const fadeDuration = 10;
|
||||
const scale = clamp(0, (distanceToStart / fadeDuration), 1);
|
||||
writeTask(() => {
|
||||
scrollEl.style.removeProperty('clip-path');
|
||||
baseEl.style.setProperty('--opacity-scale', scale.toString());
|
||||
})
|
||||
});
|
||||
}
|
||||
|
@ -3,6 +3,11 @@
|
||||
Header is a parent component that holds the toolbar component.
|
||||
It's important to note that ion-header needs to be the one of the three root elements of a page
|
||||
|
||||
## Fade Header
|
||||
|
||||
The `collapse` property can be set to `'fade'` on a page's main `ion-header` to have the background color of the toolbars fade in as users scroll. This provides the same fade effect that is found in many native iOS applications.
|
||||
|
||||
This functionality can be combined with [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles) as well. The `collapse="condense"` value should be set on the `ion-header` inside of your `ion-content`. The `collapse="fade"` value should be set on the `ion-header` outside of your `ion-content`.
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
@ -10,7 +15,7 @@ It's important to note that ion-header needs to be the one of the three root ele
|
||||
|
||||
## Usage
|
||||
|
||||
### Angular / javascript
|
||||
### Angular
|
||||
|
||||
```html
|
||||
<ion-header>
|
||||
@ -40,6 +45,69 @@ It's important to note that ion-header needs to be the one of the three root ele
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
|
||||
<!-- Fade Header with collapse header -->
|
||||
<ion-header collapse="fade" [translucent]="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content [fullscreen]="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
|
||||
```html
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>My Navigation Bar</ion-title>
|
||||
</ion-toolbar>
|
||||
|
||||
<ion-toolbar>
|
||||
<ion-title>Subheader</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<!-- Header without a border -->
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header - No Border</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">My Navigation Bar</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
|
||||
<!-- Fade Header with collapse header -->
|
||||
<ion-header collapse="fade" translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
|
||||
@ -78,6 +146,21 @@ export const HeaderExample: React.FC = () => (
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
</IonContent>
|
||||
|
||||
{/*-- Fade Header with collapse header --*/}
|
||||
<IonHeader collapse="fade" translucent={true}>
|
||||
<IonToolbar>
|
||||
<IonTitle>Header</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
<IonContent fullscreen={true}>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Header</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
</IonContent>
|
||||
</>
|
||||
);
|
||||
```
|
||||
@ -108,7 +191,7 @@ export class HeaderExample {
|
||||
</ion-toolbar>
|
||||
</ion-header>,
|
||||
|
||||
// Header without a border
|
||||
{/*-- Header without a border --*/}
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header - No Border</ion-title>
|
||||
@ -121,6 +204,21 @@ export class HeaderExample {
|
||||
<ion-title size="large">My Navigation Bar</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>,
|
||||
|
||||
{/*-- Fade Header with collapse header --*/}
|
||||
<ion-header collapse="fade" translucent={true}>
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content fullscreen={true}>
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
];
|
||||
}
|
||||
@ -159,6 +257,21 @@ export class HeaderExample {
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
|
||||
<!-- Fade Header with collapse header -->
|
||||
<ion-header collapse="fade" :translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content :fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -190,8 +303,8 @@ export default defineComponent({
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ----------- |
|
||||
| `collapse` | `collapse` | Describes the scroll effect that will be applied to the header `condense` only applies in iOS mode. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles) | `"condense" \| undefined` | `undefined` |
|
||||
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ----------- |
|
||||
| `collapse` | `collapse` | Describes the scroll effect that will be applied to the header. Only applies in iOS mode. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles) | `"condense" \| "fade" \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `translucent` | `translucent` | If `true`, the header will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). Note: In order to scroll content behind the header, the `fullscreen` attribute needs to be set on the content. | `boolean` | `false` |
|
||||
|
||||
|
10
core/src/components/header/test/fade/e2e.ts
Normal file
10
core/src/components/header/test/fade/e2e.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
test('header: fade', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/header/test/fade?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
89
core/src/components/header/test/fade/index.html
Normal file
89
core/src/components/header/test/fade/index.html
Normal file
@ -0,0 +1,89 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Header - Fade</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<style>
|
||||
.red {
|
||||
background-color: #ea445a;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #76d672;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background-color: #3478f6;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
background-color: #ffff80;
|
||||
}
|
||||
|
||||
.pink {
|
||||
background-color: #ff6b86;
|
||||
}
|
||||
|
||||
.purple {
|
||||
background-color: #7e34f6;
|
||||
}
|
||||
|
||||
.black {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.orange {
|
||||
background-color: #f69234;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
<div class="ion-page">
|
||||
<ion-header collapse="fade" translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Mailboxes</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Mailboxes</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<div class="grid ion-padding">
|
||||
<div class="grid-item red"></div>
|
||||
<div class="grid-item green"></div>
|
||||
<div class="grid-item blue"></div>
|
||||
<div class="grid-item yellow"></div>
|
||||
<div class="grid-item pink"></div>
|
||||
<div class="grid-item purple"></div>
|
||||
<div class="grid-item black"></div>
|
||||
<div class="grid-item orange"></div>
|
||||
</div>
|
||||
</ion-content>
|
||||
<ion-footer translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Updated Just Now</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
</div>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
@ -26,4 +26,19 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
|
||||
<!-- Fade Header with collapse header -->
|
||||
<ion-header collapse="fade" [translucent]="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content [fullscreen]="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
```
|
||||
|
@ -26,4 +26,19 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
|
||||
<!-- Fade Header with collapse header -->
|
||||
<ion-header collapse="fade" translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
```
|
||||
|
@ -31,6 +31,21 @@ export const HeaderExample: React.FC = () => (
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
</IonContent>
|
||||
|
||||
{/*-- Fade Header with collapse header --*/}
|
||||
<IonHeader collapse="fade" translucent={true}>
|
||||
<IonToolbar>
|
||||
<IonTitle>Header</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
<IonContent fullscreen={true}>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Header</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
</IonContent>
|
||||
</>
|
||||
);
|
||||
```
|
@ -21,7 +21,7 @@ export class HeaderExample {
|
||||
</ion-toolbar>
|
||||
</ion-header>,
|
||||
|
||||
// Header without a border
|
||||
{/*-- Header without a border --*/}
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header - No Border</ion-title>
|
||||
@ -34,6 +34,21 @@ export class HeaderExample {
|
||||
<ion-title size="large">My Navigation Bar</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>,
|
||||
|
||||
{/*-- Fade Header with collapse header --*/}
|
||||
<ion-header collapse="fade" translucent={true}>
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content fullscreen={true}>
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
];
|
||||
}
|
||||
|
@ -27,6 +27,21 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
|
||||
<!-- Fade Header with collapse header -->
|
||||
<ion-header collapse="fade" :translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content :fullscreen="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -25,6 +25,7 @@
|
||||
--border-width: 0;
|
||||
--border-style: solid;
|
||||
--opacity: 1;
|
||||
--opacity-scale: 1;
|
||||
|
||||
@include font-smoothing();
|
||||
@include padding-horizontal(var(--ion-safe-area-left), var(--ion-safe-area-right));
|
||||
@ -91,7 +92,7 @@
|
||||
background: var(--background);
|
||||
|
||||
contain: strict;
|
||||
opacity: var(--opacity);
|
||||
opacity: calc(var(--opacity) * var(--opacity-scale));
|
||||
z-index: $z-index-toolbar-background;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -334,6 +334,7 @@ export const IonFabList = /*@__PURE__*/ defineContainer<JSX.IonFabList>('ion-fab
|
||||
|
||||
|
||||
export const IonFooter = /*@__PURE__*/ defineContainer<JSX.IonFooter>('ion-footer', IonFooterCmp, [
|
||||
'collapse',
|
||||
'translucent'
|
||||
]);
|
||||
|
||||
|
Reference in New Issue
Block a user