Preventing Relayout Due to Scrollbar

Preventing relayout due to scrollbar

You can create a container that have a fixed width, and give the content the same width (same static width - not 100%).
that way, when the content overflows the parent, the scroll will not push the content but will flow above it.

using that, you can apply a cool way to scroll without pushing anything. by showing the scroll only when you hover the container.

Check out this simple Demo

EDIT:
Here I show the difference between setting static width, and %.

How Do I Stop My Web Content From Shifting Left When The Vertical Scrollbar Appears? Roll-Up of Advice 2017

Before going into individual solutions, it should be mentioned that they break down into three categories: CSS-, CSS3-, and Javascript-based solutions.

The CSS solutions tend to be rigid but very predictable and very well supported.

The CSS3 solutions have a CPU calculation cost like Javascript, but are easy to implement. In years previous to 2017, however, they had sporadic support in browsers. That is improving over time. Ultimately, they will likely be the best solution, but my own investigations today have demonstrated the support simply isn't consistent enough yet and, besides, legacy browser support is non-existent.

The Javascript solutions (whether in straight Javascript or in jQuery) need extra coding to make them robust as they have no intrinsic support for (e.g.) window resizing. However, they're the most predictable and the most backward compatible while still preserving the aesthetics of the page. I consider the line for legacy browsers to be between IE6 and IE7. Frankly, my condolences to anyone still using a browser that old.

Please note that I have not included every CSS3 and Javascript solution previously posted to Stack Exchange. Some, though novel, had substantial weaknesses and so were not included here.


**Solution #1: The CSS Solution**

Contributors: Hive7, koningdavid, Christofer Eliasson, Alec Gorge, Scott Bartell, Shawn Taylor, mVChr, fsn, Damb, Sparky, Ruben, Michael Krelin - hacker, Melvin Guerrero

Force the srollbar to always be on.

<style>
html {
overflow-y: scroll;
}
</style>

This solution is basically guaranteed to always work (there are some exceptions, but they're very rare), but it is aesthetically unpleasing. The scrollbar will always be seen, whether it's needed or not. While concensus is to use this solution in the html tag, some people suggest using it in the body tag.

Consequences

Microsoft (IE10+) has implented floating scroll bars which means your page may not be centered in it like it would be in other browsers. However, this seems to be a very minor issue.

When using structured interfaces like FancyBox, Flex-Box, or Twitter Bootstrap Modal this can cause a double-scrollbar to appear as those interfaces create their own scrollbars.

Programmers should avoid using overflow: scroll as this will cause both the vertical and horizontal scrollbars to appear.

Solution #1a: An Alternative

Contributors: koningdavid, Nikunj Madhogaria

A clever alternative, but one having only a minor aesthetic difference, is to do this:

<style>
html {
height: 101%;
}
</style>

This activates the scroll bar background but doesn't activate the scroll bar tab unless your vertical content actually overflows the bottom edge of the window. Nevertheless, it has the same weakness in that the scrollbar space is permanently consumed whether needed or not.

Solution #1b: A More Modern Solution

Contributors: Kyle Dumovic, SimonDos

Browsers are beginning to pick up the use of the overlay value for scrollbars, mimicking the floating scrollbar of IE10+.

<style>
html {
overflow-y: overlay;
}
</style>

This solution mimics the floating scrollbar in IE10+, but it is not yet available in all browsers and still has some implementation quirks. This solution is known not to work for infrastructure environments like Bootstrap Modal.


**Solution #2: The CSS3 Solution**

Use CSS3 to calculate widths. There are many ways to do this with advantages and disadvantages to each. Most disadvantages are due to (a) not knowing the actual scrollbar width, (b) dealing with screen resizing, and (c) the fact that CSS is slowly becoming yet-another-fully-functioning-programming language — like Javascript — but has not yet completely evolved into such. Whether or not it even makes sense for it to become such is a debate for another question.

The argument that users may disable Javascript and so a CSS-only solution is preferable is becoming irrelevant. Client-side programming has become so ubiquitous that only the most paranoid of people are still disabling Javascript. Personally, I no longer consider this a tenable argument.

It should be noted that some solutions modify margin and others modify padding. Those that modify margin have a common problem: if you have navigation bars, headers, borders, etc. that use a different color than the page background this solution will expose undesirable borders. It is likely that any solution using margin can be re-designed to use padding and vice-versa.

Solution #2a: The HTML-based Solution

Contributors: TranslucentCloud, Mihail Malostanidis

<style>
html {
margin-left: calc(100vw - 100%);
margin-right: 0;
}
</script>

Solution #2b: The BODY-based Solution

Contributors: Greg St.Onge, Moesio, Jonathan SI

<style>
body {
padding-left: 17px;
width: calc(100vw - 17px);
}
@media screen and (min-width: 1058px) {
body {
padding-left: 17px;
width: calc(100vw - 17px);
}
}
</style>

100vw is 100% of the viewport width.

Consequences

Some users have suggested this solution creates undesirable screen noise when the window is resized (perhaps the calculation process is occuring multiple times during the resize process). A possible workaround is to avoid using margin: 0 auto; to center your content and instead use the following (the 1000px and 500px shown in the example represent your content maximum width and half that amount, respectively):

<style>
body {
margin-left: calc(50vw - 500px);
}
@media screen and (max-width: 1000px) {
body {
margin-left: 0;
}
}
</style>

This is a fixed-scrollbar-width solution, which isn't browser independent. To make it browser independent, you must include Javascript to determine the width of the scrollbars. An example that calculates the width but does not re-incorporate the value is:

Please note that the code snippet below has been posted multiple times on Stack Exchange and other locations on the Internet verbatim with no firm attribution.

function scrollbarWidth() {
var div = $('<div style="width:50px;height:50px;overflow:hidden;position:absolute;top:-200px;left:-200px;"><div style="height:100px;"></div>');
// Append our div, do our calculation and then remove it
$('body').append(div);
var w1 = $('div', div).innerWidth();
div.css('overflow-y', 'scroll');
var w2 = $('div', div).innerWidth();
$(div).remove();
return (w1 - w2);
}

Solution #2c: The DIV-based Solution

Contributors: Rapti

Use CSS3 calculations applied directly to a container DIV element.

<body>
<div style="padding-left: calc(100vw - 100%);">
My Content
</div>
</body>

Consequences

Like all CSS3 solutions, this is not supported by all browsers. Even those browsers that support viewport calculations do not (as of the date of this writing) support its use arbitrarily.

Solution #2d: Bootstrap Modal

Contributors: Mihail Malostanidis, kashesandr

Users of Twitter Bootstrap Modal have found it useful to apply the following CSS3 to their HTML element.

<style>
html {
width: 100%;
width: 100vw;
}
</style>

Another suggestion is to create a wrapper around your content wrapper that is used to auto-detect changes in the viewport width.

<style>
body {
overflow-x: hidden;
}
#wrap-wrap {
width: 100vw;
}
#content-wrap {
margin: 0 auto;
width: 800px;
}
</style>

I have not tried either of these as I do not use Bootstrap.


**Solution #3: The Javascript Solution**

Contributors: Sam, JBH

This is my favorite solution as it deals with all the issues and is reasonably backward compatible to legacy browsers. Best of all, it's scrollbar-width independent.

<script>
function updateWindow(){
document.body.style.paddingLeft = (window.innerWidth - document.body.clientWidth);
document.body.onclick=function(){
document.body.style.paddingLeft = (window.innerWidth - document.body.clientWidth);
}
}
window.onload=updateWindow();
window.addEventListener("resize", updateWindow());
updateWindow();
</script>

Consequences

The final command to updateWindow(); should occur just before the </body> tag to avoid problems with dynamically-loaded content such as Facebook Like-Boxes. It would seem that it's redundant to the window.onload event, but not every browser treats onload the same way. Some wait for asynchronous events. Others don't.

The function is executed each and every time a user clicks within the web page. Gratefully, modern computers are fast enough that this isn't much of an issue. Still….

Finally, the function should be executed after any div is asynchronously updated (AJAX). That is not shown in this example, but would be part of the ready-state condition. For example:

xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
if(xmlhttp.responseText == 'false'){
//Error processing here
} else {
//Success processing here
updateWindow();
}
}
}

Solution #3a: Measuring Scrollbar Widths

Contributors: Lwyrn

This is a less valuable solution that takes the time to measure scrollbar widths.

<script>
var checkScrollBars = function(){
var b = $('body');
var normalw = 0;
var scrollw = 0;
if(b.prop('scrollHeight')>b.height()){
normalw = window.innerWidth;
scrollw = normalw - b.width();
$('#container').css({marginRight:'-'+scrollw+'px'});
}
}
</script>
<style>
body {
overflow-x: hidden;
}
</style>

Consequences

Like other solutions, this one permanently disables the horizontal scrollbar.

Flex: Prevent scrollbar from covering content when automatically displayed

It's a bug. See Flex verticalScrollPolicy bug for a workaround.

Make scroll bar take no space / prevent layout shift

There's no way to make a scrollbar appear on top of your content without using shady hacks, and it's not the best idea anyways since it will affect the usability of your app. If the scroll bar is over the content, it's likely to hide links/text/etc.

Your page ideally should be styled in such a way that it adapts to different browser/page widths without breaking. Especially with just a little scroll bar.

Anyways, here's a workaround that may help:

html {
overflow-y: scroll;
}

Adding this style will make sure the scroll bar track is always present, and will also help avoid "jumpy" pages when a scrollbar appears/disappears. Again, the real solution is to use a flexible layout.

As a side note, styling the scrollbar is generally not recommended. It doesn't work cross-browser and will usually be ignored completely.

CSS box shadow on container div causes scrollbars

Webkit changed its behavior recently as pointed out here:
http://archivist.incutio.com/viewlist/css-discuss/109662

Indeed as of today it is still an issue in Gecko and maybe other browsers.


I managed to fix this nasty problem on Gecko using negative margins which also work on all other browsers.

Let's assume you have a screen-wide element (E) with box-shadow applied with zero offsets and blur radius R. Let's assume you are dealing with horizontal scrollbar problem because shadow causes element E to relayout with added width.

  1. wrap E with helper wrapper element (W)
  2. set overflow:hidden on W
  3. set padding: R 0 R 0 on W
  4. set margin: -R 0 -R 0 on W

The idea is to use overflow hidden to clip out problematic shadows on the left and right. And then use padding+negative margin trick to not clip top and bottom shadows and to keep the box on the same spot in HTML flow.

You can adapt this technique to clip out any arbitrary sides of your problematic shadow box.

Right fixed sidebar inside scrollcontainer

The solution is to wrap the content and the fix part and prevent the scroll from the body.

Also, you wrap the fix part with a position: absolute wrapper. The difference is how the different positions handle right: 0. The absolute is relative to the parent (with position: relative) and the fixed is always relative to the window.

At this point the browser will block the mouse wheel event when you on the sidebar (because of the position: fixed) so we will add .fixed-inner with pointer-events: auto to allow the user to interact with the sidebar content.

I tested it only on the latest Chrome.

function showOverlay() {

// var style = document.body.style;

// style.overflow = 'hidden';

document.getElementById('overlay').style.display = 'block';

}

function closeOverlay() {

// var style = document.body.style;

// style['overflow-y'] = 'scroll';

document.getElementById('overlay').style.display = 'none';

}
* {

margin: 0;

box-sizing: border-box

}

html,

body {

position: relative;

height: 100%;

overflow-y: hidden;

}

.wrapper {

overflow-y: auto;

position: relative;

height: 100%;

}

.content {

position: relative;

display: block;

background-color: lightblue;

border: 2px solid white;

width: calc(100% - 60px)

}

.fixed-wrapper {

position: absolute;

top: 0;

right: 0;

width: 60px;

height: 100%;

}

.fixed {

position: fixed;

z-index: 1000;

background-color: lightgreen;

width: 60px;

border: 2px solid black;

text-align: right;

height: 100%;

top: 0;

pointer-events: none;

}

.fixed .fixed-inner {

pointer-events: auto;

}

#overlay {

display: none;

position: fixed;

z-index: 10000;

left: 0;

top: 0;

bottom: 0;

right: 0;

background-color: rgba(32, 32, 32, 0.5);

overflow-y: scroll;

}

.overlay-content {

margin: 50px auto;

height: 1000px;

width: 80%;

background-color: yellow;

}
<div class="wrapper">

<div class="content">

Body<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/> Body

<br/>

<button onclick="showOverlay()">show overlay</button>

</div>

<div class="fixed-wrapper">

<div class="fixed">

<div class="fixed-inner">

<a href="https://google.com">A</a>

<br/>B<br/>C

</div>

</div>

</div>

</div>

<div id="overlay">

<div class="overlay-content">

<button onclick="closeOverlay()">Close overlay</button>

</div>

</div>

How to avoid relayout of content in a tableview?

What you're doing is fine. You are putting data in the label (or whatever it is), not moving it around. That is exactly what cellForRowAtIndexPath is for — to apply to the cell the data that corresponds to this index path.



Related Topics



Leave a reply



Submit