I'm having a vertical list of several items. Every item is a two column layout made with flexbox. The left column has a fixed width. The right column contains arbitrary text and should take all the available space.
When the windows gets narrower, I still want a two column layout. Here the second column should get smaller and the text inside should wrap.
When the windows gets even narrower (second column is roughly the same size as the first column), I want the second column to move under the first.
I simply gave the first column a fixed width and put flex-wrap: wrap on the container. The problem is, that the flex-wrap already kicks in when the text in the right column is more than one line. It "has priority over" the text-wrap within the second column.
How can I create the layout described above?
I created a codepen with my issue to play around with: https://codepen.io/maxwell89/pen/PoWrBzJ.
main {
border: thin solid black;
}
article {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
article header {
margin-right: 2em;
width: 5em;
background-color: red;
}
article section {
background-color: blue;
}
<body>
<main>
<article>
<header>Header1</header>
<section>iaOIsadjio jiasdj asd you asda sad iaeojrasod aosidjasdjias diojsadiojas oidjasjio dasijod asd</section>
</article>
<article>
<header>Header2</header>
<section>Something short</section>
</article>
</main>
</body>
Try resizing the browser window and you see that the first item wraps way too early.
You need to set the flex-basis of the second element to be equal to the width of the first one. Doing this, you will trigger the wrap when that width cannot fit inside the container.
main {
border: thin solid black;
}
article {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
article header {
margin-right: 2em;
width: 5em;
background-color: red;
}
article section {
background-color: blue;
flex-basis: 5em;
flex-grow: 1;
}
<main>
<article>
<header>Header1</header>
<section>iaOIsadjio jiasdj asd you asda sad iaeojrasod aosidjasdjias diojsadiojas oidjasjio dasijod asd</section>
</article>
<article>
<header>Header2</header>
<section>Something short</section>
</article>
</main>
Related
I have a grid that's two columns side by side. However, there's an odd number of elements, so I would like to offset the right column so it's centered vertically against the left column.
What would be the best way to do that using grid?
Here's an example how i want the layout to look:
Here's an example: https://codepen.io/patricktm/pen/JjMzQWj
body {
max-width: 1000px;
margin: auto;
}
.grid-item {
background-color: #ccc;
border: 1px solid;
height: 200px;
}
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1em;
}
<body>
<div class='grid'>
<div class='grid-item'>1</div>
<div class='grid-item'>2</div>
<div class='grid-item'>3</div>
<div class='grid-item'>4</div>
<div class='grid-item'>5</div>
<div class='grid-item'>6</div>
<div class='grid-item'>7</div>
</div>
</body>
This layout isn't really feasible with Grid because there are fix row tracks that prevent the free flow of items across the column.
You're basically asking the top item in the second column to somehow space itself down in the first row track and cross into the second track, pushing down the other items along the way.
Grid doesn't work this way. The matter is discussed in detail in this post:
Aligning grid items across the entire row/column (like flex items can)
One simple way to make this layout work uses flexbox, which has no column or row tracks crossing through the flex lines. (You'll have to tweak it though, as my simple example will only work on taller screens. On shorter screens additional columns will be generated.)
.grid {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center; /* key */
height: 100vh;
gap: 1em;
}
.grid-item {
background-color: #ccc;
border: 1px solid;
height: 21%; /* prevents a 5th item in the column */
}
body {
max-width: 1000px;
margin: auto;
}
<div class='grid'>
<div class='grid-item'>1</div>
<div class='grid-item'>2</div>
<div class='grid-item'>3</div>
<div class='grid-item'>4</div>
<div class='grid-item'>5</div>
<div class='grid-item'>6</div>
<div class='grid-item'>7</div>
</div>
I have three elements I'm trying to align in my layout.
First, I have a div for feedback, and then a search input, and then a div element for suggestions.
I want the first and last element to have a width of 20%, and the search input to have a width of 60%. Using Flexbox I achieve what I want.
But there's a feature that grows all the divs to the highest element. This means that when search results pop up, the feedback and suggestion elements grow in height with the search div resulting in a messed up layout.
Is there a trick to not grow the divs with the highest element? Just make the divs (#feedback and #suggestions) have the height of the content in them?
#container_add_movies {
display: flex;
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>
Feedback
</div>
<div id='search'>
Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>
</div>
<div id='suggestions'>
Suggestions
</div>
</div>
http://codepen.io/alucardu/pen/PPjRzY
You're encountering the flex equal height columns feature.
An initial setting of a flex container is align-items: stretch.
This means that flex items automatically expand the full length of the cross axis of the container. In a row-direction container, the cross axis is vertical (height).
The tallest item sets the height for all siblings. As the tallest item expands, its siblings follow along. Hence, equal height for all items.
To override this default setting, add align-items: flex-start to the flex container:
#container_add_movies {
display: flex;
align-items: flex-start;
}
#container_add_movies {
display: flex;
align-items: flex-start; /* NEW */
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
display: block;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
... or align-self: flex-start to the flex items:
#feedback {
align-self: flex-start;
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start;
width: 20%;
background-color: yellow;
}
#container_add_movies {
display: flex;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#feedback {
align-self: flex-start; /* NEW */
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start; /* NEW */
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
align-items sets the default value of align-self. With align-self you can override the default on individual items.
More details in the spec:
8.3. Cross-axis Alignment: the align-items and align-self
properties
Flex items can be aligned in the cross axis of the current line of the
flex container, similar to justify-content but in the perpendicular
direction.
align-items sets the default alignment for all of the flex
container’s items, including anonymous flex items.
align-self allows this default alignment to be overridden for
individual flex items.
A bit of history
Since the beginnings of CSS, there have been two layout challenges that have regularly frustrated, perplexed, and annoyed front-end developers:
How to center things, especially vertically, and
How to create equal height columns (tables aside)
Today, with the advent of flexbox, these problems are over.
Centering things has never been easier:
#container {
display: flex;
justify-content: center; /* center flex items along the main axis */
align-items: center; /* center flex items along the cross axis */
}
Simple. Easy. Efficient. The craziness is over.
In terms of equal height columns, flexbox also excels: It does this by default.
#container {
display: flex;
flex-direction: row; /* not even necessary; default rule */
align-items: stretch; /* not even necessary; default rule */
}
The align-items: stretch rule tells flex items to expand along the cross-axis as much as possible. Hence, in a row-direction container all items can be equal height. More craziness tamed by flexbox.
From one popular answer for equal height columns:
Give overflow: hidden to the container and large (and equal)
negative margin and positive padding to columns. Note that this
method has some problems, e.g. anchor links won't work within your
layout.
Now that's a hack!
The pendulum is now beginning to swing the other way: Designers are asking how to TURN OFF equal height columns.
You can add align-items: flex-start to your #container_add_movies. Here's an example
to have the unequal columns in bootstrap 4, first of all it needs to know how it is making it equal heights of the columns,so the reason is the
align-items: stretch
to remove this property it need to add align-items: flex-start so for this I have added the class="align-items-start" and the issue is fixed,
Setting the child element that was causing the problem to flex:none did the trick for me.
I have three elements I'm trying to align in my layout.
First, I have a div for feedback, and then a search input, and then a div element for suggestions.
I want the first and last element to have a width of 20%, and the search input to have a width of 60%. Using Flexbox I achieve what I want.
But there's a feature that grows all the divs to the highest element. This means that when search results pop up, the feedback and suggestion elements grow in height with the search div resulting in a messed up layout.
Is there a trick to not grow the divs with the highest element? Just make the divs (#feedback and #suggestions) have the height of the content in them?
#container_add_movies {
display: flex;
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>
Feedback
</div>
<div id='search'>
Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>
</div>
<div id='suggestions'>
Suggestions
</div>
</div>
http://codepen.io/alucardu/pen/PPjRzY
You're encountering the flex equal height columns feature.
An initial setting of a flex container is align-items: stretch.
This means that flex items automatically expand the full length of the cross axis of the container. In a row-direction container, the cross axis is vertical (height).
The tallest item sets the height for all siblings. As the tallest item expands, its siblings follow along. Hence, equal height for all items.
To override this default setting, add align-items: flex-start to the flex container:
#container_add_movies {
display: flex;
align-items: flex-start;
}
#container_add_movies {
display: flex;
align-items: flex-start; /* NEW */
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
display: block;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
... or align-self: flex-start to the flex items:
#feedback {
align-self: flex-start;
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start;
width: 20%;
background-color: yellow;
}
#container_add_movies {
display: flex;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#feedback {
align-self: flex-start; /* NEW */
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start; /* NEW */
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
align-items sets the default value of align-self. With align-self you can override the default on individual items.
More details in the spec:
8.3. Cross-axis Alignment: the align-items and align-self
properties
Flex items can be aligned in the cross axis of the current line of the
flex container, similar to justify-content but in the perpendicular
direction.
align-items sets the default alignment for all of the flex
container’s items, including anonymous flex items.
align-self allows this default alignment to be overridden for
individual flex items.
A bit of history
Since the beginnings of CSS, there have been two layout challenges that have regularly frustrated, perplexed, and annoyed front-end developers:
How to center things, especially vertically, and
How to create equal height columns (tables aside)
Today, with the advent of flexbox, these problems are over.
Centering things has never been easier:
#container {
display: flex;
justify-content: center; /* center flex items along the main axis */
align-items: center; /* center flex items along the cross axis */
}
Simple. Easy. Efficient. The craziness is over.
In terms of equal height columns, flexbox also excels: It does this by default.
#container {
display: flex;
flex-direction: row; /* not even necessary; default rule */
align-items: stretch; /* not even necessary; default rule */
}
The align-items: stretch rule tells flex items to expand along the cross-axis as much as possible. Hence, in a row-direction container all items can be equal height. More craziness tamed by flexbox.
From one popular answer for equal height columns:
Give overflow: hidden to the container and large (and equal)
negative margin and positive padding to columns. Note that this
method has some problems, e.g. anchor links won't work within your
layout.
Now that's a hack!
The pendulum is now beginning to swing the other way: Designers are asking how to TURN OFF equal height columns.
You can add align-items: flex-start to your #container_add_movies. Here's an example
to have the unequal columns in bootstrap 4, first of all it needs to know how it is making it equal heights of the columns,so the reason is the
align-items: stretch
to remove this property it need to add align-items: flex-start so for this I have added the class="align-items-start" and the issue is fixed,
Setting the child element that was causing the problem to flex:none did the trick for me.
I am trying to achive the last example on the following image, using flex-box.
From what I see, the align-items: baseline; property works great when the blocks only have 1 line.
The property align-items: flex-end; creates some issues mainly because the left and right items have different font-sizes and line-heights. Although the edges of the items are aligned, the white space created by the font size and line-height differences looks really bad when the item has no borders.
I'm trying to find a good all-around solution without any JS.
Thanks in advance.
You can wrap the contents of the flex items inside inline-block wrappers:
.flex {
display: flex;
align-items: baseline;
}
.inline-block {
display: inline-block;
}
.item { border: 1px solid red; }
.item:first-child { font-size: 200%; }
.flex::after { content: ''; position: absolute; left: 0; right: 0; border-top: 1px solid blue; }
<div class="flex">
<div class="item">
<div class="inline-block">Lorem<br />Ipsum<br />Dolor</div>
</div>
<div class="item">
<div class="inline-block">Foo bar</div>
</div>
</div>
That will work because, according to CSS 2.1,
The baseline of an 'inline-block' is the baseline of its last line box
in the normal flow, unless it has either no in-flow line
boxes or if its 'overflow' property has a computed value other than
'visible', in which case the baseline is the bottom margin
edge.
At the time of writing the CSS box model alignment working draft proposes a ‘first’ and ‘last’ value to be added to ‘align-items’. The would allow:
align-items: last baseline
Current it only appears to be supported by Firefox so is one for the future.
https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
I have three columns within the flex box container, two visible and one hidden. The first two have very little content; the third one has several pages of content. I want all three to be initially vertically centered, but since the third one will overflow off the page, I want it (when made visible) to end up filling to the top of the page and then scrolling down. How can I have centred items in the flex box that overflow naturally in this way?
What's happening now in my code below is that when the third column is made visible, it overflows off the top and bottom of the page, without scroll, so that its impossible to read the first part of the content.
HTML:
<div class="flex-container">
<div class="column column-left">
column one
</div>
<div class="column column-right">
column two
</div>
<div class="column-hidden column" data-id="1">
column three
</div>
</div>
CSS:
body{
margin:0;
}
html, body{
height: 100%;
}
.flex-container{
height: 100%;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
}
.column{
padding: 0 1em 0 1em;
}
.column-left{
display: visible;
}
.column-right{
display: visible;
border: none;
text-align: left;
}
.column-hidden{
display: none;
}
Javascript:
//clicking on button does the following to show hidden column
$('.column-left').removeClass('column-left').addClass('column-hidden');
$('.column-right').removeClass('column-right').addClass('column-left');
$(".column[data-id='" + id + "']").addClass('column-right').removeClass('column-hidden');
Played a bit with your code. I rearranged align-items from .flex-container to .column, which is also display: flex;. For scrolling I think you should have additional absolutely positioned container for the content.. I used P.
Sample here http://codepen.io/vkjgr/pen/gpqLLZ
p.s. Some hints about your code. flex-direction's initial value is row, so you don't have to write it. And visible is not a property of display ;)