Sempervivum
Sempervivum

Reputation: 948

CSS flex layout: wrapping when adding padding or margin

I'm trying to create a navigation bar, a logo at the left and the links centered in the remaining space. I followed the instructions in this thread: In CSS Flexbox, why are there no "justify-items" and "justify-self" properties? and used margin:auto; for the ul in order to get it centered. This worked fine so far but when I add margin or padding anywhere inside the ul the list of links wraps. I tried box-sizing:border-box; for the ul but no success. How can I fix this? Fiddle: http://jsfiddle.net/30sy5dmy/5/

nav img {
  height: 60px;
}

nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.links {
  margin: auto;
}

nav ul li {
  display: inline-block;
  list-style: none;
  margin: 0 2%;
}
<nav>
  <img src="https://teststein.000webhostapp.com/Logo.png">
  <ul class="links">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
  </ul>
</nav>

Upvotes: 1

Views: 3742

Answers (2)

Michael Benjamin
Michael Benjamin

Reputation: 372264

The list items are wrapping because you're using percentage margins.

When you give the items horizontal margins of 2%, the browser calculates the length of that 2% after the size of the container has been determined. In other words, the percentages are not factored into the container width.

Therefore, when the 2% length is added to the items, the total length exceeds that of the container and wrapping occurs.

Solution #1: white-space: nowrap

One way to fix the problem is by suppressing line breaks in the container using the white-space property. This forces all items to stay on the same line, overflowing the container if necessary.

nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px dashed black;   /* for demo only */
}

nav img {
  height: 60px;
}

.links {
  margin: auto;
  white-space: nowrap;     /* NEW */
  padding: 0;              /* optional; remove default indentation on list elements */
  border: 1px dashed red;  /* for demo only */
}

nav ul li {
  display: inline-block;
  list-style: none;
  margin: 0 2%;
}
<nav>
  <img src="http://lorempixel.com/output/nature-q-c-60-60-1.jpg">
  <ul class="links">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
  </ul>
</nav>


Solution #2: Don't use percentage values

If you use any value other than percentages, the list items won't wrap because, unlike percentage values, they can expand the container for accommodation.

nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px dashed black;   /* for demo only */
}

nav img {
  height: 60px;
}

.links {
  margin: auto;
  padding: 0;              /* optional; remove default indentation on list elements */
  border: 1px dashed red;  /* for demo only */
}

nav ul li {
  display: inline-block;
  list-style: none;
  margin: 0 1em;            /* adjustment */
}
<nav>
  <img src="http://lorempixel.com/output/nature-q-c-60-60-1.jpg">
  <ul class="links">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
  </ul>
</nav>


Solution #3: Use flexbox

An initial setting of a flex container is flex-direction: row and flex-wrap: nowrap. This means that flex items will line up horizontally and cannot wrap.

nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px dashed black;   /* for demo only */
}

nav img {
  height: 60px;
}

.links {
  margin: auto;
  padding: 0;              /* optional; remove default indentation on list elements */
  border: 1px dashed red;  /* for demo only */
  display: flex;           /* new */
}

nav ul li {
  display: inline-block;
  list-style: none;
  margin: 0 1em;            /* adjustment; avoid percentage margins on flex items;
                               see this post:
                               https://stackoverflow.com/q/36783190/3597276 */
}
<nav>
  <img src="http://lorempixel.com/output/nature-q-c-60-60-1.jpg">
  <ul class="links">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
  </ul>
</nav>


Solution #4: Clean and Efficient Method

This solution attempts to use the least possible code to achieve the goal. Hope it helps.

nav             { display: flex; align-items: center; }
nav img         { height: 60px; }
a:first-of-type { margin-left: auto; }
a:last-of-type  { margin-right: auto; }
a + a           { margin-left: 1em; }
<nav>
    <img src="http://lorempixel.com/output/nature-q-c-60-60-1.jpg">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 2</a>
    <a href="#">Link 2</a>
</nav>

Upvotes: 3

Asons
Asons

Reputation: 87313

Simply add display: flex to the links, and then, as using percent for margins on flex items doesn't render the same cross browser, use i.e. viewport units instead.

nav img {
  height: 60px;
}
nav {
  display: flex;
  align-items: center;
}
.links {
  display: flex;
  margin: auto;
}
nav ul li {
  list-style: none;
  margin: 0 2vw;
}
<nav>
  <img src="http://lorempixel.com/output/nature-q-c-60-60-1.jpg">
  <ul class="links">
    <li><a href="#">Link 1</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
    <li><a href="#">Link 2</a></li>
  </ul>
</nav>

Upvotes: 1

Related Questions