CSS Fixed column width before wrap and full width after wrap - html

What I need
Look at the image for a general idea of what I need. I am avoiding media queries as I have a sidebar on my page which pushes all the main content, which then makes #media queries terrible to work with. I wish container queries was a thing, but I'll have to stick with creating more dynamic css than using a buggy polyfill.
What I have (don't laugh)
This is what I have worked out so far:
.container {
display: flex;
flex-wrap: wrap-reverse; /* a wrapping flexbox */
}
.content {
background: cyan;
min-width: 300px;
height: 200px;
flex: 1;
}
.sidebar {
background: tomato;
min-width: 150px;
max-width: 300px;
flex: 0 0 150px;
}
<div class="container">
<div class="child sidebar">1</div>
<div class="child content">2</div>
</div>
It's pretty much not working at all
I don't need it to be flexbox, it can be grid aswell...

There is a scenerio that you can do that we make our .container max-width:1000px; than we gave
.red flex-grow:3
.blue flex-grow:7
So when they split 1000px together .red will take 300px (flex-grow:3) and .blue will take 700px (flex-grow:7).
After 600px when they both reach their min-width:300px row wrap will happen and they will grow whole container.
body{
min-height: 100vh;
}
.container {
max-width:1000px;
margin:0 auto;
display: flex;
flex-direction: row;
flex-wrap: wrap-reverse;
height: 15rem;
}
.red {
min-width: 300px;
background: tomato;
flex-grow: 3;
flex-shrink: 0;
width:300px;
}
.blue {
background: cyan;
min-width: 500px;
flex-grow: 7;
width:400px;
}
#media screen and (max-width:800px){
.container{
max-width: 400px;
overflow: hidden;
}
}
<div class="container">
<div class="red"></div>
<div class="blue"></div>
</div>

Related

How to make a specific div go on top of another div

I have two divs.
When resizing the browser, div 2 will go on the bottom, and div one will go on the top, something like the image below.
What I want is div 1 to go on the bottom and div 2 go on the top, basically the opposite of what it does. I know I can just put div 2 on the top in the html but I want the div 1 to stay on the left.
Current code:
.div1 {
width: 55%;
height: 80vh;
display: inline-block;
margin-right: 1.5vh;
min-width: 50vh;
}
.div2 {
width: 50vh;
height: 80vh;
display: inline-block;
}
<div class="div1">
</div>
<div class="div2">
</div>
Hope that makes sense, thx to everyone that helps in advance.
The simplest way is to make parent container as display: flex; and use flex-wrap: wrap-reverse;:
.div1 {
width: 55%;
height: 80vh;
display: inline-block;
margin-right: 1.5vh;
min-width: 50vh;
background-color: blue;
}
.div2 {
width: 50vh;
height: 80vh;
display: inline-block;
background-color: red;
}
.container
{
display: flex;
flex-wrap: wrap-reverse;
/* ignore below */
resize: both;
overflow: hidden;
border: 1px solid black;
padding: 1em;
}
<div class="container">
<div class="div1">
</div>
<div class="div2">
</div>
resize me
</div>
You can achieve this by combining two concepts: media queries and flexbox.
I've set the max-width of the screen size that the media query starts applying to 600px, but you can change this to whatever value (min or max) that you want. The switch in how the two divs render when in column-view is handled via flex-direction: column-reverse.
You'll need to wrap your divs in a parent container to apply them:
.container {
display: flex;
flex-direction: row;
}
#media screen and (max-width: 600px) {
.container {
flex-direction: column-reverse;
}
}
.div1 {
width: 55%;
height: 80vh;
display: inline-block;
margin-right: 1.5vh;
min-width: 50vh;
background: green;
}
.div2 {
width: 50vh;
height: 80vh;
display: inline-block;
background: orange;
}
<div class="container">
<div class="div1"></div>
<div class="div2"></div>
</div>
You can read up on the two concepts I mentioned above in more detail:
media queries
flexbox

Content overflowing flex item despite overflow property

I have a pretty simple page setup in the following manner using flexboxes:
The blue div is supposed to make up 25% in height and the violet div 75%. In case there are too many lines in the blue div, it should stay the same size an show a scrollbar. This works for a few lines, but breaks at some point and the blue div overflows and grows into the violet one. I'm new to flexboxes, so I don't really understand why this is happening. Would I be better off not using flexboxes? Thankful for any hints or pointer at this point.
This is the code I use (run in full page):
function lines(noLines) {
var text = "line</br>".repeat(noLines);
document.getElementById("lower").innerHTML = text;
}
* {
box-sizing: border-box;
}
.body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
#static1 {
height: 30px;
width: 100%;
background-color: red;
}
#static2 {
height: 40px;
width: 100%;
background-color: orange;
}
#content {
display: flex;
flex: 1;
}
#left {
width: 40%;
background-color: yellow;
}
#right {
width: 60%;
display: flex;
flex-direction: column;
}
#upper {
flex: 3 0;
background-color: violet;
}
#lower {
flex: 1;
background-color: blue;
overflow: auto;
}
<div class="body">
<div id="static1">Some static div</div>
<div id="static2">Another static div. Flexbox below fills rest of remaining screen.</div>
<div id="content">
<div id="left">
Left part, fixed width in percentage.</br>
Click to enter lines into the bottom right:</br>
<button onclick=lines(20)>Few Lines</button>
<button onclick=lines(200)>Many Lines</button>
</div>
<div id="right">
<div id="upper">Flexbox with flex=3.</div>
<div id="lower">Flexbox with flex=1.</div>
</div>
</div>
</div>
For the overflow property to work properly, the container needs an actual height or max-height. Flex heights (you have flex: 1 on .content) won't cut it.
In order for overflow to have an effect, the block-level container
must have either a set height (height or max-height) or
white-space set to nowrap. ~ MDN
Since you already know the height of the primary container (100vh) and the first two rows (30px and 40px), the rest is simple using the calc() function.
function lines(noLines) {
var text = "line</br>".repeat(noLines);
document.getElementById("lower").innerHTML = text;
}
.body {
display: flex;
flex-direction: column;
height: 100vh; /* adjustment */
}
#static1 {
flex-shrink: 0; /* disable shrinking */
height: 30px;
/* width: 100%; */
background-color: red;
}
#static2 {
flex-shrink: 0; /* disable shrinking */
height: 40px;
/* width: 100%; */
background-color: orange;
}
#content {
height: calc(100vh - 70px); /* new */
display: flex;
/* flex: 1; */ /* may work in some browsers, but not reliable */
}
#left {
width: 40%;
background-color: yellow;
}
#right {
width: 60%;
display: flex;
flex-direction: column;
}
#upper {
flex: 3 0;
background-color: violet;
}
#lower {
flex: 1;
background-color: aqua; /* adjusted for illustration */
overflow: auto;
}
body {
margin: 0; /* new; override browser default */
}
* {
box-sizing: border-box;
}
<div class="body">
<div id="static1">Some static div</div>
<div id="static2">Another static div. Flexbox below fills rest of remaining screen.</div>
<div id="content">
<div id="left">
Left part, fixed width in percentage.<br> Click to enter lines into the bottom right:<br>
<button onclick=lines(20)>Few Lines</button>
<button onclick=lines(200)>Many Lines</button>
</div>
<div id="right">
<div id="upper">Flexbox with flex=3.</div>
<div id="lower">Flexbox with flex=1.</div>
</div>
</div>
</div>
jsFiddle demo
I hope this is what you mean, but If I'm wrong, apologies. The problem I can see lies in the way you are using flex: 1 & flex: 3 to define the proportions of the right column, without specifying to what height their parent container has, i.e. #right has no height, so the box can always expand as it gets more filled with content.
Please try this, I hope this works and if I can answer anything else, just ask please.
The only thing I changed was your CSS and added max-height: calc(100vh - 70px); to the #right div. And changed overflow: auto; to overflow-y: scroll;
* {
box-sizing: border-box;
}
.body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
#static1 {
height: 30px;
width: 100%;
background-color: red;
}
#static2 {
height: 40px;
width: 100%;
background-color: orange;
}
#content {
display: flex;
flex: 1;
}
#left {
width: 40%;
background-color: yellow;
}
#right {
width: 60%;
display: flex;
flex-direction: column;
max-height: calc(100vh - 70px);
}
#upper {
flex: 3;
height: 75%;
background-color: violet;
}
#lower {
flex: 1;
height: 25%;
background-color: blue;
overflow-y: scroll;
}
Change the top part of CSS to this:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

Get 2 divs 1 below other while third fills up the space

Is it possible (without using floats) to achieve having 2 divs one below the other, while the third one fills up the space. However, the following HTML cannot be changed; and also we can't use cannot use floats.
Here is what I tried:
div{
width: 33%;
height: 100px;
background: red;
display: inline-block;
}
.left{
background: blue;
}
.right{
background: green;
}
.middle{
width: 50%;
height: 200px;
}
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
As you can see, the 2 divs on the left are pushed down. Is there a way to make them move up or another way to achieve this altogether?
JS Fiddle for anyone who wants it: https://jsfiddle.net/g6j7nLp5/2/
You can use CSS grid:
body {
display:grid;
grid-template-areas:
"left mid"
"right mid";
grid-gap:10px;
}
.left{
background: blue;
grid-area:left;
}
.right{
background: green;
grid-area:right;
}
.middle{
height: 200px;
grid-area:mid;
background: red;
}
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
As far as I'm aware, you can't do this without adding an extra container.
HTML:
<div class="wrapper">
<div class="item">Hello</div>
<div class="item">hello2</div>
<div class="item">hello3</div>
</div>
CSS:
.wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-flow: column wrap;
flex-flow: column wrap;
height: 500px;
max-width: 500px;
}
.item {
background: lightblue;
width: 50%;
height: 50%;
}
.item:last-child {
width: 100%;
max-width: 100%;
height: 100%;
background-color: green;
}
Check it out on codepen. Good luck!
You want to use flex if you can wrap your three DIVs with a wrapper.
See a jsfiddle
It can't be done without a container (perhaps the <body>) unless you use absolute positioning or floats. Both those might be possible for you (we don't have many details) but they would be problematic.
div{
height: 100px;
}
.wrapper {
display: flex;
width: 100%; // need for compat
}
.left{
background: blue;
flex: 0 0 20px;
}
.right{
background: green;
flex: 0 0 20px;
}
.middle{
background: red;
flex: 1 0 auto;
}

max-width of overflow:scroll element to match flex-grow parent elements width

I have a container #container with a fixed width which has three children .item. Each have a flex-basis of 100px but the middle one .item-grow should grow so that all width of #container is used. This works like expected.
The .item-grow element has another children #too-big which could be wider than the available parent's width so its wrapped inside a #scroll container with overflow: scroll and max-width: 100%.
The problem is, that #scroll ignores max-width: 100% and forces the parent .item-grow to grow which foces the container #container to grow.
If I set max-width: 296px instead of max-width: 100% it works but I am looking for a dynamic (and CSS only) solution.
In the embedded code you can find a slider which changes the size of #too-big, you can clearly see that its growing the parents and not using the scrollbars.
function setSize (newValue) {
let elem = document.getElementById("too-big");
elem.setAttribute("style",`width:${newValue}px; height:${newValue}px`);
}
#container {
background-color: red;
display: flex;
width: 500px;
height: 200px;
}
.item {
display: flex;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 100px;
border: solid black 1px;
background-color: gray;
}
.item-grow {
flex-grow: 1;
align-items: center;
}
.center-wrapper {
margin: auto;
display: table-cell;
}
.scroll {
overflow: scroll;
max-width: 100%; /* I want this respect the current parents width */
/* max-width: 296px; */
max-height: 100%; /* I want this respect the current parents height */
/* max-height: 200px; */
}
#too-big {
background-color: green;
width: 100px;
height: 100px;
}
<input type="range" min=100 max=500 value=100 oninput="setSize(this.value)" onchange="setSize(this.value)">
<div id="container">
<div class="item"></div>
<div class="item item-grow">
<div class="center-wrapper">
<div class="scroll">
<div id="too-big"></div>
</div>
</div>
</div>
<div class="item"></div>
</div>
To make that work you can drop the center-wrapper and set margin: auto on the scroll.
Then the item need min-width: 0 to allow it to be smaller than its content.
And for the max-height: 100% to work (cross browser), the item-grow need a height.
Fiddle demo (with overflow: auto instead)
Stack snippet
function setSize (newValue) {
let elem = document.getElementById("too-big");
elem.setAttribute("style",`width:${newValue}px; height:${newValue}px`);
}
#container {
background-color: red;
display: flex;
width: 500px;
height: 200px;
}
.item {
display: flex;
flex-basis: 100px;
border: solid black 1px;
background-color: gray;
box-sizing: border-box; /* added */
min-width: 0; /* added */
}
.item-grow {
flex-grow: 1;
align-items: center;
height: 100%; /* added */
}
.scroll {
margin: auto; /* added */
overflow: scroll;
max-width: 100%;
max-height: 100%;
}
#too-big {
background-color: green;
width: 100px;
height: 100px;
}
<input type="range" min=100 max=500 value=100 oninput="setSize(this.value)" onchange="setSize(this.value)">
<div id="container">
<div class="item"></div>
<div class="item item-grow">
<div class="scroll">
<div id="too-big"></div>
</div>
</div>
<div class="item"></div>
</div>

Re-sizing and re-ordering elements between desktop and mobile layouts

I'd like to achieve the following with CSS only (left is mobile layout, right is desktop after breakpoint):
The challenge here obviously is that from a float point of view the element order changes: on mobile the green item is the second, but on desktop it's the first.
Is this possible to achieve with pure CSS? Possibility would be flex-box but I don't have enough experience to recreate this layout.
#container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 400px; /* 1 */
}
.box {
width: 50%;
}
.box1 {
background-color: lightgreen;
height: 400px;
}
.box2 {
background-color: orangered;
height: 200px;
}
.box3 {
background-color: aqua;
height: 200px;
}
#media (max-width: 600px) {
#container { height: auto; } /* 2 */
.box { width: 100%; }
.box2 { order: -1; } /* 3 */
}
/* purely decorative styles */
.box {
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.5em;
}
* { box-sizing: border-box; }
<div id="container">
<div class="box box1"><span>1</span></div>
<div class="box box2"><span>2</span></div>
<div class="box box3"><span>3</span></div>
</div>
jsFiddle
Notes:
Without a fixed height in a column wrap container, flex items don't know where to wrap. So, for your larger screen, define a height which forces the second item to a new column.
Now you're in a mobile layout and wrapping is no longer necessary. The container needs to be twice the height of the desktop layout. Release the height.
Tell the red box to re-position itself first on the list. (The initial order value for flex items is 0.)
Yes you can do this if you can set fixed height on flex-container. You just need to use flex-direction: column and flex-wrap: wrap and then change order with media-queries.
.content {
display: flex;
flex-wrap: wrap;
flex-direction: column;
}
.a {
height: 200px;
background: #00FF02;
}
.b {
height: 100px;
background: red;
}
.c {
height: 100px;
background: blue;
}
#media(min-width:768px) {
.content {
height: 200px;
}
.content > div {
width: 50%;
}
}
#media(max-width:768px) {
.b {
order: -1;
}
}
<div class="content">
<div class="a">A</div>
<div class="b">B</div>
<div class="c">C</div>
</div>
There is also no-flex solution, fiddle (just replace media-query min-width with whatever breakpoint you consider phone width ends):
HTML:
<div class="div1"></div>
<div class="div2"></div>
<div class="div3"></div>
CSS:
div {
width: 50%;
}
.div1 {
background-color: red;
float: right;
height: 200px;
}
.div2 {
background-color: green;
float: left;
height: 400px;
}
.div3 {
background-color: blue;
float: right;
height: 200px;
}
#media (max-width: 500px) {
.div1, .div2, .div3 { width: 100%;}
}