Visible overflow in one direction with scrolling in the other direction - css

I need to have absolutely positioned element which scrolls with its parent. The absolutely positioned element may be wider than the scrollable container, in which case the content is currently being clipped. It appears that combining overflow-y: auto; and overflow-x: visible; does not work.
Here is a JSFiddle to illustrate the problem. Notice the popups cause horizontal scrolling.
And this is what it should look like here, only with scrolling.
Can this be accomplished through CSS?

You have a hard coded width. The <div> will automatically take the full width of the page, so you want to do is restrict the maximum width that the div can contain so change the width: 400px to something like max-width: 90%
Here's a JSFiddle example: http://jsfiddle.net/c8DdL/3/

For posterity: The problem does require a JavaScript solution. Ultimately the project feature I was working on was changed to avoid this problem and resulted in a better design.

use max_width instead of width 400. That is the only solution.

I found a solution in my project, by hiding the horizontal scrollbar (I use a custom scrollbar ui), giving the container a padding-right of 300px and a margin-right of -300px. The padding and -margin make it so the normal children are aligned the same, except there's also extra room in the container in case an absolutely-positioned element extends out of that zone. (scrollable areas cut off anything outside the outer bounds)
Of course, if you have content to the right of the scroll area, this makes it extend out onto it. With a transparent background that isn't a visual problem; however it then blocks mouse events.
To solve that, I added two elements as siblings of the scroll-view, like so:
// this outer container resizes to match the size of scrollContainer
<div style={{position: "relative"}>
<div id="scrollContainer" style={{paddingRight: 300, marginRight: -300}}>
// stuff which might extend to the right
</div>
// the containers below resize with the outer container
// however, notice that the 2nd one is positioned only over the possibly-extended-onto area
<div id="insideArea" style={{position: "absolute", left: 0, right: 0, top: 0, bottom: 0}}
onMouseEnter={()=> {
// we're back inside, so enable scroll-container mouse-events
$("scrollContainer").css("pointer-events", "auto");
// prevent self from blocking mouse events for scrollContainer
$("insideArea").css("display", "none");
// re-enable extend-area div, so we know when mouse moves over it
$("extendArea").css("display", "block");
}/>
<div id="extendArea" style={{position: "absolute", top: 0, bottom: 0, left: "100%", width: 300}}
onMouseEnter={()=> {
// we're over the extend-area, so disable scroll-container mouse events
$("scrollContainer").css("pointer-events", "none");
// prevent self from blocking mouse events for behind-extend-area elements
$("#extendArea").css("display", "none");
// re-enable inside-area div, so we know when mouse moves over it
$("#insideArea").css("display", "block");
}/>
What does the above do? It makes it so when your mouse enters the normal scroll-view area, pointer-events are enabled, letting you click on stuff inside -- but when your mouse moves into the special "extended" area, the scroll-view mouse-events are disabled, letting you click on the normal items behind that area.
This solution will probably never be used by anyone else, but I spent enough time finding it I thought I'd share it anyway!

Related

"clearfix" for position fixed

disclaimer: I know that fixed elements are not ment to take theire own space in the flow of a page but i think i need it anyway.
Question:
I try to have my nav in a Grid which has the height of 100vh When I press the trigger element the whole grid slides to the side and reveals the Navigation by adding a class with js. I want the whole viewport container to be in a fixed position but as I set it to position: fixed; all of the content below will overflow the container as it should by default behavior.
is there a way to "clearfix" this overflow?
I aswell want to hide it again with a "onscroll" event, so just changing the backgroundcolor is no option for me.
One way could be to change the overflow permission in the container with something like:
someDiv{
<!---Your nav should be wrapped with this-->
position: fixed;
overflow: hidden !important;
}
Then, add an onClick to your nav so when the nav is accessed, the overflow is changed
document.getElementById('someDiv').onclick = function(){
document.getElementById('someDiv').style.overflow = 'visible';
}
Not quite sure if this is what you are after.

Make Full Page Scrollbars Control Table with Sticky Headers (CSS Only)

The following sandbox shows code that works perfectly well for a Material UI Table placed within a Paper component with a sticky header: https://codesandbox.io/s/2n40y
I would like the scrollbars (horizontal and vertical) to appear at the edges of the browser page, bottom and right respectively, yet still control the scrolling of the Table itself.
Currently I am only able to do this when removing the table from the Paper and making it a child of the page directly -- or a child of a main div that would span the full page height. Yet I need the Paper component to remain there, where other components will be placed above and below it.
Any ideas on how to achieve this?
UPDATE: in the attached sketch, the browser border appears in black and the scrollbars where they should ideally be appear in green. There is a container div in the middle of the page that contains the table in red. The table's headers should be sticky and the table shouldn't appear beyond the container div which acts as an aesthetic wrapper around it. Ideally, the browser vertical scrollbar would scroll the whole page down while leaving the page header (title + subtitle) and the table headers sticky. Also, when horizontally scrolling, the table should scroll within the container div. This is why I marked the parts that should not ideally appear in dashed lines.
All the changes we need to make are on demo.js
Firstly, we need to use a custom MUI TableContainer as the containerComponent for your #devexpress/dx-react-grid-material-ui Table. Basically, the purpose of this is so we can remove the overflow properties of the Table so that the scrolling is primarily for the body to address the requirement of
the scrollbars (horizontal and vertical) to appear at the edges of the
browser page, bottom and right respectively
import TableContainer from "#material-ui/core/TableContainer";
import makeStyles from "#material-ui/core/styles/makeStyles";
const useStyles = makeStyles({
tableContainer: {
overflow: "initial"
}
});
const MUITableContainer = ({ children, ...rest }) => {
const classes = useStyles();
return (
<TableContainer classes={{ root: classes.tableContainer }} {...rest}>
{children}
</TableContainer>
);
};
Secondly, at your MUITableContainer, get rid of the height: 400px so that the table's height will respond to the content. Again, the browser body bottom & right scrollbars will now control the document's scroll positions - this includes the table. Take a look at the Table containerComponent prop as well - we have assigned the custom TableContainer we created earlier.
<Paper>
<Grid rows={rows} columns={columns} rootComponent={GridRoot}>
<Table
containerComponent={MUITableContainer}
tableComponent={StickyTable}
/>
...
Lastly, to test this requirement:
there will be other objects before and after it.
Just render sample components before & after the Paper component
I cannot see the design spec you have referenced, but going off the sample in the comment on the first answer, I think you are trying to keep the header and footer from going off the left edge of the viewport when the user scrolls. But using just CSS, no JavaScript.
I took the entirety of the HTML (only the HTML) from your original code at https://codesandbox.io/s/2n40y (specifically <div id="root">) and dropped that into a Codepen.
Then I added a few visual design styles from your example so it looks kinda close.
Then I added the following CSS to make the column headers sticky:
th {
position: -webkit-sticky;
position: sticky;
top: 0;
}
I dropped in the following HTML as the first child and last child of <div id="root">, though it really doesn't matter where they live as long as they are not in the table.
<div class="stuckHeaderFooter">
[...]
</div>
To keep those from scrolling off screen when I scroll to the right, I made them sticky to the left (for RTL content you would need to make it sticky to the right):
.stuckHeaderFooter {
position: -webkit-sticky;
position: sticky;
left: 0;
padding: 0 1em;
display: inline-block;
}
The padding just makes it look less ugly. The inline-block is there to keep the block-level elements from filling the entire document width, which would keep them from being properly sticky since they would be wider than the viewport. You will probably have to set a max-width using vw units, but without knowing your content, target sizes, etc., I cannot say what would be best.
Finally, you have to remove the inline height: 400px on the first <div> under the root (<div class="MuiPaper-root MuiPaper-elevation1 MuiPaper-rounded" style="height: 400px;">). If you cannot override it because something injects it, then this style will override it for you but it brittle without knowing what else may be going on:
#root > div {
height: auto !important;
}
CSS only, no JavaScript in this approach at all, which is what I think you wanted.
Pen: https://codepen.io/aardrian/pen/PoNMopM
Debug view: https://cdpn.io/aardrian/debug/PoNMopM
Update: 5 October 2020: Looking at the sketch provided with the question, it is important to note that the container that does the clipping is the one that gets the scrollbar. So your options for a CSS-only solution are limited:
Add a fake block to make a visible border on the right (I updated the pen to add one; look at #root::after for an example but you will still need JS to make sure that does not appear until the table starts to get covered).
Yeah, I ran out of ideas.
In conclusion, I don't believe there is a CSS-only solution here because of how clipped areas work.
You can achieve this by setting the height and width to be equal to the viewport:
<Paper style={{ height: "100vh", width: "100vw" }}>
Example modified: https://codesandbox.io/s/table-sticky-header-forked-l77is?file=/demo.js

How can I open popover outside scroll?

My problem is when popover comes out it always stay inside of scroll. So that when I need to see popover content I need to scroll down then I can see it. I use z index. But I can not show the popover out side of scroll. I am using angular popover.
If I use position fixed instead of absolute it always open aspect of window and I don't want it.
This is an aspect of how CSS works. You are using incompatible CSS techniques. A child element (popover) that is absolutely positioned cannot be rendered outside a parent element boundary with overflow restrictions (hidden or scroll). The overflow property tells the browser to enforce rendering restrictions on all child elements except ones with "fixed" position.
If you show your code, we can probably help you achieve your goal with some modifications.
Edit
With the example provided, all that needs to be done is to add a CSS rule to the .sectionone element for position: static
.sectionOne {
position: static; // solution
overflow-x: scroll; // in example provided
}
.table {
width:1000px; // in example provided
}

position:absolute and overflow:auto prevent number input scroll

I've encountered a problem when using a html5 number input inside a div with position: absolute; overflow: auto on Chromium Version 23.0.1271.64 (165188)
Normally scrolling the mouse wheel on a focused number input increments and decrements the value in the field. But inside a div with position: absolute; overflow: auto, the div contents just scroll unless there is nowhere to scroll.
Fiddle: http://jsfiddle.net/9M9nx/7/
Is there a way to always let the input element receive the scroll event?
I think you're going to have to hack this one. This hack works:
http://jsfiddle.net/9M9nx/12/
Here I've used jQuery to change the overflow property of the scrolling parent, based on the focus and blur events on the number input.
$('.scroller input[type=number]').focus(function(){
$(this).closest('.scroller').css('overflow','hidden');
});
$('.scroller input[type=number]').blur(function(){
$(this).closest('.scroller').css('overflow','auto');
});​

Make a div nested in a jQuery UI dialog resize with the dialog?

My jQuery UI dialog contains two div elements. One has a fixed height and should be aligned at the bottom of the dialog at all times. The other one should take up the remaining space.
Basically I’d like all the dimensions highlighted in blue to remain unchanged on resize. Or, in other words, the red div resizes in both dimensions but the green div keeps its height.
What’s the easiest way to do this in jQuery UI or even just plain CSS?
I’ve found a way to do this that doesn’t use any JavaScript. It doesn’t even involve any hacks; just plain normal CSS3. Fiddle here: http://jsfiddle.net/nty5K/16/
Basically, both divs are position: absolute, and each of the sides is anchored individually using the top, bottom, left and right properties. The top div has all four positions specified, making it resize with the container while preserving the exact distance to each edge of the container. The bottom div has three of the positions fixed, whereas the top is defined only indirectly, via a fixed height.
In practice, the divs will need to be placed into a wrapper div that has position: relative, otherwise the top/bottom divs will be positioned relative to the body element.
Not sure about browser compatibility yet, but this worked fine in Firefox 10, IE9 and Chrome 17. Didn’t test this in earlier versions.
Corporate firewall is blocking images, so I am guessing what you are after based on other comments.
EDIT:
Now that I can see what you are after, I have updated my fiddle accordingly. Including the code below for completeness.
I would write a function to calculate the size of the dialog, subtract the height of the fixed div and set the height of the dynamic div to this calculated value. I would then bind a call to this function to the resize event of the dialog. Here is a fiddle, may need some tweaking for your exact layout but should be close.
One gotcha worth noting is that some browsers may not calculate correctly while they are in the middle of a scroll/resize event, queing the calculations to occur after the resize event completes with setTimeout resolves the issues, though it does make the change a bit jumpy while the resize is in progress. See this question and answer for details.
function SetDivHeight() {
var $DynamicDiv = $('div.dynamic');
var $FixedDiv = $('div.fixed');
var $Container = $(window); //Update for containing element
/*Calculate the adjustment needed to account for the margin and
border of the dynamic div.*/
var HeightAdjustment = $DynamicDiv.outerHeight(true) - $DynamicDiv.height();
/*Get the values of the top and bottom margins which overlap
between the two divs.*/
var DynamicBottomMargin = parseInt($DynamicDiv.css('marginBottom'));
var FixedTopMargin = parseInt($FixedDiv.css('marginTop'));
/*Adjust for the overlapping top/bottom margin by subtracting
which ever is smaller from the adjustment value.*/
if (DynamicBottomMargin >= FixedTopMargin) {
HeightAdjustment -= FixedTopMargin;
} else {
HeightAdjustment -= DynamicBottomMargin;
}
/*subtract the height of the fixed div from the height of the
container, subtract the calculated height adjustment from that
value, and set the result as the height of the dynamic div.*/
$DynamicDiv.height(($Container.height() - $FixedDiv.outerHeight(true)) -
HeightAdjustment);
/*May need to use $Container.innerHeight instead, if container
is not a window element.*/
}
var t;
function QueueSetDivHeight() {
if (t) {
clearTimeout(t);
}
t = setTimeout(function() {
SetDivHeight();
}, 0);
}
$(document).ready(function() {
SetDivHeight();
$(window).resize(QueueSetDivHeight);
//Bind to resize of container element instead/as well
});
Just CSS... check it out!
Set a margin to the container and a margin-top to the bottom fixed div. No jQuery required.

Resources