4
\$\begingroup\$

I've recently migrated away from floats and have started using flexbox to build my grids.

My navigation has 4 menu items. I'd like my logo to sit in the middle of these. To maintain a good page structure for SEO, I don't like the idea of putting my logo within a list item inside the nav.

Instead, I've built a solution that uses flexbox and a negative margin.

/*------------------------
Default grid
-------------------------*/
.flex {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.col {
  flex: 1;
}

/*------------------------
Columns
-------------------------*/
.has-2-columns .col {
  flex: none;
}

.has-2-columns .col {
  width: 49%;
}

/*------------------------
Logo
-------------------------*/
.site-title {
  position: relative; /* Enables z-index */
  z-index: 1; /* Positions logo above .main-navigation */
  width: 80px;
  margin: 0 auto;
  background: #ccc;
}

/*------------------------
Main navigation
-------------------------*/
.main-navigation {
  position: relative;
  margin-top: -24px; /* Brings nav inline with .site-branding */
  z-index: 0; /* Ensures nav is below .site-branding */
}

.main-navigation ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.main-navigation ul li {
  display: inline-block;
}

.left-menu {
  text-align: left;
}

.left-menu li {
  margin-right: 24px;
}

.right-menu {
  text-align: right;
}

.right-menu li {
  margin-left: 24px;
}
<header class="site-header">

  <div class="site-branding">
    <h1 class="site-title"><a href="#" rel="home">Demo</a></h1>
  </div>

  <nav class="main-navigation flex has-2-columns">

    <div class="left-menu col">
      <ul id="left-menu" class="menu">
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
      </ul>
    </div>

    <div class="right-menu col">
      <ul id="right-menu" class="menu">
        <li><a href="#">Contact</a></li>
        <li><a href="#">Store</a></li>
      </ul>
    </div>

  </nav>

</header>

Is there a better way? Would this solution cause issues across different devices when it comes to clicking / tapping the menu items or logo to go back home?

\$\endgroup\$
3
\$\begingroup\$

If you're going to use flex, use flex! Flex inherently helps with margin control.

Margins are great, but you're essentially saying, I want to learn flex, except when it's easier/convenient to go back to what I've been doing.

Some key topics of interest regarding your concerns:

To maintain a good page structure for SEO...

Great! That's a good attitude to have. You should always follow the W3C specs for best practices of what content goes where. If you don't like reading long-winded documentation.. MDN always has a great synopsis of elements/attributes/rules/principals/best practices (usually in a blue box).

Buttttt having a header inside <nav> tags isn't necessarily against standards, in fact, all flow content is permitted. ref

Additionally, in your circumstance, it acts as a main content link, so I would argue it belongs there.

However, keeping in mind the importance of a semantic elements purpose is a very good outlook imo.

Furthermore on this point, I can not tell you how many developers overlook accessibility. Not only does it help you with SEO, it absolutely is critical to how disabled persons rely on their devices. It often takes trivial amount of time to make a website accessible friendly, but developers generally don't consider it because either they themselves aren't disabled and it's in the back of their mind, they haven't had any complaints, they don't work for someone who cares to implement it. But that is beyond the scope of the question, either way you are on the right track with that mentality.

I've recently migrated away from floats and have started using flexbox

Not a bad thing, will definitely make it easier for you, but try not to consider them synonyms. Float properties apply to all elements, even flex, but flex properties do not apply to all elements. With the following caveats:

  • float applies but no effect is taken if display = none
  • float applies but no effect is taken if element is flex

An example of why they are not synonymous is float:left for an <img> tag around text will allow that text to flow around the content, whereas flexbox is ... well a box and the text will maintain in it's rect bounds instead of wrapping around the box next to it.

An important thing to embrace with flex is that as soon as you set an element to display: flex the direct children of that container become flex items. So note the hierarchy there.

Take this example where 'C' is not a direct descendant of .wrapper, therefor it doesn't inherit properties.

.wrapper {
  display: flex;
  flex-flow: column nowrap;
  
  height: 175px; padding: 10px; border-color: red;
}

.b, .c {
   float: right;
   border-color: green;
}
.c {
  background-color: lightgrey;
} 

/** irrelevant **/
div {
  height: 50px;
  border: 1px solid;
}
.a { border-color: blue; }
<div class="wrapper">
  <div class="a">:::::: A :::::::</div>
  <div class"b">
    <div>:::::: B ::::::</div>
    <div class="c">:::::: C ::::::</div>
  </div>
</div>

I bring that up, because navigation items are generally top-level children, so we can consider that in circumstances like margin-top: -24px. You can take the following snippet (unchanged from OP, other than color for effect) and see why it can be problematic real fast, and worse, it can easily create a domino effect where you will have to add margins to a lot of other things just to create synergy:

/*------------------------
Default grid
-------------------------*/

.flex {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.col {
  flex: 1;
}


/*------------------------
Columns
-------------------------*/

.has-2-columns .col {
  flex: none;
}

.has-2-columns .col {
  width: 49%;
}


/*------------------------
Logo
-------------------------*/

.site-title {
  position: relative;
  /* Enables z-index */
  z-index: 1;
  /* Positions logo above .main-navigation */
  width: 80px;
  margin: 0 auto;
  background: #ccc;
}


/*------------------------
Main navigation
-------------------------*/

.main-navigation {
  position: relative;
  margin-top: -24px;
  /* Brings nav inline with .site-branding */
  z-index: 0;
  /* Ensures nav is below .site-branding */
}

.main-navigation ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.main-navigation ul li {
  display: inline-block;
}

.left-menu {
  text-align: left;
}

.left-menu li {
  margin-right: 24px;
}

.right-menu {
  text-align: right;
}

.right-menu li {
  margin-left: 24px;
}

.site-header {
  background: pink;
}
<header class="site-header">

  <div class="site-branding">
    <h1 class="site-title"><a href="#" rel="home">Demo</a></h1>
  </div>

  <nav class="main-navigation flex has-2-columns">

    <div class="left-menu col">
      <ul id="left-menu" class="menu">
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
      </ul>
    </div>

    <div class="right-menu col">
      <ul id="right-menu" class="menu">
        <li><a href="#">Contact</a></li>
        <li><a href="#">Store</a></li>
      </ul>
    </div>

  </nav>

</header>

So that is why I say, if you're going to use flex, then use flex! Take advantage of it. Let it do all this work and calculations for you. Additionally, I don't know if you have begun plans for this or not, but this isn't really responsive friendly as it stands now.


TLDR;

Revisiting requirements

My navigation has 4 menu items. I'd like my logo to sit in the middle of these

The way you have set it up, as you can see get's the job done. But they are not apart of the same parent, therefor they can't take advantage of it's inherited properties, and more importantly don't recognize each other as siblings. So I think that's the first thing to address.

Let's assume the following here forward (no margins, no positioning):

/*------------------------
Default grid
-------------------------*/



/*------------------------
Columns
-------------------------*/

.has-2-columns .col {
  flex: none;
}

.has-2-columns .col {
  width: 49%;
}


/*------------------------
Logo
-------------------------*/

.site-title {
  background: #ccc;
}


/*------------------------
Main navigation
-------------------------*/

.main-navigation { background-color: lightgrey;}

.main-navigation ul {
  display: inline-flex;
  list-style: none;
  padding: 0;
  margin: 0;
}

.main-navigation ul li { }

.left-menu {
  text-align: left;
}

.left-menu li {}

.right-menu {
  text-align: right;
}

.right-menu li {}

.site-header {
  display: flex;
  flex-flow: row wrap;
  background-color: pink;
}
<header class="site-header">

  <div class="site-branding">
    <h1 class="site-title"><a href="#" rel="home">Demo</a></h1>
  </div>
  
  <nav class="main-navigation has-2-columns">

    <div class="left-menu col">
      <ul id="left-menu" class="menu">
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
      </ul>
    </div>

    <div class="right-menu col">
      <ul id="right-menu" class="menu">
        <li><a href="#">Contact</a></li>
        <li><a href="#">Store</a></li>
      </ul>
    </div>

  </nav>

</header>

Making them siblings can assistant in limiting any crutches we have on margins and positioning by granting them situational awareness to one another now.

This is also a good time to practice good standards when it comes to classes. Since we stripped all the classes we no longer need, we aren't styling multiple elements anymore, so we can change their selector to an id.

Additionally, let's take advantage of what we learned about direct descendants and apply that now by making the <h1> a direct sibling to both lists as follows:

/*------------------------
    Main navigation
    -------------------------*/

#main-navigation {
  background-color: lightgrey;
}

#main-navigation ul {
  display: inline-flex;
  list-style: none;
  padding: 0;
  margin: 0;
}

#site-header {
  display: flex;
  flex-flow: row wrap;
  background-color: pink;
}
<header id="site-header">

  <nav id="main-navigation">

    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
    </ul>

    <h1><a href="#" rel="home">Demo</a></h1>

    <ul>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Store</a></li>
    </ul>

  </nav>

</header>

Your needs will vary depending on the project, but this particular example we don't have anything else but the navigation so we are going to promote the <nav> to be the flex parent. In doing this we can take advantage of align properties, justify properties and of course the other flex benefits. The 2 key properties are align-items which (on flex-direction: row) it centers the children vertically in our case, and justify-content which you seem to be familiar with. These 2 properties alone handle everything you've used margins for as intended.

#main-navigation {
 display: flex;
 flex-flow: row wrap;
 align-items: center;  /* center the elements (vertically for this axis) in the parent space */
 justify-content: space-between;
}

#main-navigation ul {
  display: inline-flex;
  list-style: none;
  padding: 0;
  margin: 0;
}
#main-navigation li {
  padding: 0 10px;
}



/* irrelevant */
#site-header {
  background-color: pink;
}
<header id="site-header">

  <nav id="main-navigation">

    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
    </ul>

    <h1><a href="#" rel="home">Demo</a></h1>

    <ul>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Store</a></li>
    </ul>

  </nav>

</header>

So that's one way to get your desired outcome on a fundamental level

..... but wait, mobile first right? Naturally, a simple media query can help you adjust things as you wish, that will be arbitrary to your styling needs, but here is a brief example that makes the previous example responsive friendly:

#main-navigation {
 display: flex;
 flex-flow: row wrap;
 align-items: center;  /* center the elements (vertically for this axis) in the parent space */
 justify-content: space-between;
}

#main-navigation ul {
  display: inline-flex;
  list-style: none;
  padding: 0;
  margin: 0;
}
#main-navigation li {
  padding: 0 10px;
}


@media only screen and (max-width: 396px) {
  #main-navigation {
    flex-flow: column nowrap;
  }
  
  #main-navigation h1 {
    order: -1;
  }
}


/* irrelevant */
#site-header {
  background-color: pink;
}
<header id="site-header">

  <nav id="main-navigation">

    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
    </ul>

    <h1><a href="#" rel="home">Demo</a></h1>

    <ul>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Store</a></li>
    </ul>

  </nav>

</header>

Notice how in that example, the <h1> element has an order of -1. Flex assigns '0' to an element as the default value. Therefor -1 gives specificity to those elements without needing to change every single one to [..1,2,3 etc]

And if you REALLY REALLY don't feel well about including it there after all that, we can kind of hack it there:

#main-navigation {
  padding: 10px;
}

#main-navigation ul {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  /* center the elements (vertically for this axis) in the parent space */
  justify-content: space-evenly;
  list-style: none;
  padding: 0;
  margin: 0;
}

#branding {
  font-size: 1.75rem;
}

@media only screen and (max-width: 396px) {
  #main-navigation ul {
    flex-flow: column nowrap;
  }
  #branding {
    order: -1;
  }
}


/* irrelevant */

#site-header {
  background-color: pink;
}
<header id="site-header">

  <nav id="main-navigation">

    <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li id="branding"><a href="#">Demo</a></li>
      <li><a href="#">Contact</a></li>
      <li><a href="#">Store</a></li>
    </ul>

  </nav>

</header>

\$\endgroup\$
  • 2
    \$\begingroup\$ Wow! Thank you so much for taking the time to leave this answer. Excellent response. I'll be taking some time to try each technique this week. Rock on! \$\endgroup\$ – Sam Feb 17 at 18:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.