7

I'm working on a menu bar that's been designed with a logo/badge in the center of it. This works fine in the current situation (desktop with a few items) but if the screen is scaled or the amount of menu options increases, the logo gets put behind the menu buttons.

My current way of making it more robust is (quite literally) sidestepping the problem by scaling the logo/badge and moving it out and above of the menu bar.

But ideally I'd keep it in the 'middle' of the menu bar, between the menu options. Anyone got an idea on how to do this? Preferably using just CSS.

enter image description here

To clarify: I want the star centered to the menubar on larger screens, and bumped over to be in the middle of the remaining space on smaller screens. So just using flexbox isn't a (complete) solution. With fixed content I could use a breakpoint, but with content subject to change, the required breakpoint is impossible to predict.

enter image description here

PixelSnader
  • 552
  • 1
  • 4
  • 9
  • For your “ideal solution” on smaller screens you should use flexbox ... but that won’t solve the issue of getting it “centered” on larger screens, because there you do not want to center it in regard to the remaining space, but the overall navigation width. – CBroe Sep 01 '17 at 09:51
  • @CBroe True, and it seems I should clarify this because the current 3 answers all give the same unwanted endresult. – PixelSnader Sep 01 '17 at 11:09
  • 1
    I don’t think you will find a pure CSS solution, not with an unknown amount of menu items and dynamic widths. If all your buttons had the same fixed width, you might be able to adapt what’s been dubbed [“quantity queries”](https://alistapart.com/article/quantity-queries-for-css) to figure out where to switch between the two ways of displaying this for different combinations of number of menu items and screen widths. Getting it centered over the whole menu width could then easily be done by absolutely positioning the logo. – CBroe Sep 01 '17 at 11:14
  • @Cbroe That just blew my mind a little bit. I'm not sure if I can apply those queries to this project/element, but they seem very useful. – PixelSnader Sep 01 '17 at 11:39
  • 1
    Well a simpler alternative to such rather complex queries could be that the system that outputs your menu simply counts the items, and puts that information f.e. into a data attribute or as an additional class on the parent element, so that you can apply different styles based on that. Maybe you don’t need a single class for every possible number of items, but classes indicating simply whether the menu has more or less than X items will do already ... – CBroe Sep 01 '17 at 12:33

1 Answers1

1

Your ideal solution (or at least something very close) is possible with a flex layout. The idea is to maintain equal widths for the left and right part as long as there is enough space. This can be done by setting the flex-basis of both left and right part to a value larger than their content's size - then it won't be affected by the contents, and everything will be symmetrical.

In this demo, you can hover the body for a transition to a smaller width. The black line shows the exact center of the body.

.header {
  display: flex;
}

.start,
.end {
  /* this value should be larger than the minimum width on a "large" screen
     if it is, the content width will not determine the actual width, so start
     and end part will be of the same size -> the middle is centered
     using 50% - 50px here so we're neither growing nor shrinking if there is
     enough space (50px is half the middle width)
   */
  flex: calc(50% - 50px) 1;
}

.middle {
  /* this flex-basis is kind of the targeted width of the middle part within
     the star will be centered. Giving the middle a larger flex-basis than its
     contents prevents the contents from touching the left part even there is
     still ample space to the right
     Once the middle "bumped" to start/end, the middle will shrink, but it will
     still remain a space toward start/end as long as possible
   */
  flex: 100px 1;
}


.middle {
  text-align: center;
}

.end {
  text-align: end;
}

.start,
.middle,
.end {
  /* wraping would reduce the minimum width, don't want that */
  white-space: nowrap;
}


/* ---
 * these rules here are just for the demo, not for the layout
 * ---
 */

.start,
.middle,
.end,
{
  /* increase legibility without affecting horizontal layout */
  padding: 10px 0;
}

.center-line {
  width: 50%;
  border-right: 2px solid black;
  /* center on the border */
  margin-left: -1px;
  height: 30px;
}

html,
body {
  padding: 0;
  margin: 0;
}

.page {
  padding: 10px;
}

.middle {
  background: rgba(0, 0, 0, 0.1);
}

/* transition on hover */

.page {
  transition: width 1s ease-in-out;
  width: 500px;
  background: rgba(0, 0, 0, 0.1);
}

:hover .page {
  width: 250px;
}
<div class="page">
  <div class="header">
    <div class="start">Button Button Button</div>
    <div class="middle">*</div>
    <div class="end">Button</div>
  </div>
  <div class="center-line"></div>
</div>

Here is a variation where the width of the middle is not known. The only problem with it is that it will overflow the flex container if the whole thing does not fit. If you tell the middle that it can shrink (e.g. min-width: 0; overflow: hidden;), it will shrink as soon as the start/end parts shrink, and as soon as that contents will be clipped.

.header {
  display: flex;
  column-gap: 20px;
}

.start,
.end {
  /* this is no longer exact - */
  flex: 30%;
}

.middle {
  /* this flex-basis is kind of the targeted width of the middle part within
     the star will be centered. Giving the middle a larger flex-basis than its
     contents prevents the contents from touching the left part even there is
     still ample space to the right
     Once the middle "bumped" to start/end, the middle will shrink, but it will
     still remain a space toward start/end as long as possible
   */
  flex: 1;
}


.middle {
  text-align: center;
}

.end {
  text-align: end;
}

.start,
.middle,
.end {
  /* wraping would reduce the minimum width, don't want that */
  white-space: nowrap;
}


/* ---
 * these rules here are just for the demo, not for the layout
 * ---
 */

.start,
.middle,
.end,
{
  /* increase legibility without affecting horizontal layout */
  padding: 10px 0;
}

.center-line {
  width: 50%;
  border-right: 2px solid black;
  /* center on the border */
  margin-left: -1px;
  height: 30px;
}

html,
body {
  padding: 0;
  margin: 0;
}

.page {
  padding: 10px;
}

.middle {
  background: rgba(0, 0, 0, 0.1);
}

/* transition on hover */

.page {
  transition: width 2s linear;
  width: 700px;
  background: rgba(0, 0, 0, 0.1);
}

:hover .page {
  width: 300px;
}
<div class="page">
  <div class="header">
    <div class="start">Button Button Button</div>
    <div class="middle">This is the page title</div>
    <div class="end">Button</div>
  </div>
  <div class="center-line"></div>
</div>
Yogu
  • 9,165
  • 5
  • 37
  • 58