I have a cdk-virtual-scroll-viewport element and inside this element I have a relatively positioned div with an absolute positioned element inside it.. basically I want to be able to show the absolutely positioned item outside the cdk-virtual-scroll-viewport but its being cut off...
here is a stackblitz of the issue
https://stackblitz.com/edit/angular-kavjsh
component.html
<div class="container">
<cdk-virtual-scroll-viewport itemSize="70">
<div class="test" *cdkVirtualFor="let name of names">
<p>{{name}}</p>
<div class="test-item"></div>
</div>
</cdk-virtual-scroll-viewport>
</div>
component.css
p {
font-family: Lato;
}
cdk-virtual-scroll-viewport {
width: 150px;
border: 1px solid black;
height: 600px;
}
.test {
position: relative;
}
.test-item {
position: absolute;
background: black;
width: 150px;
height: 100px;
left: 50%;
}
whats happening is this
and my desired result is this
I've tried all sorts of positioning configuration and I can not make it work?
Any help would be appreciated!
You can use the below steps
reset contain to 'initial' or 'layout'
change overflow to 'visible'
cdk-virtual-scroll-viewport {
overflow: visible;
contain: initial;
}
:host() ::ng-deep cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper {
contain: inherit;
}
https://stackblitz.com/edit/angular-miqwyw?file=src/app/app.component.css
Try with overflow visible in the test div or the cdk-virtual-scroll-viewport
cdk-virtual-scroll-viewport {
width: 150px;
border: 1px solid black;
height: 600px;
overflow:visible
}
.test {
position: relative;
overflow:visible
}
Related
There are lots of card to be showed and I need to show menu when I hover one of the cards.
I use position: absolute; for menu and use position: relative; for the card, but why the scrollbar appeared when I hover on the card ?
<!DOCTYPE html>
<html>
<head>
<style>
.box {
height: 240px;
width: 200px;
overflow: auto;
border: 1px dashed red;
}
.card {
height: 120px;
width: 120px;
border: 1px solid blue;
position: relative;
}
.menu {
display: none;
height: 400px;
width: 200px;
position: absolute;
top: 0;
left: 0;
background: linear-gradient(orange, pink);
}
.card:hover .menu {
display: block;
}
</style>
</head>
<body>
<div class="box">
<div class="card">
<div class="menu"></div>
</div>
</div>
</body>
</html>
The scrollbar has nothing to do with your positioning, it is a result of overflow: auto; on your .box element.
overflow: auto; will show a scrolling bar if a child element overflows its parent container where overflow: auto; is set.
Seeing as the .box parent-element has a fixed size value height: 240px; while its child element .menu has height: 400px;, it will cause a scrollbar to appear because there is an overflow of 160px.
While #Yong is correct with document flow in his answer with the position: absolute; property, seeing as you have fixed height and width on all your elements, position: absolute; doesn't actually do anything in this exact reproducible example.
If I understand your problem correctly, a simple solution to your problem if you want to keep the fixed width and height on your .box element, you can simply disable the scrollbar by applying display: none; to the .box pseudo-element ::-webkit-scrollbar.
(NOTE: As of February 28th, 2022 this is still not supported in Firefox).
Read more about browser support at https://caniuse.com/?search=%3A%3A-webkit-scrollbar
Example with no positioning properties & -::webkit-scrollbar
.box {
height: 240px;
width: 200px;
border: 1px dashed red;
overflow: auto;
}
.box::-webkit-scrollbar{
display: none;
}
.card {
height: 120px;
width: 120px;
border: 1px solid blue;
/*position: relative;*/
}
.menu {
display: none;
height: 400px;
width: 200px;
/*position: absolute;
top: 0;
left: 0;*/
background: linear-gradient(orange, pink);
}
.card:hover .menu {
display: block;
}
<!DOCTYPE html>
<html>
<body>
<div class="box">
<div class="card">
<div class="menu"></div>
</div>
</div>
</body>
</html>
If you want to remove overflow altogether, you can apply overflow: hidden; to .box.
Keep in mind the fixed height of 400px on the .menu element will not apply as the fixed height of 240px on the .box element will hide the remaining 160px. I hope this solves your problem, but a little more detail would help!
absolute
The element is removed from the normal document flow, and no space is
created for the element in the page layout. It is positioned relative
to its closest positioned ancestor, if any; otherwise, it is placed
relative to the initial containing block. -MDN
.menu is positioned absolute therefore it is positioned relative to .card which is the closes positioned ancestor to it.
relative
The element is positioned according to the normal flow of the
document, ... -MDN
And because .card is positioned relative it would still take space and position according to the normal flow of the document. Therefore, it would still be taken into consideration whether the .box or its parent would overflow or not.
with set position: absolute; for .menu and position: relative; for .card you able to change the position of .menu with top bottom left right properties relative to its first positioned (not static) ancestor element( .card position ).
but in your question, the absolute or relative position is not the cause of the scrollbar appear . The reason is the owerflow property .
the default value for owerflow is visible that create no owerflowing . And you created the scrollbar by setting it auto because the size of menu is larger than card.
.box {
height: 240px;
width: 200px;
/* overflow: auto; */
border: 1px dashed red;
}
.card {
height: 120px;
width: 120px;
border: 1px solid blue;
position: relative;
}
.menu {
display: none;
height: 400px;
width: 200px;
position: absolute;
top: 0;
left: 0;
background: linear-gradient(orange, pink);
}
.card:hover .menu {
display: block;
}
<div class="box">
<div class="card">
<div class="menu"></div>
</div>
</div>
I am using this layout for responsive div that maintains aspect ratio. It works well, but it requires overflow: hidden, to be clear it's padding-top: 56.25% defined in :after. If there is no overflow on wrapper, next element (in this case href link) is blocked.
My question is: is there a way to achieve same result without overflow: hidden on wrapper? I need some element to be visible outside wrapper without being cutting off.
Open snippet in full page if you can't see the issue within a small window.
#wrapper {
position: relative;
max-width: 1000px;
min-width: 350px;
max-height: 383px;
border: 1px solid;
/*overflow:hidden;*/
}
#wrapper:after {
padding-top: 56.25%;
display: block;
content: '';
background: rgba(0,0,0,.25);
}
<div id="wrapper"></div>
click me
You can add a inner div and make it responsive with a pseudo element like you did before, and apply overflow: hidden; on it. Then add another sibling div and set the style you wish to apply, it would be div #test in the example, as you see it will be visible outside the wrapper.
#wrapper {
position: relative;
max-width: 1000px;
border: 1px solid;
}
#inner {
min-width: 350px;
max-height: 383px;
overflow: hidden;
}
#inner:after {
background: rgba(0,0,0,.25);
padding-top: 56.25%;
display: block;
content: '';
}
#test {
position: absolute;
right: 0;
bottom: 0;
transform: translateY(100%);
width: 100px;
height: 50px;
background: aqua;
}
<div id="wrapper">
<div id="inner"></div>
<div id="test"></div>
</div>
click me
I have a child element with overflow:visible; and the parent element with overflow:hidden;. The child element has height higher than the parent element.
Why the child element is hidden if has the property overflow set to visible?
HTML:
<div id="container">
<div id="makeThisVisible"></div>
<div id="thisRemainsHidden"></div>
</div>
CSS:
#container {
width: 500px;
height: 100px;
border: 1px solid black;
background: Gray;
/*OVERFLOW*/
overflow: hidden;
}
#makeThisVisible {
width: 240px;
height: 300px;
float: left;
border: 1px solid red;
background: IndianRed;
/*OVERFLOW*/
overflow: visible;
margin-left: 8px;
}
#thisRemainsHidden {
width: 240px;
height: 300px;
float: left;
border: 1px solid teal;
background: DarkCyan;
}
The fiddle: http://jsfiddle.net/ewNbu/
To resolve this issue i don't want to use visibility property for #container or position:absolute property for #makeThisVisible, but I want to find another better way to solve the problem.
Please help!
Thank you so much.
You can try playing with:
position:absolute;
which breaks the child out of the scope of the parent element.
DEMO
Is there any css property like min-height, but for top?
In the example below, when i hide div1 (via javascript), i want div2 to have top:50. Else, to be placed below div1.
<html>
<head>
<style>
#div1
{
height:100px;
}
#div2{
//min-top:50px;
}
</style>
</head>
<body>
<div id='div1'>This div may be hidden</div>
<div id='div2'>This div must not be placed above 50px</div>
</body>
</html>
Edit: as i answered below
When div1 is not hidden i want div2 to be exactly below div1. imagine div1 as a treeview which can have any height (or even be hidden) and div2 as a paragraph which should always be below 50px
I came up with this solution which utilises the top:0 bottom:0 hack.
We create a container the height of it's relative parent (if any) - we then give this a min-height (eg your min-top)
We then position the actual element absolutely to the bottom on this container.
CSS:
.container {
position:absolute;
bottom:0px;
top: 0;
min-height: 700px; //Adjust this to your MINIMUM (eg your min-top)
}
.position-me {
position: absolute;
bottom: 0;
}
HTML:
<div class="container">
<div class="position-me">Great!</div>
</div>
"Is there a css min-top property?" no, but ...
... you can use math function to take effect like min-top:
<style>
#div2{
top:max(50px, 10%);
}
</style>
https://developer.mozilla.org/en-US/docs/Web/CSS/max
No there's nothing like min-top
Instead you can use is
div {
position: relative;
top: 50px;
}
And for the example you shown visibility: hidden; will be best suited here, as it will reserve the space of your hidden div
I suspect that this will do the trick for you but I believe it is not a very good practice:
#div1
{
height:100px;
outline: 1px solid red;
margin-bottom:-50px;
}
#div2{
margin-top:50px;
outline: 1px solid blue;
}
DEMO: http://jsfiddle.net/pavloschris/tbbvU/
( Just comment/uncomment the display:none to see it work.)
I see that this question has still many views and people are still commenting. Because of the fact that the question is not fully answered, i decided to write here the complete answer:
Appropriate css:
#div1 {
min-height:50px;
background-color: #fee;
margin-bottom:-50px;
}
#div2 {
margin-top:50px;
background-color: #efe
}
http://jsfiddle.net/vVsAn/5051/
Results
When div1 is hidden, div2 has a top property of 50px
When div1 is not hidden:
If div1 height is less than 50px, then div2 is placed at 50px
If div1 height is more than 50px, then div2 is placed right under div1
$(window).on("resize", function () {
if ($('#div1').css('display', 'none')){
$("#div2").addClass('minTop');
} else if ($('#div1').css('display', 'block')){
$("#div2").removeClass('minTop');
}
}).resize();
#div1{
width:100px;
height:100px;
background-color:#ff0000;
position:absolute;
display:block;
/* display:none; */
}
#div2{
width:100px;
background-color:#ffff00;
top:150px;
position:absolute;
}
#div2.minTop{
top:50px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
</head>
<body>
<div id='div1'>div 1</div>
<div id='div2'>div 2</div>
</body>
</html>
Solution using margins
See also solution using position:sticky.
The following solution uses a css3 selector "directly preceded by" or "placed immediately after" and it works by toggling a predetermined class (.hidden in this example) on the preceding element.
#div1.hidden + #div2 {
margin-top: 50px;
}
.hidden {
display: none;
}
const toggle = () => div1.classList.toggle('hidden')
#div1.hidden + #div2 {
margin-top: 50px;
}
.hidden {
display: none;
}
div {
border: 1px solid red;
height: 100px;
margin-bottom: 10px;
}
section {
position: absolute;
border: 1px solid blue;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 10px;
overflow: hidden;
margin: 5px;
}
aside {
position: absolute;
top: 40px;
right: 20px;
z-index: 1;
display: flex;
flex-direction: column;
}
<section>
<div id='div1'>This div may be hidden</div>
<div id='div2'>This div must not be placed above 50px</div>
</section>
<aside>
<button type="button" onclick="toggle()">Toggle #div1</button>
</aside>
Solution using position: sticky
See also solution using margins.
To achieve somewhat similar you can use position: sticky. It's not exactly same as top-min would have ideally been, but it can be tweaked cleverly with parent styles to achieve what you have in mind.
.sticky {
/* Note: The parent element must have a non-default position set too. */
position: sticky;
top: 50px;
}
Note: The parent of position:sticky element must have a non-default position set as well.
What this does is that when the element moves up by either scrolling, reducing viewport height or layout changes, it will stick to the defined position and will not move until the parent element itself crosses the boundary and pushes the element out of the way (as seen in animation below).
const toggle = () => div1.classList.toggle('hidden')
const toggleSticky = () => div2.classList.toggle('sticky')
.sticky {
position: sticky;
top: 50px;
}
.hidden {
display: none;
}
section {
/* Note: The parent of position:sticky element must have a non-default position set. */
position: absolute;
border: 1px solid blue;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 10px;
overflow: hidden;
margin: 5px;
}
div {
border: 1px solid red;
height: 100px;
margin-bottom: 10px;
}
aside {
position: absolute;
top: 40px;
right: 20px;
z-index: 1;
display: flex;
flex-direction: column;
}
<section>
<div id='div1'>This div may be hidden</div>
<div id='div2' class="sticky">This div must not be placed above 50px</div>
</section>
<aside>
<button type="button" onclick="toggle()">Toggle #div1</button>
<button type="button" onclick="toggleSticky()">Toggle #div2 sticky</button>
</aside>
I am looking to overlay a caption on to an image. I have managed to do this, but the image is expanding out of the parent div.
I have the containing div set to inline-block, as I want it to 'auto size', not take up width: 100%. If you look at the current output, you'll see the image could be within the black bordered box.
It only needs to work in Chrome, if you encounter cross-browser issues.
Thanks in advance!
LIVE DEMO
CSS:
#body_content {
border: solid 1px blue;
display: inline-block;
padding: 5px;
}
#body_header {
border: solid 1px red;
font-size: 25px;
padding: 5px;
}
#body_image {
position: absolute;
}
#body_image_caption {
color: white;
line-height: 30px;
margin-left: 10px;
}
#body_image_container {
background: white;
border: solid 1px black;
margin-top: 3px;
padding: 10px;
}
#body_image_overlay {
background-color: black;
bottom: 5px;
display: block;
height: 30px;
opacity: 0.85;
position: absolute;
width: 100%;
}
HTML:
<div id="body_content">
<div id="body_header">
Heading
</div>
<div id="body_image_container">
<div id="body_image">
<img src="http://i.imgur.com/s6G8n.jpg" width="200" height="200" />
<div id="body_image_overlay">
<div id="body_image_caption">
Some Text
</div>
</div>
</div>
</div>
</div>
The #body_image element is escaping from the #body_image_container because its position is set to absolute. Absolutely positioned elements are removed from the document's flow, causing parent elements to collapse as though the child element wasn't there. If you change it to relative, then it becomes contained within the black box:
#body_image{
position: relative;
}
http://jsfiddle.net/AaXTm/2/
Try this css in parent div.
Overflow:auto
Check this fiddle. You need to set the position of the child element of the image to be absolute and the parent element to be relative. Change the width of the caption accordingly.
child-element {
position:absolute;
}
parent-element {
position:relative
}
http://jsfiddle.net/AaXTm/4/