How to style nth-child alternating in flexbox - css

I like to build a grid-like construct where my first and every odd row have two flex elements by each other in f.e. 60% and 40% width and in my second and every even row these elements have opposite widths meaning 40% and 60% (reversed).
Sure I would define every element by hand, but when I just a frontend framework I like to generate these elements programmatically and that's where the struggle comes in.
I prepare the static version here: https://play.tailwindcss.com/dqiZBooPhQ
How can I determine which element gets the 60% and which gets the 40%?

I made a simple sample with css flexbox for you
CSS:
div {
min-width: 200px;
height: 25px;
}
.wrapper {
width: 500px;
display: flex;
flex-direction: column;
}
.wrapper > div {
display: flex;
}
.wrapper > div:nth-child(even) {
width: 100%;
background-color: #f00;
}
.wrapper > div:nth-child(even) > div:first-child {
width: 40%;
border: 1px solid black;
}
.wrapper > div:nth-child(even) > div:last-child {
width: 60%;
border: 1px solid black;
}
.wrapper > div:nth-child(odd) {
width: 100%;
background-color: #0f0;
}
.wrapper > div:nth-child(odd) > div:first-child {
width: 60%;
border: 1px solid black;
}
.wrapper > div:nth-child(odd) > div:last-child {
width: 40%;
border: 1px solid black;
}
and HTML
<div class="wrapper">
<div id="first">
<div class="a">test</div>
<div class="b">test</div>
</div>
<div id="second">
<div class="a">test</div>
<div class="b">test</div>
</div>
<div id="third">
<div class="a">test</div>
<div class="b">test</div>
</div>
</div>

Related

Styling layout with flexbox

How should I style using flexbox to get a layout like this? I'm hesitant to use grid as it has limited support on IE11. I'd love to make it possible to add more or less small divs and not to add more containers for small divs
HTML for the layout is looking like this:Desired Layout image
.container {
display: flex;
}
.large {
height: 200px width: 150px;
border: 1px solid black;
}
.small {
height: 100px;
width: 150px;
border: 1px solid black;
}
<div class="container">
<div class="large">1</div>
<div class="small">2</div>
<div class="small">3</div>
<div class="small">4</div>
<div class="small">5</div>
</div>
I would use css-grid over flexbox, here is an example:
tutorial here, current specifications here
.container {
display: grid;
grid-template-columns: 60px 60px 60px 60px 60px;
grid-template-rows: 30px 30px;
grid-auto-flow: column;
}
.container div {
border:1px solid gold;
}
.item-a {
grid-column: 1;
grid-row: 1 / 3;
}
<section class="container">
<div class="item-a">item-a</div>
<div class="item-b">item-b</div>
<div class="item-c">item-c</div>
<div class="item-d">item-d</div>
<div class="item-e">item-e</div>
</section>
I added a parent div for .small divs and I used margin and flex-wrap. But I suggest use grid for you.
.container {
display: flex;
}
.large {
height: 220px;
width: 150px;
border: 1px solid black;
box-sizing:border-box;
margin:10px;
}
.small_cont {
width:340px;
display:flex;
height:200px;
flex-wrap:wrap;
}
.small {
height: 100px;
width: 150px;
border: 1px solid black;
box-sizing:border-box;
margin:10px;
}
<div class="container">
<div class="large">1</div>
<div class="small_cont">
<div class="small">2</div>
<div class="small">3</div>
<div class="small">4</div>
<div class="small">5</div>
</div>
</div>

flexbox how to achieve this specific layout?

Like in the image - http://i65.tinypic.com/aa7ndw.png Examples and live flex configurators are explain only simple examples, or I just don't get it.
Will I be able to use media queries to for example not display a4 when < 800px?
I have always used float and flex is somehow 'different' anyway I would like to know it better, so any help is appreciated.
flex specific example
Apply display: flex to a container and its child elements will be displayed in flex. For this layout, you will want to wrap the elements when width is already filled for the current row.
The header and footer will be width: 100%, taking a full row. #a3 and #a4 will have flex: 1 to distribute the width of their row, taking each one 50% of the width.
div.flex-container{
width: 200px;
height: 300px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
#a1, #a2{
width: 100%;
}
#a3, #a4{
flex: 1;
}
#a5, #a6, #a7{
height: 50px;
width: 80%;
margin: auto;
margin-bottom: 1rem;
}
/* Example styles */
div{
text-align: center;
}
#a1{
background-color: red;
}
#a2{
background-color: limegreen;
}
#a3{
background-color: royalblue;
}
#a4{
background-color: cyan;
}
#a5, #a6, #a7{
background-color: fuchsia;
}
<div class="flex-container">
<div id="a1">a1</div>
<div id="a3">a3</div>
<div id="a4">a4
<div id="a5">a5</div>
<div id="a6">a6</div>
<div id="a7">a7</div>
</div>
<div id="a2">a2</div>
</div>
And yeah, you can use media queries as normal
div.flex-container{
width: 200px;
height: 300px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
#a1, #a2{
width: 100%;
}
#a3, #a4{
flex: 1;
}
#a5, #a6, #a7{
height: 50px;
width: 80%;
margin: auto;
margin-bottom: 1rem;
}
#media (max-width: 800px){
#a4{
display: none;
}
}
/* Example styles */
div{
text-align: center;
}
#a1{
background-color: red;
}
#a2{
background-color: limegreen;
}
#a3{
background-color: royalblue;
}
#a4{
background-color: cyan;
}
#a5, #a6, #a7{
background-color: fuchsia;
}
<div class="flex-container">
<div id="a1">a1</div>
<div id="a3">a3</div>
<div id="a4">a4
<div id="a5">a5</div>
<div id="a6">a6</div>
<div id="a7">a7</div>
</div>
<div id="a2">a2</div>
</div>

Responsive flexbox layout wrap issue

I have these two different layouts illustrated in the code below. My issue is that I can't replicate these layouts without changing the markup. I was wondering if there was some fancy flexbox way I can accomplish exactly this while only using one html scheme. Note: the container will need to have a dynamic height. The solution doesn't necessarily have to use flexbox as long as the desired layout is achieved.
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
display: flex;
flex-wrap: wrap;
}
.a {
background: red;
width: 40%;
}
.b {
background: blue;
width: 60%;
}
.c {
background: green;
}
.a-mobile {
background: red;
width: 40%;
}
.b-mobile {
background: blue;
width: 60%;
}
.c-mobile {
background: green;
width: 100%;
}
<h2>Desktop</h2>
<main>
<div class="a">a</div>
<div class="b">b
<div class="c">c</div>
</div>
</main>
<h2>Mobile</h2>
<main>
<div class="a-mobile">a-mobile</div>
<div class="b-mobile">b-mobile</div>
<div class="c-mobile">c-mobile</div>
</main>
display:grid will be useful for this kind of layout:
but this is still experimental and(2020) can be tested in few browsers, see also http://caniuse.com/#search=grid
A tutorial among others https://css-tricks.com/snippets/css/complete-guide-grid/
main {
display: grid;
grid-template-columns: 30% auto;
}
.a {
background: red;
grid-row-end: span 2
}
.b,
.c {
background: green;
}
.c {
background: lightblue
}
#media screen and (max-width: 700px) {/* value setted for the demo */
.a {
grid-row-end: span 1/* reset optionnal in this very case */
}
.c {
grid-column-end: span 2
}
}
<main>
<div class="a"> break point set at 700px for demo</div>
<div class="b"> i don't move much myself :)</div>
<div class="c"> see in full page to see me aside the red box and below the green one</div>
</main>
codepen to play with
Here's the float-flexbox method I described in the comments. Not particularly fond of it, but it does exactly what you asked for.
It's hacky and, from my POV, goes in the same category as Bootstrap 3's .clearfix::before|after hack — {display:table; content: " ";} — it is a practical solution to a real layout problem, usable until a better, cleaner one will have better browser support and render this one obsolete.
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
display: flex;
flex-wrap: wrap;
margin-bottom: 1em;
color: white;
}
.a {
background: red;
flex-basis: 40%;
}
.b {
background: blue;
flex-basis: 60%;
}
.c {
background: green;
flex-basis: 100%;
}
#media (min-width: 800px) {
main {
display: block;
overflow: hidden;
}
.a {
float: left;
min-width: 40%;
}
.b,.c {
padding-left: 40%;
}
.a,.c {
padding-bottom: 32768px;
margin-bottom: -32768px;
}
}
<main>
<div class="a">a<br />a<br />a<br/>a</div>
<div class="b">b</div>
<div class="c">c</div>
</main>
<main>
<div class="a">a</div>
<div class="b">b<br />b<br />b<br/>b</div>
<div class="c">c</div>
</main>
<main>
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c<br />c<br />c<br/>c</div>
</main>
Another solution, it's independent of flex box, and does not need fixed height.
Flexbox does not do a good job of adjusting to two dimensional layouts!
html {
height: 100%;
}
body {
height: 100%;
}
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
height: 100%;
}
.a {
background: red;
width: 40%;
height: 100%;
float: left;
}
.b {
background: blue;
width: 60%;
height: 50%;
float: left;
}
.c {
background: green;
width: 60%;
height: 50%;
float: left;
}
#media (max-width: 800px) {
.a {
width: 40%;
height: 50%;
}
.c {
width: 100%;
}
}
<h2>Desktop and Mobile</h2>
<main>
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</main>

Fix width of a flex column based on another

I have a wrapper of 500px and 2 columns. The second column is 200px width (flex: 0 0 200px).
If in the first there is an element > 300px the first column will expand according to this element.
How can I stop the first column from growing, basing only the width of the wrapper and the second column?
Fiddle here: https://jsfiddle.net/b58aatdr/3/
#hello {
display: flex;
width: 500px;
}
#hello > div {
height: 50px;
}
#hello > div:first-child {
background-color: yellow;
}
#hello > div:last-child {
background-color: red;
flex: 0 0 200px;
}
#baddiv {
width: 400px;
height: 20px;
background-color: purple;
}
<div id="hello">
<div>
<div id="baddiv"></div>
</div>
<div></div>
</div>
Set max-width: 300px to your first div if you want it to adjust itself up to 300px and use width: 300px; if you want it to always be 300px even if content is less wide.
Update based on comment
The 2:nd div group uses another trick, position: absolute, where one doesn't need to set any width, it uses the parent and the right div to restrict the left div from growing beyond the 300px.
Note also, this is a normal behavior how element works, if they don't have a fixed/max width set, they grow (or in some cases wrap) to fit their content.
Update 2 based on comment
The 3:rd div group uses display: table instead of flex, where one doesn't need to set any width.
.hello {
display: flex;
width: 500px;
}
.hello > div {
height: 50px;
}
.hello > div:last-child {
background-color: red;
flex: 0 0 200px;
}
.baddiv {
width: 400px;
height: 20px;
background-color: purple;
}
/* alt. 1 */
.hello.nr1 > div:first-child {
background-color: yellow;
max-width: 300px;
}
/* alt. 2 */
.hello.nr2 > div:first-child {
flex: 1;
position: relative;
background-color: lime;
}
.inner {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
/* alt. 3 */
.hello.nr3 {
display: table;
table-layout: fixed;
width: 500px;
}
.hello.nr3 > div {
height: 50px;
display: table-cell;
}
.hello.nr3 > div:first-child {
background-color: cyan;
}
.hello.nr3 > div:last-child {
background-color: red;
width: 200px;
}
<div class="hello nr1">
<div>
<div class="baddiv"></div>
</div>
<div></div>
</div>
<br>
<div class="hello nr2">
<div>
<div class="inner">
<div class="baddiv">
</div>
</div>
</div>
<div></div>
</div>
<br>
<div class="hello nr3">
<div>
<div class="baddiv"></div>
</div>
<div></div>
</div>

Force display: table element to not overstep parent element width

How can I prevent the display: table element overstepping its parent element width?
Here is a jsFiddle of the below:
.container {
max-width: 150px;
padding: 5px;
border: 2px solid #0f0;
}
.table {
display: table;
border: 1px solid #00f;
max-width: 100%;
}
.cell {
display: table-cell;
}
.cell:nth-child(2) {
background: #f00;
}
<div class="container">
<div class="table">
<span class="cell">
<select>
<option>long long long long long desc</option>
</select>
</span>
<span class="cell">A</span>
</div>
</div>
In effect, the .table element is wider than .container.
How can I prevent that and keep max-width of .table 100% of parent element? (max-width is not working).
I'm looking for pure CSS solution.
Very simple:
Demo http://jsfiddle.net/zpfLxkrh/3/
you need two things:
.table{
table-layout: fixed;
width: 100%;
}
select {
max-width: 100%;
}
The problem is not your display: table div... it is your select.
If you want to keep that width, make it behave!
select {
width: 100%;
}
Example
The select size will now be controlled by its cell size. I have changed the cell sizes to 50% to illustrate this.
.container {
max-width: 150px;
padding: 5px;
border: 2px solid #0f0;
}
.table {
display: table;
border: 1px solid #00f;
max-width: 100%;
}
.cell {
display: table-cell;
width: 50%;
}
.cell:nth-child(2) {
background: #f00;
}
select {
width: 100%;
}
<div class="container">
<div class="table">
<span class="cell">
<select>
<option>long long long long long desc</option>
</select>
</span>
<span class="cell">A</span>
</div>
</div>

Resources