I'm trying to create a very basic navigation bar with a horizontal unordered list and flexbox, but my list items are being shifted to the right and I don't understand why.
In my example, I want the list items to be grouped together and centered in the smaller viewport, and evenly distributed in the larger one.
This works as expected, except everything seems shifted slightly to the right. So in the smaller viewport, the content is never quite centered, and in the larger viewport, there's a gap before my first list item.
Using a negative margin helps me in the larger viewport, but not the smaller one.
I'm very new to CSS, so I may have missed something obvious.
.container {
display: flex;
flex-flow: row;
justify-content: space-between;
display: flex;
list-style: none;
background: black;
}
.container a {
text-decoration: none;
color: white;
background: red;
}
#media all and (max-width: 600px) {
.container {
justify-content: center;
}
.container a {
padding: 10px;
}
}
<div>
<ul class="container">
<li>ABOUT</li>
<li>WORK</li>
<li>CONTACT</li>
</ul>
</div>
Codepen
ul elements (your container) has a default padding you need to set to 0.
.container {
display: flex;
justify-content: space-between;
list-style: none;
background: black;
padding: 0; /* added property */
}
.container a {
text-decoration: none;
color: white;
background: red;
}
#media all and (max-width: 600px) {
.container {
justify-content: center;
}
.container a {
padding: 10px;
}
}
<div>
<ul class="container">
<li>ABOUT</li>
<li>WORK</li>
<li>CONTACT</li>
</ul>
</div>
Related
I have a navigation bar and I added a red line on the bottom when hovering any item of the list, but I want to move that red line under the header (something like "Services"), any idea how to achieve this?
I added an small sample in codepen so you can easily check the HTML and CSS code
header {
background-color: lightblue;
padding-top: 1rem;
position: sticky;
top: 0;
display: flex;
align-items: center;
justify-content: space-around;
}
header nav {
min-width: 50%;
}
header nav ul {
margin: 0;
height: 100%;
list-style: none;
padding-left: 0;
display: flex;
align-items: center;
justify-content: space-between;
}
header li:hover {
height: 100%;
border-bottom: 2px solid red;
}
<header>
<a href="/">
<p>Whatever logo</p>
</a>
<nav>
<ul>
<li>About us</li>
<li>Services</li>
<li>Pricing</li>
<li>Blog</li>
</ul>
</nav>
CONTACT
</header>
Link to check the code
You can fix the header height and also fix the height of navbar items.
Also, you had one issue where on hover li elements are moving. You can also fix that with always adding border with transparent color to the element, so the overall height of the element won't change on hover state.
Here is the fixed CSS
header {
background-color: lightblue;
position: sticky;
display: flex;
height: 60px;
align-items: center;
justify-content: space-around;
}
header nav {
min-width: 50%;
}
header nav ul {
margin: 0;
height: 100%;
list-style: none;
padding-left: 0;
display: flex;
align-items: center;
justify-content: space-between;
height: 60px;
}
header li {
display: flex;
align-items: center;
border-bottom: 2px solid transparent;
height: 60px;
}
header li:hover {
border-bottom: 2px solid red;
}
https://codepen.io/swarajgk/pen/JjZewPo?editors=1100
I think just giving height to all list elements the same as the header will work.
Like this:-
header {
background-color: lightblue;
padding-top: 1rem;
height: 3rem;
position: sticky;
top: 0;
display: flex;
align-items: center;
justify-content: space-around;
}
header nav {
min-width: 50%;
height : 100%;
}
header nav ul {
margin: 0;
height: 100%;
list-style: none;
padding-left: 0;
display: flex;
align-items: center;
justify-content: space-between;
}
header li{
height: inherit;
}
header li:hover {
border-bottom: 2px solid red;
}
<body>
<header>
<a href="/"
><p>Whatever logo</p></a>
<nav>
<ul>
<li>About us</li>
<li>Services</li>
<li>Pricing</li>
<li>Blog</li>
</ul>
</nav>
CONTACT
</header>
</body>
Hope this solves the issue.
header {
background-color: lightblue;
padding-top: 1rem;
height: 3rem;
position: sticky;
top: 0;
display: flex;
align-items: center;
justify-content: space-around;
}
header nav {
min-width: 50%;
height : 100%;
}
header nav ul {
margin: 0;
height: 100%;
list-style: none;
padding-left: 0;
display: flex;
align-items: center;
justify-content: space-between;
}
header li{
height: inherit;
}
header li:hover {
border-bottom: 2px solid red;
}
I'd suggest the following approach, with explanatory comments in the CSS:
/* removing default padding and margin from all
elements, and forcing the browser to use the
same sizing algorithm - border-box - to calculate
element sizes, including the padding and border
widths in the declared size: */
*, ::before, ::after {
box-sizing: border-box;
padding: 0;
margin: 0;
}
/* setting common properties for the two element
groups: */
header,
header nav ul {
/* using display: flex layout: */
display: flex;
/* forcing the flex-items within the flex parent
to take the full height of that parent: */
align-items: stretch;
}
header {
background-color: lightblue;
block-size: 3em;
position: sticky;
justify-content: space-around;
}
/* using :is() to combine the two selectors
header a,
header li
into one selector: */
header :is(a, li) {
/* using grid layout: */
display: grid;
/* positioning the - including text - content
at the center of the element: */
place-items: center;
}
header nav {
min-width: 50%;
}
header nav ul {
/* the <ul> isn't a flex-item so we have to specify
that we want it to take all available space on
the block-axis (equivalent to 'height' in left-to-right
languages such as English): */
block-size: 100%;
list-style: none;
justify-content: space-between;
}
header li {
/* to prevent the jumping content: */
border-bottom: 2px solid transparent;
}
header li:hover {
/* to style the color of the bottom border: */
border-bottom-color: red;
}
<header>
<a href="/">
<p>Whatever logo</p>
</a>
<nav>
<ul>
<li>About us</li>
<li>Services</li>
<li>Pricing</li>
<li>Blog</li>
</ul>
</nav>
CONTACT
</header>
JS Fiddle demo.
References:
align-items.
display.
justify-content.
place-items.
Bibliography:
"Aligning items in a flex container," MDN.
"Basic concepts of flexbox," MDN.
"Box alignment in grid layout," MDN.
<ul>
<li>Home</li>
<li>About</li>
<li>Works</li>
<li>Support</li>
Hello, guys, I am trying to have a navigation with flexbox but there is way too much space between the flex items
<ul><li>Blog</li> </ul>
.nav ul {
padding: 0;
display: flex;
align-content: flex-start;
flex-wrap: nowrap;
}
.nav ul li {
flex: 1;
}
Your problem is flex: 1, which tells each individual li to fill all remaining space. This (in your case) effectively breaks the flex-start you define in ul.
You need to change your CSS to the following:
ul {
padding: 0;
display: flex;
justify-content: flex-start;
flex-wrap: nowrap;
}
ul li {
padding-left: 10px; /* or some other padding */
padding-right: 10px;
}
Check out this example: https://codepen.io/anon/pen/vWEPNe
I'm using flexbox for my navigation and I can't seem to get my borders to work right for my media query specified for column wrap.
I want the borders to stretch across the device width completely, for example I want the border all the way from the left to all the way on the right on the device, and I want each a element to take up one 'row' on the device but currently the borders only stretch half way and some of the li elements are sharing a row when others are not and I'm not too sure why. Even when I make a to display block, it's not working. I also tried making flex basis 100% for the a elements.
Edit: I think I figured it out for the positioning. I made the #nav ul. not just #nav column wrap. However, I'm still experiencing the border problem unfortunately.
#nav {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
margin: 0;
flex-flow: row wrap;
justify-content: center;
align-items: center;
background-color: orange;
}
#nav li a {
color: white;
margin: 15px;
padding: 5px;
display: block;
;
text-decoration: none;
font-size: 24px;
font-family: courier;
}
#nav li {
list-style: none;
}
#nav ul {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
margin: 0;
flex-flow: row wrap;
justify-content: center;
align-items: center;
}
#media all and(max-width: 800px) {
#nav {
justify-content: space-around;
}
}
#media all and (max-width: 500px) {
#nav {
flex-flow: column wrap;
padding: 5px;
}
#nav li a {
flex: 1 100%;
display: block;
padding: 5px;
border-top: 1px solid black;
border-bottom: 1px solid black;
}
}
<div id="nav">
<ul>
<li> Calendar </li>
<li> Events </li>
<li> Hours </li>
<li> Contact </li>
<li> About </li>
</ul>
</div>
Try to reset the default padding on ul element.
ul {
padding-left: 0;
}
also reset the default margin on body if needed.
body {
margin: 0;
}
For the flexbox part, you should set display: flex; on #nav ul, rather than #nav. You don't need to set any style on #nav actually. If you want the each li to take 100% width in the media query, you can set flex item to flex: 1 1 100%;, working example in the fiddle below.
#media all and (max-width: 500px) {
#nav li {
flex: 1 1 100%;
padding: 5px;
border-top: 1px solid black;
border-bottom: 1px solid black;
}
}
jsFiddle
I am styling a header of a webpage. I want the header to be a single line which includes a logo and some navigational links. I feel the best, most modern way to layout this header today is with CSS3's flexbox, so that is what I would like to use.
I would like for the logo to be as far left in the flex container as possible, and the remaining navigation items to be as far right as possible. This could easily be achieved by floating the elements left and right, but that is not what I would like to do. So...
How do you align child elements of a flexbox container to opposite far ends of the main axis?
There is a property for the flexbox child elements that allows you to do this on the cross axis, align-self, but it seems there is none to do this on the main axis.
The best way I have come up with to achieve this is to insert an additional, empty, element in between the logo and the navigational links to serve as a spacer. But part of the reason I am choosing to use flexbox for this header is to cohere with a responsive design and I do not know of a way to make the spacing element take up all the remaining space, regardless of the width of the viewing window.
Here is where I currently stand with the mark-up, simplified to only include the elements pertinent to this situation.
HTML
<ul>
<!-- Should be as far left as possible -->
<li id="main">Some Logo <span>Some tag line.</span></li>
<!-- Should be as far right as possible -->
<li>Home</li>
<li>Products</li>
<li>Price Sheet</li>
<li>Capabilities</li>
<li>Contact</li>
</ul>
CSS
ul {
width: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
padding: 0;
margin: 0;
list-style: none;
}
li {
margin: 0 8px;
padding: 8px;
font-size: 1rem;
text-align: center;
font-weight: bold;
color: white;
background: green;
border: solid 4px #333;
}
#main { font-size: 2rem; }
#main span { font-size: 1rem; }
From your question:
I do not know of a way to make the spacing element take up all the remaining space, regardless of the width of the viewing window.
This is exactly what the flex-grow CSS rule was designed for. If only one child element has the flex-grow attribute set, then it will take up all the remaining space in the flex container. The only markup you will need in this case is the following:
HTML:
<li id="spacer"></li>
CSS:
#spacer {
visibility: hidden;
flex-grow: 1;
}
Full Live Demo:
ul {
width: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
padding: 0;
margin: 0;
list-style: none;
}
li {
margin: 0 8px;
padding: 8px;
font-size: 1rem;
text-align: center;
font-weight: bold;
color: white;
background: green;
border: solid 4px #333;
}
#main { font-size: 2rem; }
#main span { font-size: 1rem; }
#spacer {
visibility: hidden;
flex-grow: 1;
}
<ul>
<!-- Should be as far left as possible -->
<li id="main">Some Logo <span>Some tag line.</span></li>
<!-- Spacer element -->
<li id="spacer"></li>
<!-- Should be as far right as possible -->
<li>Home</li>
<li>Products</li>
<li>Price Sheet</li>
<li>Capabilities</li>
<li>Contact</li>
</ul>
JSFiddle Version: https://jsfiddle.net/7oaahkk1/
I think the only flexibility that is needed, at least on large screens, should go on the first flex-item in the list. The one you want to place your logo at.
By setting this items flex-grow rule to 1 and the text-align to left it will stay on the left side, growing in size, making sure all other items stay on the right side. Since the logo may have a greater height value than all the other items it would make sense to change the align-items rule to baseline, making sure all items are horizontally aligned.
Furthermore i have added a few media queries to change the flex settings accordingly.
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: border-box;
}
body {
margin: 0;
}
ul {
width: 100%;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: stretch;
padding: 0;
margin: 0;
list-style: none;
}
li {
margin: 0;
padding: 8px;
font-size: 1rem;
text-align: center;
font-weight: bold;
color: white;
background: green;
border: solid 4px #333;
}
li:first-child {
font-family: sans;
font-size: 2em;
text-align: center;
}
li:first-child span {
font-size: initial;
}
#media (min-width: 34em) {
ul {
flex-flow: row wrap;
justify-content: space-between;
align-items: flex-start;
}
li {
flex: 1;
}
#main {
flex: 0 0 100vw;
}
}
#media (min-width: 48em) {
ul {
justify-content: flex-end;
align-items: baseline;
}
li {
flex: none;
}
#main {
flex: 1 0 auto;
text-align: left;
}
}
<ul>
<!-- Should be as far left as possible -->
<li id="main">Some Logo <span>Some tag line.</span></li>
<!-- Should be as far right as possible -->
<li>Home</li>
<li>Products</li>
<li>Price Sheet</li>
<li>Capabilities</li>
<li>Contact</li>
</ul>
Essentially you need a row container with two child columns
container is a flexible div
column one is a flexed div with the logo
column two is a flexible ul with flexed li's
AND 'justify-content: space-between' to move the columns to the far ends
Check my snippet (full page)!
.container,
.menu {
display: flex;
}
.container {
justify-content: space-between;
width: 100%;
}
.menu {
padding: 0;
margin: 0;
list-style: none;
}
li,
.logo {
margin: 0 8px;
padding: 8px;
font-size: 1rem;
text-align: center;
font-weight: bold;
color: white;
background: green;
border: solid 4px #333;
}
#main {
font-size: 2rem;
}
#main span {
font-size: 1rem;
}
<div class="container">
<div id="main" class="logo">Some Logo <span>Some tag line.</span>
</div>
<ul class="menu">
<li>Home</li>
<li>Products</li>
<li>Price Sheet</li>
<li>Capabilities</li>
<li>Contact</li>
</ul>
</div>
JSfiddle Demo
Wrap a ul over the rest of the list items and use nested flex container. This is to provide flexbox to act on two elements.
Use justify-content: space-between on the main flexbox parent to equally space the two elements.
.parent-menu {
width: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
/* Modify */
align-items: center;
padding: 0;
margin: 0;
list-style: none;
}
li {
margin: 0 8px;
padding: 8px;
font-size: 1rem;
text-align: center;
font-weight: bold;
color: white;
background: green;
border: solid 4px #333;
}
#main {
font-size: 2rem;
}
#main span {
font-size: 1rem;
}
.right-menu {
display: flex;
/* Add */
}
<ul class="parent-menu">
<!-- Should be as far left as possible -->
<li id="main">Some Logo <span>Some tag line.</span>
</li>
<ul class="right-menu">
<!-- Should be as far right as possible -->
<li>Home</li>
<li>Products</li>
<li>Price Sheet</li>
<li>Capabilities</li>
<li>Contact</li>
</ul>
</ul>
One posibility is to set a right margin on the first element
ul {
width: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
padding: 0;
margin: 0;
list-style: none;
}
li {
margin: 0 8px;
padding: 8px;
font-size: 1rem;
text-align: center;
font-weight: bold;
color: white;
background: green;
border: solid 4px #333;
}
#main {
font-size: 2rem;
margin-right: auto; /* create a right margin as needed */
}
#main span { font-size: 1rem; }
#spacer {
visibility: hidden;
flex-grow: 1;
}
<ul>
<!-- Should be as far left as possible -->
<li id="main">Some Logo <span>Some tag line.</span></li>
<!-- Should be as far right as possible -->
<li>Home</li>
<li>Products</li>
<li>Price Sheet</li>
<li>Capabilities</li>
<li>Contact</li>
</ul>
here's what I have Fiddle
ul {
display: flex;
justify-content: flex-start;
flex-direction: row;
align-items: center;
width: 100%;
height: 100px;
background: #333;
padding: 15px;
}
ul li {
padding: 15px;
margin: 5px;
background: #efefef;
border: 1px solid #ccc;
display: inline-block;
list-style: none;
}
#item-1 {
height: 50px;
}
#item-2 {
height: 70px;
}
<ul>
<li id="item-1">Home</li>
<li id="item-2">Menu</li>
<li>More</li>
<li>Stuff</li>
<li>Settings</li>
</ul>
I want the last item inside the flex-box to be pulled to the right ("Settings" in my fiddle) while keeping all other items the way they are. The "Settings"-item should also be centered vertically and everything.
align-self: flex-end pushes the item to the bottom (I want it on the right).
I would very much prefer a solution using flex-box because my items have variable heights and should always be centered vertically.
What is the cleanest way to achieve this?
Thanks for your help!
Simple fix, use an auto-adjusting margin:
ul li:last-child {
margin-left: auto;
}
You may also want to not use width: 100% so that the element stays inside the visible area:
ul {
display: flex;
justify-content: flex-start;
flex-direction: row;
align-items: center;
/* width: 100%; */
height: 100px;
background: #333;
padding: 15px;
}
http://jsfiddle.net/dwLHE/
See also https://www.w3.org/TR/css-flexbox-1/#auto-margins