How would I go about absolutely positioning the child to the right side of the parent (with margin on all sides of the child element)? Why does the child cause the parent (with a min-height) to generate a scrollbar when the child falls outside of the normal flow of the document? What must I do to get rid of that scrollbar?
Alternatively, how could I use the calc() function in the context of a relative position of the child so I get the same outcome?
* {
box-sizing: border-box;
}
.box {
width: 50%;
min-height: 400px;
margin: 50px auto;
background: hsl(220, 80%, 50%);
overflow: auto;
position: relative;
}
.child {
width: 200px;
margin: 20px;
min-height: inherit;
background: firebrick;
position: absolute;
right: 0;
}
<div class="box">
<div class="child"></div>
</div>
The min-height: inherit; on the child inherits the value from the parent which is 400px, and the margin: 20px; makes the total height over 100%, and you have overflow: auto; sets there, it means the scrollbar will appear if the container couldn't hold the content inside.
If they are in the normal content flow, the scrollbar won't appear, since it is min-height, the container will adjust the height to fit the content. However, in the relative and absolute positions, the absolute box is taken out the normal flow, the container won't able to adjust the height to fit automatically, and that will cause the overflow when the child's height exceeds.
To get rid of the scrollbar, you can use calc() function like you mentioned. You just need to set min-height: calc(100% - 40px); on the child. Or, change overflow value to hidden on the parent, the output will be different though.
By the way, since you have box-sizing: border-box; declared, but it does not do anything for margin.
Related
I have a case where the fixed element is 'positioned' - in a way - relative to the parent container and not the browser window...
.container {
position: relative;
width: 640px;
margin: 0 auto;
}
.options {
position: fixed;
bottom: 0;
width: 100%;
}
.options button {
float: left;
box-sizing: border-box;
width: 25%;
}
<div class="container">
<div class="options">
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
</div>
</div>
The div containing the buttons is fixed, and the bottom offset is set to 0. However, the div is offset a certain distance, and starts at the same horizontal distance as the parent container. Now once I set the left offset value to '0' the element positions itself as expected, starting from the edge of the viewport. So I understand that this isn't actually positioned in relation to the parent container. But why is there an offset initially? I'm guessing the default 'auto' setting computes that left value to something other than zero. But how is this value computed?
Also, another point of confusion arose with how the width value is computed, when the value is 100% vs inherit. I looked up and realized that the difference between the two is that while 'width: 100%' sets the width to 100% of the computed value of the parent element, 'width: inherit' takes up the CSS value of the parent literally and applies that to the element. So in the case of the sample I shared above, while the former will set the width of the div containing the buttons to literally 100% of its own parent's computed width, the latter will set to width to '640px', which is the parent's CSS value. The issue I have is, in the first case, where the width is set in percentages, the element is wider than expected. The computed width appears to be computed from the viewport width i.e. 100% of the viewport, and not the parent element, which is what I expected.
If 'width: inherit' acquires the width of 640px from the parent element, then why is the width inherited from the viewport if width is set to 100%, and not the computed value of the parent. Why is it that in one case, the preceding container is considered as the parent from which the value is inherited, and in the other case the viewport is the parent from which the value is computed?
But why is there an offset initially?
That's the case with position values other than static and sticky (fixed, absolute) they keep their parent offsets.
Demo:
*,
*:after,
*:before {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body * {
padding: 10px;
border: 1px solid;
}
body {
text-align: center;
}
[container] {
position: relative;
width: 120px;
margin: 50px;
padding: 30px;
display: inline-block;
}
[absolute] {
position: absolute;
}
[fixed] {
position: fixed;
}
<div container>
<div absolute>absolute</div>
</div>
<br/>
<div container>
<div fixed>fixed</div>
</div>
As you can see even with position applied, the elements don't suddenly jump around to where they're expected to be. You can try adding left:0 add see how they move.
Width: inherit or 100%; ?
Like i said before:
percentage is relative to the containing block, that changes according to css rules, inherit keyword is relative to the parent element defined in the markup and that never changes with css
Much more accurate MDN explanation
Percentage values that are applied to the width, height, padding, margin, and offset properties of an absolutely positioned element (i.e., which has its position set to absolute or fixed) are computed from the element's containing block.
Demo
[container] {
background: orange;
position: relative;
width: 300px;
height: 100px;
transform: translate(0)
}
[fixed] {
background: red;
position: fixed;
width: 100%;
left: 0;
}
<div container>
<div fixed>fixed</div>
</div>
In this example width:100% is behaving as it should because we changed the congaing block of the fixed element using transform: translate(0)
There's many ways to change the containing block of an element i suggest you read up the MDN article on that.
body have a padding per default. You can add padding: 0 to make your fixed element go as far to the left as possible, or add left: 0 to your fixed .options element.
You shouldn't use fixed width (640px), because you should code with responsiveness in mind.
You shouldn't use float in layout, because it mess up the box size of the object. Only use it on images if you want the text to "float" around the image.
html, body { /* ADDED */
margin: 0;
padding: 0;
}
.container {
position: relative;
width: 100%; /* CHANGED */
margin: 0 auto;
/* ADDED */
min-width: 640px;
}
.options {
position: fixed;
bottom: 0;
width: 100%;
/*left: 0; if you don't want to change the padding for the body */
/* ADDED */
display: flex;
}
.options button {
/*float: left;*/
box-sizing: border-box;
/* width: 25%; */
/* ADDED */
flex: 1 1 auto; /* grow / shrink / auto-adjust in width */
}
<div class="container">
<div class="options">
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
</div>
</div>
I have issues with understanding the div position (relative, absolute, fixed) properties. I basically have an absolute div centered. Inside the div it should be possible to scroll vertically and horizontally. Inside this div should be a fixed header with a width larger than to screen (overflow) and a content div which has an overflow vertically and horizontally as well.
html,
body {
height: 100%;
width: 100%;
background: #fff;
margin: 0px auto;
padding: 0px auto;
position: fixed;
}
.container {
width: calc(100% - 20px);
height: calc(100% - 20px);
top: 10px;
left: 10px;
background: #2924aa;
overflow: scroll;
display: flex;
position: absolute;
z-index: 20;
}
.container-header {
width: calc(100%);
height: calc(10%);
background: #2924aa;
overflow: visible;
z-index: 10;
position: fixed;
background: red;
}
.container-body {
width: calc(110%);
height: calc(110%);
background: #2924aa;
overflow: auto;
position: absolute;
background: green;
}
<div class="container">
<div class="container-header"></div>
<div class="container-body"></div>
</div>
Here is my plunker:
https://plnkr.co/edit/wCWvHPcuYmVMql5HulHy
So i think the main question you have is in regards to the Position Attribute in CSS3. Below is a brief summary of each possible value.
CSS Positioning
The CSS positioning attribute of position has four different values.
Static - Static is the default value for position. It keeps the element on the page in its place, and it scrolls up the page as you scroll.
Relative - Relative positioning is pretty much as the same as static; however, you can use the left, right, top, and bottom attributes to alter the placement of the element relative to its original position.
Fixed - A fixed element's position is in relation to the viewport (i.e. the browser) therefore, an element with a fixed position does not scroll with the page, because when you scroll the viewport does not change. However, if you resize the browser, the element will change position.
Absolute - A element with an absolute position, is positioned relative to its parent element (i.e. the element that contains it).
A good resource for more information, including some diagrams can be found here.
I'm trying to put two divs with 50% width beside one another, they are inline-blocks.
The problem is, I also wish to add other elements that affect the width, such as margin, padding, borders, etc. I am quite alright to have a few pixels to be hidden off the side of the window. (In fact, I'd prefer it)
Whats the trick exactly?
How can I have two inline divs that don't stack on top of each other when they hit the maximum width of their parent. Is there some default positioning that inline-blocks have?
EDIT: Here is an example of code. It seems rather simple to me, but they just wont line up.
.parent {
overflow: hidden;
position: relative;
width: 100%;
height: 300px;
}
.child {
display: inline-block;
overflow: hidden;
position: relative;
width: 50%;
height: 100%;
margin: 1px;
}
<div class="parent">
<div class="child">content</div>
<div class="child">content</div>
</div>
The reason they won't stack is because you have set the margin to 1px and then the width to be 50% of the available width. So each child was in fact 50% + 1px + 1px (for left and right) in width which would exceed the available width of 100% by 4px.
Try either with padding, or margin, or reduce the width of the parents. You could also do:
width: calc(50% - 2px);
Also, the nature of inline-block makes it trickier to align elements next to each other if they add up to exactly (or near) 100%.
You can solve this by either setting the parent to have a font-size of 0 and the children to anything greater than 0. Or, you could set each child to float: left
Demo 1 (using floats)
Demo 2 (using floats, and calc())
Demo 3 (setting font-size to 0)
For padding and borders you can use box-sizing: border-box; on your child element.
border-box: "The width and height properties (and min/max properties) includes content, padding and border, but not the margin"
source: box-sizing
I think for margin you need to cut some space off your .children. For example: width: 49.5%; margin: 1%;
As Mike suggested, try to use box-sizing: border-box.it will work only if you specify padding instead of margin.
But in this case, even with padding and border-box, still you would not be able to place them side by side as inline-block elements create a small gap in between..
More you can find out https://css-tricks.com/fighting-the-space-between-inline-block-elements/
If you are ok with few pixels to be hidden off the side of the window, you can add white-space: nowrap; to the parent.
.parent {
overflow: hidden;
position: relative;
width: 100%;
height: 300px;
white-space:nowrap;
}
.child {
display: inline-block;
position: relative;
width: 50%;
height: 100%;
margin: 1%;
}
For the record, these solutions seemed to be the most reliable:
width: calc(50% - 2px) (Worked with float: left;)
border-sizing: border-box; (Worked with border: 1px solid #fff;)
white-space: nowrap; (worked circumstantially.)
Thank you to everyone who has contributed.
This was the sort of clarity I was looking for. Knowing multiple ways to solve this issue is abundantly helpful.
In the following fiddle:
http://jsfiddle.net/6qF7Q/1/
I have a yellow content area that has a min-height set to 100% - it's the background div to all pages and should take up at least 100% of the available height. If there's overflow, it expands vertically.
Then, within that yellow container, I have another child div (red) that I would like to take up as much vertical space as its parent. It seems I can't set height because the parent element only has min-height, and setting min-height on the red element doesn't work either.
So right now, the yellow is behaving as I'd like, but the red is not expanding. How can this be achieved with CSS only?
CSS:
.browser {
background-color: blue;
height: 600px;
width: 200px;
position: relative;
}
.innercontent {
min-height: 100%;
background-color: red;
width: 100%;
color: white;
padding: 2px;
}
.content {
background-color: yellow;
width: 100%;
min-height: calc(100% - 30px);
}
.footer {
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
background-color: orange;
height: 20px;
}
HTML:
<div class="browser">
<div class="content">
<div class="innercontent">
This is the problem - I need this to take up 100% of the remaining yellow space, without setting the parent element's 'height' - only min-height is specified in the parent because I need to make sure that it takes up 100% of the height at least, but allow it to extend vertically if there's any overflow.
</div>
should not see any yellow
</div>
<div class="footer"></div>
</div>
Take a look at this
I added this
*{
box-sizing: border-box;
}
html, body {
/* Make the body to be as tall as browser window */
height: 100%;
}
and changed some attributes u can see at fiddle
If thats what you want you should read this article
http://css-tricks.com/a-couple-of-use-cases-for-calc/
I made that based in this use-cases
I think this might solve your issue?
I have changed the innercontent to position: absolute
http://jsfiddle.net/6qF7Q/7/
If you have text in the yellow section it will always show.
Also, you're going to have to do a bit of fiddling to get your footer positioned correctly since you are going to have an overflowing absolute element. I think a full body position: relative wrapper will solve it.
P.S I don't see why you would need a .content AND a .innercontent if you don't want the .content to show?
This works much better and doesn't give you footer grief: http://jsfiddle.net/6qF7Q/9/
I have one element below another and I am using position relative to drag the bottom element up just a bit so that it overlays the top element.
The paperOverlay element is the last element on the page, vertically speaking, and I want it to extend to the bottom of the browser window. However, the relative nudging of the element's position leaves an equal amount of whitespace at the bottom. Is there any way to avoid this?
The HTML looks like:
div class="container">
<div class="homePage">
<!-- some content -->
</div>
<div class="paperOverlay" style="position: relative; top: -70px;">
<!-- some more content -->
</div>
</div>
And the CSS looks like:
div.container
{
width: 960px;
margin: 0 auto;
}
div.homePage
{
width: 800px;
height: 500px;
}
div.paperOverlay
{
width: 960px;
min-height: 400px;
background: url('Images/Overlay.png') no-repeat top center;
}
Basically, the bottom layer is a white background with a torn paper edge effect at the top. The goal is to have the torn paper edge slightly overlay the bottom of the element above it. I did try margin-top: -70px as suggested below and it fixed the height, but now the elements in the top element lay on top of the overlay, and I want the overlay to be on top.
Could you try a negative margin rather than relative positioning? Also, could you explain a little bit more why you need to do this and post you css so that we can better suggest a solution?
Try setting the height of the paperOverlay element. It should be the actual height minus the amount moved relatively.
I did try margin-top: -70px as suggested below and it fixed the height, but now the elements in the top element lay on top of the overlay, and I want the overlay to be on top.
Try this:
div.container
{
margin: 0 auto;
width: 960px;
}
div.homePage
{
height: 500px;
position: relative;
width: 800px;
z-index: 1;
}
div.paperOverlay
{
background: url('Images/Overlay.png') no-repeat top center;
min-height: 400px;
position: relative;
top: -70px;
/* you can optionally use bottom: 70px; rather than top: -70px */
width: 960px;
z-index: 2;
}
Using position: relative; on both elements and setting the z-index should get the overlay on top of the top element, rather than the other way around.
You may also want to try using display: block; on all elements where you need fixed width/height (especially divs and other containers that need a fixed width/height, like anchors or list items), to prevent collapsing. It will usually resize non-block-level elements to fit their contents and ignore width and height rules otherwise.
Using the "vh" unit worked for me. I could not get it to work with height: calc(100%-50px)
#main-nav{
width: 55px;
background-color: white;
transition: 400ms;
height: calc(100vh - 50px);
}