Setting wrapper div to position absolute shrinks wrapper to arbitrary width - css

I'm running into an issue with position: absolute and I can't find an answer anywhere that explains why it's happening.
I have a flexbox container inside a wrapper with two children that are each set to flex-basis: 50%. When I set position: absolute on the wrapper div, the wrapper shrinks in an unpredictable way.
See the code below:
.outer-wrapper {
position: relative;
width: 100%;
}
.outer-wrapper .wrapper {
position: absolute;
}
.outer-wrapper .wrapper .flex-container {
display: flex;
}
.outer-wrapper .wrapper .flex-container .flex-item {
flex-basis: 50%;
}
<div class="outer-wrapper">
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
</div>
Removing line 6 in the CSS causes the flex-container to expand to the full width of the parent and each flex child takes up 50% of the width, as expected. However, when I set the wrapper div to position: absolute, the wrapper div shrinks to what seems like an arbitrary width and the text in the flex-children breaks onto multiple lines.
My questions:
Why does setting position: absolute on the wrapper div cause the wrapper div to shrink smaller than its content?
How does the browser determine what width to shrink the wrapper div to? It seems to me like it would either shrink to be as small as possible without introducing line breaks into the text, or would shrink as small as possible while still fitting the longest word, but instead it's shrinking to somewhere in the middle (it only introduces one line break in a string of short words).
Is there a way, while still using flexbox and position: absolute in this way, to force the browser to not shrink the wrapper smaller than its content (unless there is a max-width set on the wrapper)?
Really appreciate any help! This has been driving me crazy!

Why does setting position: absolute on the wrapper div cause the wrapper div to shrink smaller than its content?
How does the browser determine what width to shrink the wrapper div to?
The trick is the use of flex-basis::50%. You are in a situation where you are using a shrink-to-fit container (position:absolute element) and at the same time you are using percentage value inside the flex-basis. So the browser is first calculating the width of the container (ignoring the flex-basis) then the width calculated will be used as reference for the flex-basis.
Here is an illustration of what is happening:
.wrapper {
position: absolute;
border:1px solid red;
}
.wrapper .flex-container {
display: flex;
}
.wrapper .flex-container .flex-item {
/*flex-basis: 50%;*/
border:1px solid green;
}
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
<div class="wrapper" style="top:100px;">
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text That Is Long
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
</div>
Notice how in the first example (without flex-basis) the width is equal to the largest content. In the second example you will see that the total width didn't change but we made the flex items equal in width.
The same logic also happen with inline-block or float or any shrink-to-fit container.
.wrapper {
display:inline-block;
border:1px solid red;
}
.wrapper .flex-container {
display: flex;
}
.wrapper .flex-container .flex-item {
/*flex-basis: 50%;*/
border:1px solid green;
}
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>
<br><br>
<div class="wrapper">
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text That Is Long
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
<div class="flex-item" style="flex-basis: 50%;">
Some Text
</div>
</div>
</div>
To get what you want it's clear that you need to not use flex-basis:50% and consider a different idea to get the same width.
Here is one using CSS grid as I think it would be tedious with flexbox:
.wrapper {
position:absolute;
border:1px solid red;
}
.wrapper .flex-container {
display: grid;
grid-template-columns:repeat(2,1fr);
}
.wrapper .flex-container .flex-item {
border:1px solid green;
}
<div class="wrapper">
<div class="flex-container">
<div class="flex-item">
Some Text That Is Long
</div>
<div class="flex-item">
Some Text
</div>
</div>
<div class="flex-container">
<div class="flex-item">
Some Text
</div>
<div class="flex-item">
Some Text
</div>
</div>
</div>

The reason it is shrinking is since you are setting position absolute without specifying a width.
Block element feature of having the full width of the parent's content area will not be honored when an element is absolute positioned.
If you want to retain the width (100% of the container) of a block element, then set the width of the absolute element .wrapper to 100% and problem solved.
.outer-wrapper {
position: relative;
width: 100%;
}
.wrapper {
position: absolute;
width:100%;
}
.flex-container {
display: flex;
}
.flex-item {
flex-basis: 50%;
}

Related

Wesbite scrolls despite overflow-y

Please see the Fiddle example.
The website scrolls entirely despite overflow-y configured onto the DIV of the orange area.
If the list within the orange area is shorter, it works perfectly: The website doesn't scroll, only a scrollbar appears on the right side of the area.
But if the inner content grows, there's a point that website begins to scroll.
How can I avoid that behavior? Doesn't matter how long the orange content is, only that area should scroll.
I'm using Bootstrap 4.
... links to fiddle must be accompanied by code...
Hoping i understood you well.Try this using bootstrap:
<div class="row">
<div class="col ">
<div class="d-flex flex-column bd-highlight mb-3">
<div class="p-2 flex-even bd-highlight bg-primary" >Heading</div>
<div class="p-2 flex-even bd-highlight bg-warning yellow">
</div>
<div class="p-2 flex-even bd-highlight bg-secondary">Flex item 3</div>
</div>
</div>
<div class="col bg-success Context">Context</div>
</div>
Styling:
.row{
height: 100vh;
padding: 0;
margin: 0;
}
.row >div{
padding: 0;
margin: 0;
}
.Context{
height: 100%;
overflow-y: scroll;
}
.flex-even {
height: 32.5vh;
}
.yellow{
overflow-y: scroll;
}

How to to center anchor and img to be responsive

<div class="testt">
<div class="test">
<img src="4.jpg">
test
</div>
<div class="test">
<img src="5.jpg">
test
</div>
<div class="test">
<img src="7.jpg">
test
</div>
<div class="test">
<img src="6.jpg">
test
</div>
If you can help me for the pictures to be one line and the anchor beneath them nicely centered and also to be responsive for all devices
You can use display: flex; on the parent and that will put everything on one line, give it a relative width so that it scales with the viewport, assign text-align: center; to the .test divs to center the contents, and give the img a max-width: 100% so that it scales with the parent size.
.testt {
display: flex;
width: 90%;
margin: auto;
}
.test {
text-align: center;
}
.test img {
max-width: 100%;
display: block;
}
<div class="testt">
<div class="test">
<img src="http://kenwheeler.github.io/slick/img/fonz1.png">
test
</div>
<div class="test">
<img src="http://kenwheeler.github.io/slick/img/fonz1.png">
test
</div>
<div class="test">
<img src="http://kenwheeler.github.io/slick/img/fonz1.png">
test
</div>
</div>

Non-wrapping CSS Flex with fixed widths

I'm building a Carousel-type component, but am having some difficulty getting it to work just right.
My basic approach is a div (wrapper) with lots of other divs (items) in it. I want to display 4 items on the carousel at any one time. The items have various content heights, but the heights of the items should be equal (to the largest required).
I can't work out the CSS combination I need to get this to work correctly.
With this setup (HTML + CSS at bottom of post), the width: 25%; on each item-container is ignored.
If I add a fixed with to .item, then the 25% kicks in, but the item width is unknown -- it depends on the browsers size. Setting it to 1000px means you lose content from the item. Setting it to ~210px works, but when you start shrinking your browser, you lose content. On a large browser, you have excessive spacing.
Curiously, if I add flex-wrap: wrap to the CSS, then the 25% width is applied correctly -- but I can't do that, because then it's not a carousel! Example
The scenario is simple:
An unknown amount of items in a div with overflow: auto, which are equal heights should be displayed, with 4 of the children divs on the screen at any one time.
My HTML is structured as follows:
<div id="container">
<div id="wrapper">
<div class="item-container">
<div class="item">
<p>
Carousel Item #1 with some quite long text.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #2.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #3.
</p>
</div>
</div>
...
</div>
</div>
My CSS:
#container {
width: 100%;
background: #0f0;
overflow: auto;
}
#wrapper {
display: flex;
}
.item-container {
border: 1px solid #f00;
width: 25%;
}
Note, this is my MCVE. On my real component, I have buttons for scrolling left and right, the content is significantly more complex and stuff like that.
All you need is to add flex: 0 0 auto to .item-container elements.
* {
box-sizing: border-box;
}
#container {
width: 100%;
background: #0f0;
overflow: auto;
}
#wrapper {
display: flex;
}
.item-container {
border: 1px solid #f00;
flex: 0 0 auto;
width: 25%;
}
<div id="container">
<div id="wrapper">
<div class="item-container">
<div class="item">
<p>
Carousel Item #1 with some quite long text.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #2.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #3.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #4.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #5.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #6.
</p>
</div>
</div>
<div class="item-container">
<div class="item">
<p>
Carousel Item #7.
</p>
</div>
</div>
</div>
</div>

Input field should take the remaining width

I am trying to build a form to add new users to some kind of entity. The idea is to have user avatars in a line and on the end of the line there is a input-field with a typeahead to insert new users.
I tried this some years ago and ended up using javascript as I was not able to do this in plain css (2).
The big question: is this somehow possible in css3?
Basic idea of code:
<div class="availableWidth">
<div class="list">
<ul>
<li><div class="avatar">...</div></li>
...
</ul>
</div>
<div class="form">
<div class="typeaheadField">
<input ...>
</div>
<button>+</button>
</div>
</div>
CSS:
.list ul li {
list-style-type:none;
display:inline-block;
}
button {
width:50px;
}
Basic Idea is that the box .availableWidth has some width (100%) the box .list grows in width (when new li items are added) as the box .form should shrink in width. Right to the input is a some pixels wide button. The input should take the remaining space.
Is that possible in css3 or will I need Javascript?
You can use flexbox, or you can use display table attributes in CSS. Take a look:
.container {
display: table;
width: 100%;
position:relative;
}
.avatar {
width: 50px;
height: 50px;
display: table-cell;
}
.input {
height: 50px;
display:table-cell;
vertical-align: middle;
}
.input input {
width: 100%;
box-sizing: border-box;
padding: 5px;
}
<div class="container">
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="input">
<input type="text"/>
</div>
</div>
<div class="container">
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="avatar">
<img src="http://dummyimage.com/50x50/000/fff&text=Avatar"/>
</div>
<div class="input">
<input type="text"/>
</div>
</div>
You can add all the avatars that you want at left side and the input rearrange automatically.
You want to make input 100% width relative to some container from avatars to button. You can get it by using table, flexboxes or formatting contexts and floats.
Here is last one http://jsfiddle.net/53f0yzeL/
Notice overflow:hidden rule for .avatars-wrapper, it make container to fit exactly between floated elements and .avatars side so you can make input 100% wide.

CSS same height blocks

I have a jsfiddle here - http://jsfiddle.net/ktmzk3jk/
I'd like to make the red background on the blocks the same height.
I'm sure I could do it with Jquery but is there a standard CSS soultion.
<div class="container">
<div class="row">
<div class="col-sm-4 col">
<div class="block">
<h3>65%</h3>
<p>Some Text Some Text</p>
</div>
</div>
<div class="col-sm-4 col">
<div class="block">
<h3>20%</h3>
<p>Some Text Some Text Some Text Some Text Some Text Some Text Some Text Some Text Some Text Some Text</p>
</div>
</div>
<div class="col-sm-4 col">
<div class="block">
<h3>5%</h3>
<p>Some Text Some Text Some Text Some Text Some Text Some Text Some Text Some Text</p>
</div>
</div>
</div>
</div>
Try like this DEMO
CSS:
.row-full-height {
height: 100%;
}
.col-full-height {
height: 100%;
vertical-align: middle;
}
.row-same-height {
display: table;
width: 100%;
/* fix overflow */
table-layout: fixed;
}
.col-xs-height {
display: table-cell;
float: none !important;
}
HTML:
<div class="row">
<div class="row-same-height row-full-height">
<div class="col-sm-4 col-xs-height col-full-height">...</div>
</div>
</div>
You shouldn't style that inner <div class="block"> , in fact you shouldn't even have it there;
directly style the .col selector,
here you have a fiddle.
For equal size red blocks, you need to update value of height in .block, set height to height:150px instead of height:100% if you know the maximum height. Otherwise also include overflow:auto; so that a scroll appears if text goes beyond the boundary
Updated JS Fiddle: http://jsfiddle.net/ktmzk3jk/8/
Adding a min-height to would be the best approach but I would recommend a jQuery approach. Especially if the content changes to different lengths often.

Resources