I need to display some elements inline so they wrap when they fill the viewport width. I'd prefer to use flex with - easy and maintainable, gap clearly defined - instead of inline or floats - you need to use margins for the gap, then avoid ugly wraps using negative margin...
Problem is I am not being able to do it when the items to align are nested on different parents. Example of the tags I'd like to align:
div wrapper:
ul list of some related items
li item
li item
span item not in list
span item not in list
I am attaching a demo, where the structgure is repeated 3 times, each time offering less width to showcase how the items wrap. The ul behaves perfectly as an inline element, until it has to wrap, then it behaves as a block element.
div {
border: 1px solid blue; /* for easier debugging */
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 40px; /* just visual separation between the 3 examples */
}
div:nth-of-type(2) {
max-width: 450px; /* stretcher just to show how items wrap */
}
div:nth-of-type(3) {
max-width: 250px; /* stretcher just to show how items wrap */
}
ul {
border: 1px solid green; /* for easier debugging */
display: inline-flex;
flex-wrap: wrap;
gap: 20px;
}
li, span {
border: 1px solid red; /* for easier debugging */
display: inline;
}
<div>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
<span>Action 1</span>
<span>Action 2</span>
<span>Action 3</span>
</div>
<!-- structure repeats 3 times -->
<p>This wraps okay</p>
<div>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
<span>Action 1</span>
<span>Action 2</span>
<span>Action 3</span>
</div>
<p>The UL pushed next inline elements to a new line :(</p>
<div>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
<span>Action 1</span>
<span>Action 2</span>
<span>Action 3</span>
</div>
Use the display: contents property on the ul element, which allows the child elements to be treated as if they were direct children of the parent container.
ul {
display: contents;
}
Can also use display: inline-block on the li and span elements instead of display: inline which allow them to have their own layout. Also you can use white-space: nowrap on the ul to prevent it from breaking to a new line.
li, span {
display: inline-block;
}
ul {
white-space: nowrap;
}
* {
/* just for reset and for remove all margins and paddings */
box-sizing: border-box;
margin: 0;
padding: 0;
}
div {
border: 1px solid blue;
/* for easier debugging */
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 40px;
/* just visual separation between the 3 examples */
}
div:nth-of-type(2) {
max-width: 450px;
/* stretcher just to show how items wrap */
}
div:nth-of-type(3) {
/* max-width: 250px; */
max-width: fit-content;
/* is like 488px, but is resizable*/
/* you wrong, the ul by default doesn't
push to next line any elements,
you have did a static width
of maximum 250px...*/
/* stretcher just to show how items wrap */
}
ul {
border: 1px solid green;
/* for easier debugging */
display: inline-flex;
flex-wrap: wrap;
gap: 20px;
}
li, span {
border: 1px solid red;
/* for easier debugging */
display: inline;
}
<div>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
<span>Action 1</span>
<span>Action 2</span>
<span>Action 3</span>
</div>
<!-- structure repeats 3 times -->
<p>This wraps okay</p>
<div>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
<span>Action 1</span>
<span>Action 2</span>
<span>Action 3</span>
</div>
<p>The UL pushed next inline elements to a new line :(</p>
<div>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
<span>Action 1</span>
<span>Action 2</span>
<span>Action 3</span>
</div>
You have did a "static" width on 2nd child of max(250px) and then, they can't wrap anymore beacuse they were already wrapped.
Related
I am trying to recreate alignment of divs with unequal heights.
Here is the JSFiddle link: jsfiddle
As per the example give if only 1 child exists it should be centered, otherwise the children should be side by side in 2 columns. I achieved that using flex but I'm facing an issue that if the height of children is big it is leaving a big space as shown in fiddle with div "weird space above this box"
SCSS code:
body {
background: grey;
}
.container {
max-width: 500px;
ul {
list-style-type: none;
background: white;
padding: 30px;
display: flex;
flex-wrap: wrap;
justify-content: center;
>li {
border: 2px solid black;
width: 42%;
height: fit-content;
padding: 5px;
margin: 10px;
}
}
}
HTML:
<div class="container">
<ul class="parent">
<li>child 1 </li>
</ul>
</div>
<div class="container">
<ul class="parent">
<li>child 1 </li>
<li>child 2 child 2</li>
</ul>
</div>
<div class="container">
<ul class="parent">
<li>child 1 </li>
<li>child 2 child 2</li>
<li>child child child child child child child child v child child child child child child child child child child child child child child </li>
<li>child child</li>
<li>child child</li>
<li>weird space above this box</li>
<li>child child</li>
</ul>
</div>
I think what you are asking for is the two columns to be equal height? Remove height: fit-content; from the > li css block and the heights should grow to be equal.
You can remove height property from child. This will result in both the child taking full height.
height: fit-content;
How can I align the nav items, Page One and Page Two so that they present to the left rather than to the right? I can move the content center and to the end, but I simply need to move the two nav items to the left and the flexbox option don't seem to allow me to do so? Please help, thank you.
#box1 {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#list1 {
display: flex;
align-content: space-between;
}
.list2 {
list-style-type: none;
}
main {
display: flex;
flex: 1;
flex-wrap: wrap;
}
<div id="list1">
<nav>
<ul class="list2">
<li>Page One</li>
<li>Page Two</li>
</ul>
</nav>
</div>
If mean to have the nav anchors to be aligned left to each other you can simply add flex-inline the li elements if you mean to flex on nav:
.list2 {
list-style-type: none;
display: inline-flex;
}
.list2 li {
margin-right: 5px;
}
<div id="list1">
<nav >
<ul class="list2">
<li>Page One</li>
<li>Page Two</li>
</ul>
</nav>
</div>
or you can also use inline-block on <li> elements like in this snippet:
.list2 li {
display: inline-block;
}
<div id="list1">
<nav >
<ul class="list2">
<li>Page One</li>
<li>Page Two</li>
</ul>
</nav>
</div>
I'm currently working on a menu consisting of two parts (see image). On mobile, I'd like to show these menu items stacked from top to bottom, but starting with the bottom menu and ending with the top menu. Is there any (clean) way to do this with CSS or will I have to create two menus and show the correct one depending on page width?
EDIT: To clarify, the image is just to show an example of what I mean. I'm wondering in a more general sense if it's possible to somehow reverse the divs in CSS (without absolute positioning etc).
EDIT 2: Apologies for not adding any code. Here's a small pen that shows the situation: https://codepen.io/anon/pen/GWwrMW
<div class="nav">
<ul class="nav__top">
<li>Sub Item 1</li>
<li>Sub Item 2</li>
</ul>
<ul class="nav__primary">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
.nav__top,
.nav__primary {
list-style: none;
margin: 0 0 20px 0;
text-align: right;
li {
display: inline-block;
padding: 10px;
background-color: #ccc;
}
}
On mobile, I want the sub items to be displayed underneath the main items.
You can do this with flex and flex-direction: column-reverse, or for more control, using the order property on flex children. But with your example, flex-direction: column-reverse would work.
.nav__top li,
.nav__primary li {
display: inline-block;
padding: 10px;
background-color: #ccc;
}
#media (max-width: 420px) {
.nav {
display: flex;
flex-direction: column-reverse;
}
.nav li {
display: list-item;
}
}
<div class="nav">
<ul class="nav__top">
<li>Sub Item 1</li>
<li>Sub Item 2</li>
</ul>
<ul class="nav__primary">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
This added CSS will reverse the order in the second menu:
.nav__primary {
display: flex;
flex-direction: row-reverse;
}
You can put it in a media query.
https://codepen.io/anon/pen/ryQjdg
ADDITION: I overread the wish of it to be stacked horizontally. In this case you need
.nav__primary {
display: flex;
flex-direction: column-reverse;
}
If you want responsive nav bar you have to use media queries. Something like this
#media screen and (max-width: 600px){
ul.topnav li {float: none;}}
This will work if your menu was built by list.
Figured it out. Since I only need to support mobile browsers I can use Flexbox:
.nav {
display: flex;
flex-direction: column-reverse;
}
I'm currently trying to make a sidebar layout work. I feel like I'm nearly there but the last bit is just not working.
html,body {
width: 100%;
height: 100%;
}
#wrapper {
display: flex;
width: 100%;
height: 100%;
}
.sidebar {
height: 100%;
position: fixed;
width: 200px;
background: red;
overflow: auto;
flex-direction: column;
display: flex;
}
ul {
padding: 0;
margin: 0;
}
.menu {
flex: 1;
background: rgb(150,0,0);
}
.users {
overflow: auto;
max-height: 240px;
min-height: 100px;
}
<div id="wrapper">
<div class="sidebar">
<ul class="menu">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
</ul>
<ul class="users">
<li>user 1</li>
<li>user 2</li>
<li>user 3</li>
</ul>
</div>
<div class="content">
</div>
</div>
Here is a fiddle of the layout which works better to see the issue than the above snippet:
https://jsfiddle.net/ybp4og8w/1/
All works great except when the height of the window gets really small, smaller than the menu items list. The content at the bottom disappears off screen. Ideally I'd like to have the user list sticky at the bottom (which is correct right now but I've also had this issue when messing with the code), not overlap the menu items when the height gets small but instead make the sidebar become scroll-able.
Any tips on how to achieve this?
I see your jsfiddle and apply this code in #sidebar
overflow-y:scroll;
May be this helpful.
Thanks!
With a simple html list like in the example below, how do I get the list items to center when it goes onto a second line?
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
</ul>
</div>
.container{max-width:500px;}
li{display:block;float:left;background:grey;}
http://jsfiddle.net/hzazvwte/
When the container is shrunk and the menu items start dropping into the line below, I would like them to be centered. How can I achieve this?
You have to remove float, set text-align: center; to the container, inline-block to items, reset margin / padding and eliminate white spacing between elements.
.container {
max-width: 500px;
margin: 0 auto;
text-align: center;
}
ul {
margin: 0;
padding: 0;
}
li {
display: inline-block;
/* float: left; */
background: grey;
margin: 0;
}
Fiddle: http://jsfiddle.net/hzazvwte/4/
Do you mean the text in the li items?
.container{max-width:300px;}
li{
display:block;
float:left;
background:grey;
width: 100px;
text-align: center;
}