Lightning コンソール環境でのCustomLightningRecordPageTemplateの高度なカスタマイズ(scroll,flex)

<section><h1>・　シナリオ・要件</h1>
<strong>標準LightningRecordPageTemplate(ヘッダーと右サイドバー)を参考にして</strong>
<ul><li>画面イメージ
![ヘッダーサブヘッダーと右サイドバー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447529/84175337-5b5b-3274-bada-e6d152c0666b.png)
<strong>ブラウザ側のスクロールを消し、全画面でtemplate側のスクロール一つだけある
サブヘッダーはいくらスクロールしても画面の特定位置にある
サブヘッダーの表示サイズと表示非表示をコントロールできる</strong>
<li><h1>Lightning Consoleアプリでの画面イメージ</h1></li>
<p>ブラウザのzoomサイズをいくら変えてもブラウザ側のスクロールは出てこなくて、テンプレートのスクロールしかありません。</p>
![customTemplate_Scroll1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447529/c344a108-e21e-88dc-f84c-c809e060c472.png)
<p>画面を下にスクロールすると、サブヘッダーが画面の特定位置に固定できます。</p>
![customTemplate_Scroll2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447529/d1215ae7-edfe-9415-5c09-a35c7f9fa983.png)
<p>サブヘッダーの表示サイズをコントロールできます。</p>
![customTemplate_Scroll3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447529/a841477e-46cf-5de2-02d4-73b8c9fc3df4.png)
<p>ボタンでサブヘッダーの表示非表示をコントロールできます。</p>
![customTemplate_Scroll4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447529/04d3c72b-0576-dc58-fe7f-baad7641988d.png)

<ul><li><h4>有効ブラウザ</h4></li></ul>
Chrome,Edgeの最新版しかテストしていないです。
最新版のChrome,Edge 👌
<h1>・　事前準備</h1>
<li>＜Salesforce＞custom page templateのカスタマイズ</h4></header><footer>参考：<a href="https://developer.salesforce.com/docs/atlas.enus.lightning.meta/lightning/components_config_for_app_builder_template_component.htm">create Lightning Page Template</a></li>
<li><h4>＜CSS、SLDS＞ブラウザ側のスクロール消し、template側にスクロール配置</h4></li>
＜CSS＞
```position:absolute;```
```display:flex;```
```box-sizing: border-box;```
```height:100%;width:100%;```
```overflow-y:auto```
OR ＜SLDS＞
```slds-is-absolute```
```slds-grid```
```slds-scrollable```
```box-sizing: border-box;```
```height:100%;width:100%;```
OR ＜SLDS＞
```slds-modal__container```
<strong>```slds-modal__content```</strong>(スクロール自動的に配置できる、わざとCSSを書けなくてもいいです。)
参考：
<a href="https://developer.mozilla.org/ja/docs/Web/CSS/flex">flexについて</a>
<a href="https://developer.mozilla.org/ja/docs/Web/CSS/overflow">スクロールについて</a>
<a href="https://www.lightningdesignsystem.com/utilities/position/#site-main-content">SLDS positionについ</a>
<a href="https://www.lightningdesignsystem.com/utilities/grid/#site-main-content">SLDS gridについて</a>
<a href="https://www.lightningdesignsystem.com/components/modals/#site-main-content">SLDS modalについて</a>
<a href="https://www.lightningdesignsystem.com/utilities/scrollable/#site-main-content">SLDS スクロールについて</a>
<li><h4>＜Javascript or jQuery(ここでJavascript)＞サブヘッダーはいくらスクロールしても画面の特定位置にある</h4</li>
```element.clientHeight
element.scrollTop
```
<div>![HTML scrollTop clientHeight offSetTop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447529/c551535b-72f9-48bb-1355-320e4b688dc4.png)</div>
<li><h1>コード実装</h1></li>

```html:CustomPageTemplate1.cmp
<aura:component implements="lightning:recordHomeTemplate">
<aura:attribute name="top" type="Aura.component[]"></aura:attribute>
<aura:attribute name="middle" type="Aura.component[]"></aura:attribute>
<aura:attribute name="middle_Path" type="Aura.component[]"></aura:attribute>
<aura:attribute name="bottom_left" type="Aura.component[]"></aura:attribute>
<aura:attribute name="bottom_right" type="Aura.component[]"></aura:attribute>
<aura:attribute name="scrollFlag" type="Boolean" default="true"></aura:attribute>
<aura:attribute name="middleSize" type="String" default="small"></aura:attribute>
<aura:attribute name="middleSizeNumber" type="String" default="8"></aura:attribute>
<aura:attribute name="middleSizeBar" type="Boolean" default="true"></aura:attribute>
<aura:handler name="init" value="{!this}" action="{!c.handleInit}"></aura:handler>
<aura:handler name="change" value="{!v.scrollFlag}" action="{!c.handleCssRerender}"></aura:handler>
<aura:handler name="change" value="{!v.middleSize}" action="{!c.handleMidControllerRerender}"></aura:handler>

<div class="slds-modal slds-fade-in-open slds-modal_large" style="z-index:initial;position:absolute;">
                        <div class="slds-modal__container"
                            style="margin: 0;padding:0;width:100%;height:calc(100% + var(--lwc-templateGutters,0));">
                            <div class="slds-modal__content" onscroll="{!c.handleScroll}" style="background-color: transparent;">
                                <lightning:layout multipleRows="true">
                                    <lightning:layoutItem size="12" class="slds-m-bottom_small">
                                        <div aura:id="topDiv">
                                            {!v.top}
                                        </div>
                                    </lightning:layoutItem>
                                    <lightning:layoutItem size="12">
                                        <lightning:layout multipleRows="true">
                                            <lightning:layoutItem size="12">
                                                <div class="slds-slider slds-size_x-small" aura:id="middleSizeController">
                                                    <span role="button" data-id="middleSlider"
                                                        class="slds-slider__value slds-badge slds-theme_error" aria-hidden="true"
                                                        onclick="{!c.handleSizeLabel}"><a href="javascript:void(0)"
                                                            style="text-decoration: none;"
                                                            title="クリックすると、サイズバーが最小化になる。">{!v.middleSize}</a></span>
                                                    <input type="range" aura:id="midlleSizeInput" class="slds-slider__range" min="6"
                                                        max="10" value="{!v.middleSizeNumber}" onchange="{!c.handleSlider}" />
                                                </div>
                                                <div aura:id="middleDiv">
                                                    {!v.middle}
                                                </div>
                                            </lightning:layoutItem>
                                            <lightning:layoutItem size="12">
                                                <div aura:id="pathDiv">
                                                    {!v.middle_Path}
                                                </div>
                                            </lightning:layoutItem>
                                            <lightning:layoutItem size="12">
                                                <lightning:layout>
                                                    <lightning:layoutItem size="{!$Browser.isDesktop ? '8' : '12'}"
                                                        flexibility="auto,no-grow" class="slds-m-right_small">
                                                        <div aura:id="bottom_left" class="bottom_left">
                                                            {!v.bottom_left}
                                                        </div>
                                                    </lightning:layoutItem>
                                                    <lightning:layoutItem size="{!$Browser.isDesktop ? '4' : '12'}">
                                                        <div aura:id="bottom_right" class="bottom_right slds-m-right_small">
                                                            {!v.bottom_right}
                                                        </div>
                                                    </lightning:layoutItem>
                                                </lightning:layout>
                                            </lightning:layoutItem>
                                        </lightning:layout>
                                    </lightning:layoutItem>
                                </lightning:layout>
                            </div>
                        </div>
                    </div>
                </aura:component>
```

```css:CustomPageTemplate1.css
.THIS {
                height: calc(100% + var(--lwc-templateGutters, 0));
                padding-bottom: var(--lwc-templateGutters, 0) !important;
                }
                
                .THIS [data-id=middleSlider] {
                font-size: var(--lwc-varFontSize7);
                }
                
                .THIS .middleSizeController_static {
                display: none;
                }
                
                .THIS .middle {
                position: relative;
                width: 100%;
                top: 0;
                }
                
                .THIS .middle_fixed {
                position: fixed;
                top: 0;
                width: 100%;
                z-index: 98;
                }
                
                .THIS .middleSizeController_fixed {
                box-sizing: border-box;
                width: 25%;
                right: 0.3rem;
                border-radius: var(--lwc-pageHeaderBorderRadius);
                background-color: rgba(255, 255, 255, 0.5);
                z-index: 99;
                }
                
                .THIS .middleSizeBar {
                display: none;
                }
                
                .THIS .middleSizeBar_Undisable {
                display: contents;
                }
                
                .THIS .middleSizeController_zoom {
                box-sizing: content-box;
                width: min-content;
                }
                
                .THIS .middle_scale_1 {
                z-index: 98;
                display: none;
                }
                
                .THIS .middle_scale_4 {
                z-index: 98;
                transform: scale(0.3, 0.3);
                transform-origin: top right;
                }
                
                .THIS .middle_scale_6 {
                z-index: 98;
                transform: scale(0.6, 0.6);
                transform-origin: top right;
                }
                
                .THIS .middle_scale_8 {
                z-index: 98;
                transform: scale(0.8, 0.8);
                transform-origin: top right;
                }
                
                .THIS .middle_scale_10 {
                z-index: 98;
                transform: scale(1, 1);
                transform-origin: top right;
                }
```

```html:CustomPageTemplate1.design
<design:component>
                        <flexipage:template>
                            <flexipage:region name="top" defaultWidth="large"></flexipage:region>
                            <flexipage:region name="middle" defaultWidth="large"></flexipage:region>
                            <flexipage:region name="middle_Path" defaultWidth="large"></flexipage:region>
                            <flexipage:region name="bottom_left" defaultWidth="large">
                                <flexipage:formfactor type="medium" width="small"></flexipage:formfactor>
                                <flexipage:formfactor type="large" width="large"></flexipage:formfactor>
                            </flexipage:region>
                            <flexipage:region name="bottom_right" defaultWidth="small">
                                <flexipage:formfactor type="medium" width="small"></flexipage:formfactor>
                                <flexipage:formfactor type="large" width="large"></flexipage:formfactor>
                            </flexipage:region>
                        </flexipage:template>
                        <design:supportedFormFactors>
                            <design:supportedFormFactor type="small"></design:supportedFormFactor>
                            <design:supportedFormFactor type="large"></design:supportedFormFactor>
                        </design:supportedFormFactors>
                    </design:component>
```

```js:CustomPageTemplate1Controller.js
({
                    handleInit: function(component, event, helper) {
                    helper.doSetStaticStyle(component);
                    },
                    handleSlider: function(component, event, helper) {
                    let middleSize = event.target.value;
                    component.set("v.middleSizeNumber", middleSize);
                    helper.doSetMiddleSize(component,middleSize);
                    },
                    handleCssRerender: function(component, event, helper) {
                    component.set("v.middleSizeBar", false);
                    component.set("v.middleSize", "x-small");
                    component.set("v.middleSizeNumber", 7);
                    helper.doSetSizeLabel(component);
                    helper.doChangeMiddleSize(component);
                    },
                    handleMidControllerRerender: function(component, event, helper) {
                    helper.doChangeMiddleSize(component);
                    },
                    handleScroll: function(component, event, helper) {
                    let top = component.find("topDiv").getElement();
                    let middle = component.find("middleDiv").getElement();
                    let scroller = event.target;
                    let topMiddleClientHeight = top.clientHeight + (middle.clientHeight * 0.3);
                    component.set("v.scrollFlag", scroller.scrollTop > topMiddleClientHeight && $A.get("$Browser.formFactor") == "DESKTOP" ?
                    false : true);
                    },
                    handleSizeLabel: function(component, event, helper) {
                    helper.doSetSizeLabel(component);
                    }
                    })
```

```js:CustomPageTemplate1Helper.js
({
                    doChangeMiddleSize: function(component, event) {
                    let scrollFlag = component.get("v.scrollFlag");
                    if (scrollFlag) {
                    this.doSetStaticStyle(component);
                    this.doRemoveScaleStyle(component);
                    } else {
                    this.doRemoveScaleStyle(component);
                    this.doSetFixedStyle(component);
                    let middleSize = component.get("v.middleSize");
                    this.doSetMiddleSizeByLabel(component,middleSize);
                    }
                    },
                    doSetStaticStyle: function(component, event) {
                    let middleComp = component.find("middleDiv");
                    let middleSizeController = component.find("middleSizeController");
                    $A.util.addClass(middleSizeController, "middle");
                    $A.util.addClass(middleSizeController, "middleSizeController_static");
                    $A.util.addClass(middleComp, "middle");
                    $A.util.removeClass(middleSizeController, "middle_fixed");
                    $A.util.removeClass(middleComp, "tabBar");
                    $A.util.removeClass(middleComp, "middle_fixed");
                    },
                    doSetMiddleSize: function(component,middleSizeNumber){
                    switch (middleSizeNumber) {
                    case "7":
                    component.set("v.middleSize", "x-small");
                    break;
                    case "8":
                    component.set("v.middleSize", "small");
                    break;
                    case "9":
                    component.set("v.middleSize", "medium");
                    break;
                    case "10":
                    component.set("v.middleSize", "large");
                    break;
                    case "6":
                    component.set("v.middleSize", "close");
                    break;
                    }
                    },
                    doSetMiddleSizeByLabel: function(component,middleSize){
                    let middleComp = component.find("middleDiv");
                    switch (middleSize) {
                    case "x-small":
                    this.doRemoveScaleStyle(component);
                    $A.util.addClass(middleComp, "middle_scale_4");
                    break;
                    case "small":
                    this.doRemoveScaleStyle(component);
                    $A.util.addClass(middleComp, "middle_scale_6");
                    break;
                    case "medium":
                    this.doRemoveScaleStyle(component);
                    $A.util.addClass(middleComp, "middle_scale_8");
                    break;
                    case "large":
                    this.doRemoveScaleStyle(component);
                    $A.util.addClass(middleComp, "middle_scale_10");
                    break;
                    default:
                    this.doRemoveScaleStyle(component);
                    $A.util.addClass(middleComp, "middle_scale_1");
                    break;
                    }
                    },
                    doSetSizeLabel: function(component, event) {
                    let middleSizeBar = component.get("v.middleSizeBar");
                    component.set("v.middleSizeBar", middleSizeBar ? false : true);
                    middleSizeBar = middleSizeBar ? false : true;
                    let midlleSizeInput = component.find("midlleSizeInput");
                    let middleSizeController = component.find("middleSizeController");
                    let middleComp = component.find("middleDiv");
                    switch (middleSizeBar) {
                    case false:
                    this.doRemoveScaleStyle(component);
                    $A.util.addClass(midlleSizeInput, "middleSizeBar");
                    $A.util.addClass(middleComp, "middle_scale_1");
                    $A.util.addClass(middleSizeController, "middleSizeController_zoom");
                    break;
                    default:
                    let middleSize = component.get("v.middleSize");
                    // this.doChangeMiddleSize(component);
                    this.doRemoveScaleStyle(component);
                    this.doSetFixedStyle(component);
                    this.doSetMiddleSizeByLabel(component,middleSize);
                    switch (middleSize) {
                    case "x-small":
                    component.set("v.middleSizeNumber", 7);
                    break;
                    case "small":
                    component.set("v.middleSizeNumber", 8);
                    break;
                    case "medium":
                    component.set("v.middleSizeNumber", 9);
                    break;
                    case "large":
                    component.set("v.middleSizeNumber", 10);
                    break;
                    case "close":
                    component.set("v.middleSizeNumber", 6);
                    break;
                    }
                    let middleSizeNumber = component.get("v.middleSizeNumber");
                    this.doSetMiddleSize(component,middleSizeNumber);
                    $A.util.removeClass(midlleSizeInput, "middleSizeBar");
                    $A.util.removeClass(middleSizeController, "middleSizeController_zoom");
                    break;
                    }
                    },
                    doSetFixedStyle: function(component, event) {
                    let middleComp = component.find("middleDiv");
                    let middleSizeController = component.find("middleSizeController");
                    $A.util.addClass(middleSizeController, "middle_fixed");
                    $A.util.addClass(middleSizeController, "middleSizeController_fixed");
                    $A.util.removeClass(middleSizeController, "middle");
                    $A.util.removeClass(middleSizeController, "middleSizeController_static");
                    $A.util.addClass(middleComp, "tabBar");
                    $A.util.addClass(middleComp, "middle_fixed");
                    $A.util.removeClass(middleComp, "middle");
                    },
                    doRemoveScaleStyle: function(component, event) {
                    let middleComp = component.find("middleDiv");
                    $A.util.removeClass(middleComp, "middle_scale_1");
                    $A.util.removeClass(middleComp, "middle_scale_4");
                    $A.util.removeClass(middleComp, "middle_scale_6");
                    $A.util.removeClass(middleComp, "middle_scale_8");
                    $A.util.removeClass(middleComp, "middle_scale_10");
                    }
                    })
```