Fix layout shifts caused by early rendering passes
authorAlexander Ebert <ebert@woltlab.com>
Mon, 21 Aug 2023 12:17:55 +0000 (14:17 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 21 Aug 2023 12:17:55 +0000 (14:17 +0200)
The previous CSS code relied on `.content:not(:last-child)` to reserve the space required for the right sidebar.

This selector does not work as expected when the browser does an early rendering pass while the `.content` block is still open. It causes the space for the sidebar to be reserved but once the parsing continues the browser realizes that there is no sidebar (=`.content` is the last child) and layout is visually updated.

See https://www.woltlab.com/community/thread/301233-template-list-behavior-when-sorting-results/

com.woltlab.wcf/templates/footer.tpl
com.woltlab.wcf/templates/header.tpl
wcfsetup/install/files/style/layout/layout.scss

index 1139f44d8b42f066da3a830e5c4377d0eaa86d04..5977933dee84917863f8a3cef347eb8a7df81d0c 100644 (file)
                                        {@$__wcf->getAdHandler()->getAds('com.woltlab.wcf.footer.content')}
                                {/if}
                        </div>
-                               
-                       {capture assign='__sidebarRightContent'}
-                               {event name='boxesSidebarRightTop'}
-                               
-                               {* WCF2.1 Fallback *}
-                               {if !$sidebar|empty}
-                                       {if !$sidebarOrientation|isset || $sidebarOrientation == 'right'}
-                                               {@$sidebar}
-                                       {/if}
-                               {/if}
-                               
-                               {if !$sidebarRight|empty}
-                                       {@$sidebarRight}
-                               {/if}
-                               
-                               {foreach from=$__wcf->getBoxHandler()->getBoxes('sidebarRight') item=box}
-                                       {@$box->render()}
-                               {/foreach}
-                               
-                               {event name='boxesSidebarRightBottom'}
-                       {/capture}
-                               
-                       {if $__sidebarRightContent|trim}
+                       
+                       {hascontent}
                                <aside class="sidebar boxesSidebarRight" aria-label="{lang}wcf.page.sidebar.right{/lang}">
                                        <div class="boxContainer">
-                                               {if MODULE_WCF_AD && $__disableAds|empty && $__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.top')}
-                                                       <div class="box boxBorderless">
-                                                               <div class="boxContent">
-                                                                       {@$__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.top')}
-                                                               </div>
-                                                       </div>
-                                               {/if}
-                                                       
-                                               {@$__sidebarRightContent}       
-                                               
-                                               {if MODULE_WCF_AD && $__disableAds|empty && $__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.bottom')}
-                                                       <div class="box boxBorderless">
-                                                               <div class="boxContent">
-                                                                       {@$__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.bottom')}
-                                                               </div>
-                                                       </div>
-                                               {/if}
+                                               {content}{@$__sidebarRightContent}{/content}
                                        </div>
                                </aside>
-                       {/if}
+                       {/hascontent}
                </div>
        </section>
        
index b9839e5d6858e46d12f99be35968fe92fce4ddf9..90db1ed7f94dc6b1a0299864607703c2f4f3cdde 100644 (file)
                                        </div>
                                </aside>
                        {/hascontent}
+
+                       {capture assign='__sidebarRightContent'}
+                               {if MODULE_WCF_AD && $__disableAds|empty && $__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.top')}
+                                       <div class="box boxBorderless">
+                                               <div class="boxContent">
+                                                       {@$__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.top')}
+                                               </div>
+                                       </div>
+                               {/if}
+                               
+                               {event name='boxesSidebarRightTop'}
+                               
+                               {* WCF2.1 Fallback *}
+                               {if !$sidebar|empty}
+                                       {if !$sidebarOrientation|isset || $sidebarOrientation == 'right'}
+                                               {@$sidebar}
+                                       {/if}
+                               {/if}
+                               
+                               {if !$sidebarRight|empty}
+                                       {@$sidebarRight}
+                               {/if}
+                               
+                               {foreach from=$__wcf->getBoxHandler()->getBoxes('sidebarRight') item=box}
+                                       {@$box->render()}
+                               {/foreach}
+                               
+                               {event name='boxesSidebarRightBottom'}
+
+                               {if MODULE_WCF_AD && $__disableAds|empty && $__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.bottom')}
+                                       <div class="box boxBorderless">
+                                               <div class="boxContent">
+                                                       {@$__wcf->getAdHandler()->getAds('com.woltlab.wcf.sidebar.bottom')}
+                                               </div>
+                                       </div>
+                               {/if}
+                       {/capture}
                        
-                       <div id="content" class="content">
+                       <div id="content" class="content{if $__sidebarRightContent|trim} content--sidebar-right{/if}">
                                {if MODULE_WCF_AD && $__disableAds|empty}{@$__wcf->getAdHandler()->getAds('com.woltlab.wcf.header.content')}{/if}
                                
                                {if $__disableContentHeader|empty}
index d504e577e556b612191b84432a431a03eef1d92f..0bc7e12c6740c2bc7fd1f8cdc9cf3049e74124dd 100644 (file)
@@ -110,14 +110,13 @@ html.iOS select {
        .content {
                flex: 1 1 0px;
 
-               // sidebar follows
-               &:not(:last-child) {
+               &.content--sidebar-right {
                        flex-basis: calc(100% - 340px);
-                       max-width: calc(100% - 340px); // IE fix
-               }
+                       max-width: calc(100% - 340px);
 
-               & + .sidebar {
-                       margin-left: 30px;
+                       & + .sidebar {
+                               margin-left: 30px;
+                       }
                }
        }