WebKit Bugzilla
Attachment 347085 Details for
Bug 188558
: CSS transition with CSS transform exhibits unintended jitter
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
HTML file for reduced test case
index.html (text/html), 9.52 KB, created by
Eugene Wen
on 2018-08-14 09:52:38 PDT
(
hide
)
Description:
HTML file for reduced test case
Filename:
MIME Type:
Creator:
Eugene Wen
Created:
2018-08-14 09:52:38 PDT
Size:
9.52 KB
patch
obsolete
><!DOCTYPE html> ><html> ><head> > <meta charset="utf-8"> > > <meta name="mobile-web-app-capable" content="yes"> > <meta name="apple-mobile-web-app-capable" content="yes"> > <meta name="apple-mobile-web-app-status-bar-style" content="default"> > > <meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui"> > <script src="https://unpkg.com/vue"></script> > <style> > body { > font-size: 50px; > font-weight: 400; > line-height: 200px; > color: white; > background: black; > width: 100%; > margin: 0; > margin-top: 20px; > } > > div.pages { > padding-top: 0; > padding-bottom: 0; > position: relative; > overflow: visible; > } > > div.pages div.cursor { > left: 0; > position: relative; > height: 100%; > padding: 0; > } > > div.pages .cursor:not(.dragging) { > -webkit-transition: left 6.6s ease; > -moz-transition: left 6.6s ease; > transition: left 6.6s ease; > } > > div.carousel-item { > height: 100%; > background-color: red; > display: block; > position: absolute; > list-style: none; > padding: 0; > margin: 0; > top: 0; > left: 0; > cursor: pointer; > -webkit-transform-origin: 50% 50%; > -moz-transform-origin: 50% 50%; > -ms-transform-origin: 50% 50%; > -o-transform-origin: 50% 50%; > transform-origin: 50% 50%; > -webkit-transform-style: preserve-3d; > -moz-transform-style: preserve-3d; > -ms-transform-style: preserve-3d; > -o-transform-style: preserve-3d; > transform-style: preserve-3d; > -webkit-transition: -webkit-transform .5s cubic-bezier(.075,.82,.165,1); > -moz-transition: -moz-transform .5s cubic-bezier(.075,.82,.165,1); > transition: transform .5s cubic-bezier(.075,.82,.165,1); > } > > div.thumbnail { > height: 100%; > display: block; > position: relative; > width: 94%; > padding-top: 0; > padding-bottom: 0; > margin-left: 3%; > margin-right: 3%; > content: ""; > border-radius: 3px; > background-color: blue; > color: #fff; > text-align: center; > line-height: 200px; > font-size: 48px; > -webkit-transition: opacity .5s cubic-bezier(.075,.82,.165,1),height .5s cubic-bezier(.075,.82,.165,1); > -moz-transition: opacity .5s cubic-bezier(.075,.82,.165,1),height .5s cubic-bezier(.075,.82,.165,1); > transition: opacity .5s cubic-bezier(.075,.82,.165,1),height .5s cubic-bezier(.075,.82,.165,1); > background-position: 50%; > background-size: cover; > background-repeat: no-repeat; > overflow: hidden; > } > > div.nav { > display: block; > position: absolute; > top: -12px; > bottom: -12px; > opacity: .7; > border: 0 solid #fff; > width: 7.55%; > content: ""; > cursor: pointer; > font-size: 48px; > line-height: 200px; > text-align: center; > -webkit-transition: opacity .66s ease; > -moz-transition: opacity .66s ease; > transition: opacity .66s ease; > } > > div.nav.prev { > left: 0; > background-color: rgba(12,10,21,.5); > background-image: -webkit-linear-gradient(right,rgba(12,10,21,.5),#0c0a15 12.5%); > background-image: linear-gradient(270deg,rgba(12,10,21,.5) 0,#0c0a15 12.5%); > } > > div.nav.next { > right: 0; > background-color: rgba(12,10,21,.5); > background-image: -webkit-linear-gradient(left,rgba(12,10,21,.5),#0c0a15 12.5%); > background-image: linear-gradient(90deg,rgba(12,10,21,.5) 0,#0c0a15 12.5%); > } > </style> ></head> ><body> > <div id="app"> > <div class="pages" :style="pagesStyle"> > <div > class="cursor" > :class="cursorClass" > :style="cursorStyle" > @touchstart="touchstart" > @touchmove="touchmove" > @touchend="touchend" > @touchcancel="touchend"> > <div > v-for="c in content" > :key="`${ c.index }-${ c.value }`" > class="carousel-item" > :style="containerStyle(c)"> > <div > class="thumbnail aspect-ratio" > > > {{ c.value }} > </div> > </div> > </div> > <div class="nav prev" @click="previous"> < </div> > <div class="nav next" @click="next"> > </div> > </div> > </div> > > <script> > var app = new Vue({ > el: '#app', > data: { > resolution: 4, > screen: { > width: document.documentElement.clientWidth, > height: document.documentElement.clientHeight > }, > aspect: document.documentElement.clientWidth / document.documentElement.clientHeight, > page: 0, > touch: null, > touchLeft: 0, > touchPercentage: 0, > touchLimit: 0.33, // 0-1 percentage value for swipe detection > max_screen_width: 1080, > duration: 500, > content: [ > { value: 'a', index: -10 }, > { value: 'b', index: -9 }, > { value: 'c', index: -8 }, > { value: 'd', index: -7 }, > { value: 'e', index: -6 }, > { value: 'f', index: -5 }, > { value: 'g', index: -4 }, > { value: 'h', index: -3 }, > { value: 'i', index: -2 }, > { value: 'j', index: -1 }, > { value: 'a', index: 0 }, > { value: 'b', index: 1 }, > { value: 'c', index: 2 }, > { value: 'd', index: 3 }, > { value: 'e', index: 4 }, > { value: 'f', index: 5 }, > { value: 'g', index: 6 }, > { value: 'h', index: 7 }, > { value: 'i', index: 8 }, > { value: 'j', index: 9 } > ], > row: 0 > }, > mounted: function() { > window.addEventListener('resize', this.resize, false); > this.update(); > this.setResolution(); > }, > beforeDestroy: function() { > window.removeEventListener('resize', this.resize, false); > }, > computed: { > width: function() { > return Math.min(this.screen.width, this.max_screen_width); > }, > adaptiveHeight: function() { > return this.height || 0; > }, > height: function() { > return 0.98 * (this.screen.width * 0.85 / this.resolution) / this.aspect; > }, > pageLeft: function() { > return this.touch ? this.touchLeft : this.offsetLeft; > }, > offsetLeft: function() { > return this.page - 0.03; > }, > firstIndex: function() { > // The index of the first item in the active set. > return this.page * this.resolution; > }, > centerIndex: function() { > // The index of the center most item. > return Math.floor(this.firstIndex + this.resolution / 2); > }, > pagesStyle: function() { > return { > height: '200px' > }; > }, > cursorStyle: function() { > return { > left: (-this.pageLeft * 85) + '%' > }; > }, > cursorClass: function() { > return { > dragging: !!this.touch > }; > } > }, > watch: { > width: function() { > this.setResolution(); > } > }, > methods: { > update: function() { > var that = this; > var length = this.content.length; > this.content = this.content.map( function(item) { > var xpct = 85 / that.resolution; > var offset = 5; > item.offsetWidthPercentage = xpct; > item.offsetLeftPercentage = item.index * xpct + offset; > > var range = length / 2; > // Delta is used to determine the index shift > var delta = that.centerIndex - item.index; > > if (delta <= - range) { > item.index -= length; > } else if (delta > range) { > item.index += length; > } > > return item; > }); > }, > resize: function() { > this.screen.width = document.documentElement.clientWidth; > this.screen.height = document.documentElement.clientHeight; > this.aspect = this.screen.width / this.screen.height; > }, > next: function () { > this.page++; > > this.update(); > }, > previous: function () { > this.page--; > > this.update(); > }, > setResolution: function() { > this.resolution = this.width >= 600 ? 4 : 2; > }, > containerStyle: function(item) { > return { > top: (this.row * 1.01) * this.adaptiveHeight + 'px', > left: item.offsetLeftPercentage + '%', > width: item.offsetWidthPercentage + '%' > }; > }, > touchstart: function(e) { > this.touchPercentage = 0; > if (e.touches.length > 0) { > this.touch = e.touches[0]; > this.touchLeft = this.offsetLeft; > } > }, > touchmove: function(e) { > if (e && e.preventDefault) { > e.preventDefault(); > } > > if (e.touches.length > 0) { > > var touch = e.touches[0]; > > // Delta comparison to do precise touch dragging > if (this.touch) { > > var dx = touch.pageX - this.touch.pageX; > dx /= screen.width; > this.touchPercentage += dx; > this.touchLeft -= dx; > > } > > this.touch = touch; > > } > > return false; > }, > touchend: function() { > this.touch = null; > if (this.touchPercentage > this.touchLimit) { > this.previous(); > } else if (this.touchPercentage < - this.touchLimit) { > this.next(); > } > this.touchPercentage = 0; > } > } > }) > </script> ></body> ></html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="default"> <meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui"> <script src="https://unpkg.com/vue"></script> <style> body { font-size: 50px; font-weight: 400; line-height: 200px; color: white; background: black; width: 100%; margin: 0; margin-top: 20px; } div.pages { padding-top: 0; padding-bottom: 0; position: relative; overflow: visible; } div.pages div.cursor { left: 0; position: relative; height: 100%; padding: 0; } div.pages .cursor:not(.dragging) { -webkit-transition: left 6.6s ease; -moz-transition: left 6.6s ease; transition: left 6.6s ease; } div.carousel-item { height: 100%; background-color: red; display: block; position: absolute; list-style: none; padding: 0; margin: 0; top: 0; left: 0; cursor: pointer; -webkit-transform-origin: 50% 50%; -moz-transform-origin: 50% 50%; -ms-transform-origin: 50% 50%; -o-transform-origin: 50% 50%; transform-origin: 50% 50%; -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; -ms-transform-style: preserve-3d; -o-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-transition: -webkit-transform .5s cubic-bezier(.075,.82,.165,1); -moz-transition: -moz-transform .5s cubic-bezier(.075,.82,.165,1); transition: transform .5s cubic-bezier(.075,.82,.165,1); } div.thumbnail { height: 100%; display: block; position: relative; width: 94%; padding-top: 0; padding-bottom: 0; margin-left: 3%; margin-right: 3%; content: ""; border-radius: 3px; background-color: blue; color: #fff; text-align: center; line-height: 200px; font-size: 48px; -webkit-transition: opacity .5s cubic-bezier(.075,.82,.165,1),height .5s cubic-bezier(.075,.82,.165,1); -moz-transition: opacity .5s cubic-bezier(.075,.82,.165,1),height .5s cubic-bezier(.075,.82,.165,1); transition: opacity .5s cubic-bezier(.075,.82,.165,1),height .5s cubic-bezier(.075,.82,.165,1); background-position: 50%; background-size: cover; background-repeat: no-repeat; overflow: hidden; } div.nav { display: block; position: absolute; top: -12px; bottom: -12px; opacity: .7; border: 0 solid #fff; width: 7.55%; content: ""; cursor: pointer; font-size: 48px; line-height: 200px; text-align: center; -webkit-transition: opacity .66s ease; -moz-transition: opacity .66s ease; transition: opacity .66s ease; } div.nav.prev { left: 0; background-color: rgba(12,10,21,.5); background-image: -webkit-linear-gradient(right,rgba(12,10,21,.5),#0c0a15 12.5%); background-image: linear-gradient(270deg,rgba(12,10,21,.5) 0,#0c0a15 12.5%); } div.nav.next { right: 0; background-color: rgba(12,10,21,.5); background-image: -webkit-linear-gradient(left,rgba(12,10,21,.5),#0c0a15 12.5%); background-image: linear-gradient(90deg,rgba(12,10,21,.5) 0,#0c0a15 12.5%); } </style> </head> <body> <div id="app"> <div class="pages" :style="pagesStyle"> <div class="cursor" :class="cursorClass" :style="cursorStyle" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" @touchcancel="touchend"> <div v-for="c in content" :key="`${ c.index }-${ c.value }`" class="carousel-item" :style="containerStyle(c)"> <div class="thumbnail aspect-ratio" > {{ c.value }} </div> </div> </div> <div class="nav prev" @click="previous"> < </div> <div class="nav next" @click="next"> > </div> </div> </div> <script> var app = new Vue({ el: '#app', data: { resolution: 4, screen: { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight }, aspect: document.documentElement.clientWidth / document.documentElement.clientHeight, page: 0, touch: null, touchLeft: 0, touchPercentage: 0, touchLimit: 0.33, // 0-1 percentage value for swipe detection max_screen_width: 1080, duration: 500, content: [ { value: 'a', index: -10 }, { value: 'b', index: -9 }, { value: 'c', index: -8 }, { value: 'd', index: -7 }, { value: 'e', index: -6 }, { value: 'f', index: -5 }, { value: 'g', index: -4 }, { value: 'h', index: -3 }, { value: 'i', index: -2 }, { value: 'j', index: -1 }, { value: 'a', index: 0 }, { value: 'b', index: 1 }, { value: 'c', index: 2 }, { value: 'd', index: 3 }, { value: 'e', index: 4 }, { value: 'f', index: 5 }, { value: 'g', index: 6 }, { value: 'h', index: 7 }, { value: 'i', index: 8 }, { value: 'j', index: 9 } ], row: 0 }, mounted: function() { window.addEventListener('resize', this.resize, false); this.update(); this.setResolution(); }, beforeDestroy: function() { window.removeEventListener('resize', this.resize, false); }, computed: { width: function() { return Math.min(this.screen.width, this.max_screen_width); }, adaptiveHeight: function() { return this.height || 0; }, height: function() { return 0.98 * (this.screen.width * 0.85 / this.resolution) / this.aspect; }, pageLeft: function() { return this.touch ? this.touchLeft : this.offsetLeft; }, offsetLeft: function() { return this.page - 0.03; }, firstIndex: function() { // The index of the first item in the active set. return this.page * this.resolution; }, centerIndex: function() { // The index of the center most item. return Math.floor(this.firstIndex + this.resolution / 2); }, pagesStyle: function() { return { height: '200px' }; }, cursorStyle: function() { return { left: (-this.pageLeft * 85) + '%' }; }, cursorClass: function() { return { dragging: !!this.touch }; } }, watch: { width: function() { this.setResolution(); } }, methods: { update: function() { var that = this; var length = this.content.length; this.content = this.content.map( function(item) { var xpct = 85 / that.resolution; var offset = 5; item.offsetWidthPercentage = xpct; item.offsetLeftPercentage = item.index * xpct + offset; var range = length / 2; // Delta is used to determine the index shift var delta = that.centerIndex - item.index; if (delta <= - range) { item.index -= length; } else if (delta > range) { item.index += length; } return item; }); }, resize: function() { this.screen.width = document.documentElement.clientWidth; this.screen.height = document.documentElement.clientHeight; this.aspect = this.screen.width / this.screen.height; }, next: function () { this.page++; this.update(); }, previous: function () { this.page--; this.update(); }, setResolution: function() { this.resolution = this.width >= 600 ? 4 : 2; }, containerStyle: function(item) { return { top: (this.row * 1.01) * this.adaptiveHeight + 'px', left: item.offsetLeftPercentage + '%', width: item.offsetWidthPercentage + '%' }; }, touchstart: function(e) { this.touchPercentage = 0; if (e.touches.length > 0) { this.touch = e.touches[0]; this.touchLeft = this.offsetLeft; } }, touchmove: function(e) { if (e && e.preventDefault) { e.preventDefault(); } if (e.touches.length > 0) { var touch = e.touches[0]; // Delta comparison to do precise touch dragging if (this.touch) { var dx = touch.pageX - this.touch.pageX; dx /= screen.width; this.touchPercentage += dx; this.touchLeft -= dx; } this.touch = touch; } return false; }, touchend: function() { this.touch = null; if (this.touchPercentage > this.touchLimit) { this.previous(); } else if (this.touchPercentage < - this.touchLimit) { this.next(); } this.touchPercentage = 0; } } }) </script> </body> </html>
View Attachment As Raw
Actions:
View
Attachments on
bug 188558
: 347085