kopia lustrzana https://github.com/nolanlawson/pinafore
				
				
				
			fix jerky scrolling on Safari
							rodzic
							
								
									2bd553d64c
								
							
						
					
					
						commit
						7582f34d24
					
				|  | @ -1,8 +1,10 @@ | ||||||
| <Nav page={{page}} /> | <Nav page={{page}} /> | ||||||
| 
 | 
 | ||||||
| <main> | <div class="container"> | ||||||
| 	<slot></slot> |   <main> | ||||||
| </main> |     <slot></slot> | ||||||
|  |   </main> | ||||||
|  | </div> | ||||||
| <script> | <script> | ||||||
| 	import Nav from './Nav.html'; | 	import Nav from './Nav.html'; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ | ||||||
| <style> | <style> | ||||||
|   .loading-page { |   .loading-page { | ||||||
|     width: 100%; |     width: 100%; | ||||||
|     min-height: 40vh; |     min-height: 50vh; | ||||||
|     display: flex; |     display: flex; | ||||||
|     align-items: center; |     align-items: center; | ||||||
|     justify-content: center; |     justify-content: center; | ||||||
|  |  | ||||||
|  | @ -27,7 +27,6 @@ | ||||||
| 		right: 0; | 		right: 0; | ||||||
| 		top: 0; | 		top: 0; | ||||||
| 		z-index: 10; | 		z-index: 10; | ||||||
| 		will-change: transform; /* avoids "repaints on scroll" for fixed position header */ |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ul { | 	ul { | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| <:Window bind:scrollY='scrollY' bind:innerHeight='innerHeight'/> | <:Window bind:innerHeight='innerHeight'/> | ||||||
| <div class="virtual-list" ref:node style="height: {{$height}}px;"> | <div class="virtual-list" style="height: {{$height}}px;"> | ||||||
|   <!-- <div class="virtual-list-viewport" ref:viewport></div> --> |   <!-- <div class="virtual-list-viewport" ref:viewport></div> --> | ||||||
|   {{#each $visibleItems as item @key}} |   {{#each $visibleItems as item @key}} | ||||||
|   <VirtualListItem :component |   <VirtualListItem :component | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
|   import { virtualListStore } from '../_utils/virtualListStore' |   import { virtualListStore } from '../_utils/virtualListStore' | ||||||
|   import debounce from 'lodash/debounce' |   import debounce from 'lodash/debounce' | ||||||
| 
 | 
 | ||||||
|   const DEBOUNCE_TIME = 200 |   const DEBOUNCE_TIME = 500 | ||||||
| 
 | 
 | ||||||
|   export default { |   export default { | ||||||
|     oncreate () { |     oncreate () { | ||||||
|  | @ -35,12 +35,16 @@ | ||||||
|           'items': items |           'items': items | ||||||
|         }) |         }) | ||||||
|       }) |       }) | ||||||
|       this.observe('scrollY', debounce((scrollY) => { |       document.body.querySelector('.container').addEventListener('scroll', debounce((e) => { | ||||||
|         console.log('setting scrollY', scrollY) |  | ||||||
|         this.store.set({ |         this.store.set({ | ||||||
|           scrollTop: scrollY |           scrollTop: e.target.scrollTop | ||||||
|         }) |         }) | ||||||
|       }, DEBOUNCE_TIME)) |       }, DEBOUNCE_TIME, { | ||||||
|  |         leading: true, | ||||||
|  |         trailing: true | ||||||
|  |       })) | ||||||
|  |     }, | ||||||
|  |     ondestroy () { | ||||||
|     }, |     }, | ||||||
|     data: () => ({ |     data: () => ({ | ||||||
|       component: null |       component: null | ||||||
|  |  | ||||||
|  | @ -8,7 +8,6 @@ | ||||||
|   .virtual-list-item { |   .virtual-list-item { | ||||||
|     position: absolute; |     position: absolute; | ||||||
|     top: 0; |     top: 0; | ||||||
|     will-change: transform; |  | ||||||
|   } |   } | ||||||
| </style> | </style> | ||||||
| <script> | <script> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,5 @@ | ||||||
| import { Store } from 'svelte/store.js' | import { Store } from 'svelte/store.js' | ||||||
| 
 | 
 | ||||||
| const RENDER_BUFFER = 1000 |  | ||||||
| 
 |  | ||||||
| class VirtualListStore extends Store { | class VirtualListStore extends Store { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -14,6 +12,7 @@ const virtualListStore = new VirtualListStore({ | ||||||
| virtualListStore.compute('visibleItems', | virtualListStore.compute('visibleItems', | ||||||
|     ['items', 'scrollTop', 'height', 'itemHeights', 'innerHeight'], |     ['items', 'scrollTop', 'height', 'itemHeights', 'innerHeight'], | ||||||
|     (items, scrollTop, height, itemHeights, innerHeight) => { |     (items, scrollTop, height, itemHeights, innerHeight) => { | ||||||
|  |   let renderBuffer = 2 * innerHeight | ||||||
|   let visibleItems = [] |   let visibleItems = [] | ||||||
|   let totalOffset = 0 |   let totalOffset = 0 | ||||||
|   let len = items.length |   let len = items.length | ||||||
|  | @ -26,11 +25,11 @@ virtualListStore.compute('visibleItems', | ||||||
|     //console.log(key, 'scrollTop', scrollTop, 'currentOffset', currentOffset, 'innerHeight', innerHeight)
 |     //console.log(key, 'scrollTop', scrollTop, 'currentOffset', currentOffset, 'innerHeight', innerHeight)
 | ||||||
|     let isBelowViewport = (currentOffset < scrollTop) |     let isBelowViewport = (currentOffset < scrollTop) | ||||||
|     if (isBelowViewport) { |     if (isBelowViewport) { | ||||||
|       if (scrollTop - RENDER_BUFFER > currentOffset) { |       if (scrollTop - renderBuffer > currentOffset) { | ||||||
|         continue // below the area we want to render
 |         continue // below the area we want to render
 | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       if (currentOffset > (scrollTop + innerHeight + RENDER_BUFFER)) { |       if (currentOffset > (scrollTop + innerHeight + renderBuffer)) { | ||||||
|         break // above the area we want to render
 |         break // above the area we want to render
 | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -5,6 +5,11 @@ body { | ||||||
|   line-height: 1.3; |   line-height: 1.3; | ||||||
|   color: var(--body-text-color); |   color: var(--body-text-color); | ||||||
|   background: var(--body-bg); |   background: var(--body-bg); | ||||||
|  |   position: fixed; | ||||||
|  |   left: 0; | ||||||
|  |   right: 0; | ||||||
|  |   bottom: 0; | ||||||
|  |   top: 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #svelte { | #svelte { | ||||||
|  | @ -12,21 +17,30 @@ body { | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| main { | .container { | ||||||
|   overflow-x: hidden; |  | ||||||
|   overflow-y: auto; |   overflow-y: auto; | ||||||
|  |   overflow-x: hidden; | ||||||
|   -webkit-overflow-scrolling: touch; |   -webkit-overflow-scrolling: touch; | ||||||
|  |   position: absolute; | ||||||
|  |   top: 72px; | ||||||
|  |   left: 0; | ||||||
|  |   right: 0; | ||||||
|  |   bottom: 0; | ||||||
|  |   will-change: transform; /* avoids "repaint on scroll" in Chrome */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main { | ||||||
|   position: relative; |   position: relative; | ||||||
|   max-width: 600px; |   max-width: 600px; | ||||||
|   padding: 15px 15px; |   padding: 15px 15px; | ||||||
|   box-sizing: border-box; |   box-sizing: border-box; | ||||||
|   margin: 85px auto 15px; |   margin: 15px auto 15px; | ||||||
|   background: var(--main-bg); |   background: var(--main-bg); | ||||||
|   border: 1px solid var(--main-border); |   border: 1px solid var(--main-border); | ||||||
|   border-radius: 1px; |   border-radius: 1px; | ||||||
|   @media (max-width: 767px) { |   @media (max-width: 767px) { | ||||||
|     padding: 5px 5px; |     padding: 5px 5px; | ||||||
|     margin: 75px auto 15px; |     margin: 5px auto 15px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ | ||||||
| 	<style> | 	<style> | ||||||
| /* auto-generated w/ build-sass.js */ | /* auto-generated w/ build-sass.js */ | ||||||
| :root{--button-primary-bg:#6081e6;--button-primary-text:#fff;--button-primary-border:#132c76;--button-primary-bg-active:#456ce2;--button-primary-bg-hover:#6988e7;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#4169e1;--main-bg:#fff;--body-bg:#e8edfb;--body-text-color:#333;--main-border:#dadada;--svg-fill:#4169e1;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#4169e1;--nav-border:#214cce;--nav-a-border:#4169e1;--nav-a-selected-border:#fff;--nav-a-selected-bg:#6d8ce8;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#839deb;--nav-a-bg-hover:#577ae4;--nav-a-border-hover:#4169e1;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#839deb;--action-button-fill-color-hover:#99afef;--action-button-fill-color-active:#577ae4;--settings-list-item-bg:#fff;--settings-list-item-text:#4169e1;--settings-list-item-text-hover:#4169e1;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--deemphasized-text-color:#666} | :root{--button-primary-bg:#6081e6;--button-primary-text:#fff;--button-primary-border:#132c76;--button-primary-bg-active:#456ce2;--button-primary-bg-hover:#6988e7;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#4169e1;--main-bg:#fff;--body-bg:#e8edfb;--body-text-color:#333;--main-border:#dadada;--svg-fill:#4169e1;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#4169e1;--nav-border:#214cce;--nav-a-border:#4169e1;--nav-a-selected-border:#fff;--nav-a-selected-bg:#6d8ce8;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#839deb;--nav-a-bg-hover:#577ae4;--nav-a-border-hover:#4169e1;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#839deb;--action-button-fill-color-hover:#99afef;--action-button-fill-color-active:#577ae4;--settings-list-item-bg:#fff;--settings-list-item-text:#4169e1;--settings-list-item-text-hover:#4169e1;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--deemphasized-text-color:#666} | ||||||
| body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.3;color:var(--body-text-color);background:var(--body-bg)}#svelte{display:flex;flex-direction:column}main{overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch;position:relative;max-width:600px;padding:15px 15px;box-sizing:border-box;margin:85px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px}@media (max-width: 767px){main{padding:5px 5px;margin:75px auto 15px}}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px}button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover{background:var(--button-bg-hover)}button:active{background:var(--button-bg-active)}button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0} | body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.3;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}#svelte{display:flex;flex-direction:column}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;position:absolute;top:72px;left:0;right:0;bottom:0;will-change:transform}main{position:relative;max-width:600px;padding:15px 15px;box-sizing:border-box;margin:15px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px}@media (max-width: 767px){main{padding:5px 5px;margin:5px auto 15px}}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px}button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover{background:var(--button-bg-hover)}button:active{background:var(--button-bg-active)}button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0} | ||||||
| 
 | 
 | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Ładowanie…
	
		Reference in New Issue
	
	 Nolan Lawson
						Nolan Lawson