Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Element with CSS display: none; breaking layout - causing misalignment

I have a basic menu, made from a horizontally aligned list (<li>), each containing an icon image and some text:

Menu bar

One of the <li> contains an extra image with display: none; so that the icon can be toggled (from a green to a red pepper, in this example. The problem is that it doesn't align correctly on some browsers, as shown in the above image. My understanding was that in contrast to visibilty: hidden;, an element with display: none; should not affect the position of any other element and should render as if it's not there?

The browsers where it doesn't render correctly are Google Chrome and Safari - but only on MacOS(!?) and IE7 (I know, I know...) on Windows. Every other browser / OS combination I've tested works fine.

Here's the HTML:

<ul class="menu">
    <li><img alt="Green Pepper" src="/green.png">li</li>
    <li><img alt="Green Pepper" src="/green.png">li</li>
    <li><img alt="Green Pepper" src="/green.png">li</li>
    <li id="change">
        <img alt="Red Pepper" src="/red.png" style="display: none;">
        <img alt="Green Pepper" src="/green.png"> 
        li
    </li>
    <li><img alt="Green Pepper" src="/green.png">li</li>
</ul>

Here's the CSS:

.menu li {
    cursor: default;
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 10pt;
    list-style-type: none; 
    position: relative; 
    text-align:center; 
    margin: 0 0 0 -25px; 
    padding: 8px 0 0 0;
    width: 144px;
    height: 35px;
    display: inline-block;
    background-image: url(../bct-white.png);
    background-repeat: no-repeat;
    color: #0091c1;
}

And for the icon images:

.menu img {
    display: inline;
    vertical-align: -25%;
    padding-right: 6px;
}

I've also had to include a browser hack for IE7 because it doesn't recognise inline-block, coming from a separate stylesheet based on a conditional import (<!--[if lte IE 7]>):

.menu li {
    zoom: 1;
    display: inline;
}

Although, obviously that style isn't loaded on Chrome and Safari regardless of OS, so can't be causing my issue on Macs.

I know the quickest solution would be to refactor the HTML and the JavaScript manipulation of the show / hide of the icons, but I'd really like to know what causes this issue and how to resolve it.


Update

I've tracked the cause down. Basically, the element style of display: none; on the <img> element overrides the inline from the .menu img rule. Removing that, then toggling between block and inline allows you to reproduce the issue. This is obviously a browser bug, and while the element is not displayed being an in-line or block element should have no effect on the layout.


jsFiddles

Issue with Chrome and Safari on Macs only

Issue with extra CSS for IE7 only

Note! For me, the Fiddle page didn't load properly using IE7, but the direct link for the result iFrame is http://fiddle.jshell.net/z4dU7/3/show/

Bounty update!!!

I've posted one fix below, but it actually introduces the same layout problem in IE9! Please feel free to evolve or improve on my answer - or come to the table with something completely different! :)

like image 281
Michael Avatar asked Jul 11 '13 10:07

Michael


2 Answers

Scrap Approach and Use Background Images

http://jsfiddle.net/P5CKC/2/

<ul class="menu">
    <li><span>Li</span></li>
    <li><span>Li</span></li>
    <li><span>Li</span></li>
    <li class="change"><span>Li</span></li>
    <li><span>Li</span></li>
</ul>

CSS

ul.menu {
    overlflow: hidden;
}
ul.menu li {
    float: left;
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 10pt;
    text-align:center; 
    margin: 0 0 0 -25px; 
    width: 152px;
    line-height: 35px;
    height: 35px;
    background: url(../bct-white.png) no-repeat;
    color: #0091c1;
}
ul.menu li span {
    background: url(/green.png) no-repeat 5px 6px;
    display: block;
}
ul.menu li.change span {
    background-image: url(/red.png);
}

CSS2.0 and browser compatibility

The code application I have provided is Css2.0 and should easily work in IE7 and above.

  1. Removed img tags and implemmented aesthetics (images) as backgrounds
  2. Extra span had to be added because CSS2 allows only 1 background image per element
  3. Li tag holds the arrow background; span tag holds the pepper background
  4. Updated id="change" to class="change". UNLESS you are 100% certain that you will only have one #change element, use a class. This is purely styling and it prevents you from having two menu lists on the same page.
  5. Tweaked your CSS styling a bit as follows:

Removed top padding and increased the height. So your li elements are the same height BUT then added line-height: 35px -> this is the best way to vertically center text. Utlizing top padding works but it is prone to poor browser inconsistency.

Change li elements to floats. Floated elements are the most IE7 friendly method! Even IE6 will not bug out but I don't have that old version to test your webpage in. FYI - ul.menu has to have overflow: hidden to clear the floats.

position: relative; 
cursor: default;

Unless you changed the defaults, you can keep these two properties out. cursor should be default. Position: relative is unnecessary - you aren't using absolute positioning or anything that warrants its need. Now, you can keep these in your declaration. I just like code to be as "slim" as possible.

final words:

Take a look at my CSS. Notice how I used ul.menu in all my declaration. You may want to get in the habit of doign the same; this provides the developer some insight on what the HTML looks like and more importantly - your css will not get overrided if you decide to add <div class=menu> later on. Specfically .menu img would apply to any image tag within the menu div.

Okay - that's it. Let me know if there are any clarfications.

FYI - seeing as this question has a bounty, if you provide me with the background images I can polish my code to suit your needs 100% - perhaps upload them in an edit of your answer.

like image 151
ProfileTwist Avatar answered Oct 30 '22 08:10

ProfileTwist


There is whitespace between your elements. None of your other list items have that whitespace. Try removing all whitespace between those elements and see if that fixes your problem.

If it does, it just means that your HTML is parsing the content of your <li> as having a line break - which would be why you are seeing an issue. To solve this, wrap the text in your <li> with a <span>. When your browser parses HTML it will automatically trim whitespace between HTML tags and automatically fix the issue (without losing your formatting)

like image 41
Matthew R. Avatar answered Oct 30 '22 07:10

Matthew R.