带有 CSS 显示的元素:无;破坏布局 - 导致错位

Posted

技术标签:

【中文标题】带有 CSS 显示的元素:无;破坏布局 - 导致错位【英文标题】:Element with CSS display: none; breaking layout - causing misalignment 【发布时间】:2013-07-09 13:52:06 【问题描述】:

我有一个基本菜单,由水平对齐的列表 (<li>) 组成,每个列表都包含一个图标图像和一些文本:

其中一个<li> 包含一个带有display: none; 的额外图像,以便可以切换图标(在本例中从绿色变为红色辣椒。 问题是它在某些浏览器上无法正确对齐,如上图所示。我的理解是,与visibilty: hidden; 相比,带有display: none; 的元素不应该影响任何其他元素的位置,并且应该像不存在一样呈现?

无法正确呈现的浏览器是 Google ChromeSafari - 但仅限于 MacOS(!?) 和 IE7(我知道,我知道...)在 Windows 上。我测试过的所有其他浏览器/操作系统组合都可以正常工作。

这是 html

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

这是 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;

对于图标图像:

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

我还必须包含针对 IE7 的浏览器 hack,因为它无法识别来自基于条件导入 (&lt;!--[if lte IE 7]&gt;) 的单独样式表的内联块:

.menu li 
    zoom: 1;
    display: inline;

虽然,很明显,无论操作系统如何,Chrome 和 Safari 都不会加载该样式,因此不会在 Mac 上引起我的问​​题。

我知道最快的解决方案是重构 HTML 和 javascript 对图标的显示/隐藏的操作,但我真的很想知道是什么导致了这个问题以及如何解决它。


更新

我已经找到原因了。基本上,&lt;img&gt; 元素上的display: none; 元素样式会覆盖.menu img 规则中的inline。删除它,然后在blockinline 之间切换可以让您重现该问题。这显然是一个浏览器错误,虽然元素没有显示为内联或块元素,但对布局没有影响。


jsFiddles

Issue with Chrome and Safari on Macs only

Issue with extra CSS for IE7 only

注意!对我来说,使用 IE7 无法正确加载 Fiddle 页面,但结果 iFrame 的直接链接是 http://fiddle.jshell.net/z4dU7/3/show/

赏金更新!!!

我在下面发布了一个修复程序,但它实际上在 IE9 中引入了相同的布局问题!请随时改进或改进我的答案 - 或以完全不同的方式来到桌面! :)

【问题讨论】:

我认为我们需要看到这一点才能为您提供帮助。我做了一个快速的小提琴,无法重现这种行为 - display:none 从布局中删除了图像(应该如此)。也许#change 应用了其他样式? 这个小提琴演示在 IE7 中:jsfiddle.net/z4dU7/3 要在 Mac 上查看问题,只需删除最后一个样式规则(从我系统上的 IE 特定样式表中提取)。跨度> @David 我已经用两个场景的链接更新了我的问题。 你可能还是要考虑使用背景图片,这样它们就不会影响视觉流动。 对不起,它可能已经被建议了,但我很懒,我不想阅读所有的答案。如果你的意思是切换图像,我假设有某种用户触发它的动作。一旦使用一些 javascript 执行此操作,为什么不直接更改图像的 src 属性?由于不会有更多隐藏图像,所以问题应该消失了对吗? 【参考方案1】:

要解决(外观)问题,请更改菜单中包含的图标图像的垂直对齐方式:

.menu img 
    display: inline;
    vertical-align: top;
    margin-top: 2px;
    padding-right: 6px;

在受影响的浏览器上,附加图像(带有display: none;)正在改变包含元素的高度。将&lt;img&gt; 设置为display: none; 意味着display: inline; 设置不再应用并且位于第一个图像下方。

仅仅通过内联显示额外的&lt;img&gt; 可以解决垂直对齐问题,但显然不能解决问题,因为需要在不改变文本位置的情况下隐藏图像。

此修复将垂直对齐方式从百分比 (-25%) 更改为固定位置,从而避免包含元素高度的任何(虚假)差异。然后,我设置了图像的上边距,以从元素的上边缘获得所需的间距。

更新

此修复会破坏 IE9 中的显示 - 外观与没有此修复的 IE7 相同。

【讨论】:

您可以尝试将隐藏图像的宽度和高度设置为 1 或 0。这样即使它们以某种方式影响布局,它也不可见。【参考方案2】:

这是一个奇怪的问题,但我可以在 Firefox v22 中重现该问题。真正奇怪的是,在jsFiddle 中,如果我只是点击“整理”然后点击“运行”,问题就解决了。正如Matthew R mentioned,这可能是由于额外的空白被删除了。

破碎:

整理、运行和修复

这是使用背景图像的另一种方法:

Working Example

.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 10px;
  width: 118px;
  height: 20px;
  display: inline-block;
  background-image: url(http://modmyi.com/attachments/forums/iphone-4-4s-new-skins-themes-launches/465481d1282224308-classified-hd-cydia-released-goldborder.png), url(http://i.stack.imgur.com/dmHl0.png);
  background-position: 0% 0%, 44% 75%;
  background-size: 128px, 18px;
  background-repeat: no-repeat;
  color: #0091c1;


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


#change:hover 
  background-image: url(http://modmyi.com/attachments/forums/iphone-4-4s-new-skins-themes-launches/465481d1282224308-classified-hd-cydia-released-goldborder.png), url(http://www.chiletownhotsauce.com/images/stories/Red%20bell%20pepper.jpg);
  background-repeat: no-repeat;
  background-position: 0% 0%, 44% 75%;
  background-size: 128px, 18px;

<ul class="menu">
  <li>li</li>
  <li>li</li>
  <li>li</li>
  <li id="change">li</li>
  <li>li</li>
</ul>

【讨论】:

【参考方案3】:

元素之间有空格。您的其他列表项都没有那个空格。尝试删除这些元素之间的所有空格,看看是否能解决您的问题。

如果是这样,则仅表示您的 HTML 将 &lt;li&gt; 的内容解析为有换行符 - 这就是您看到问题的原因。要解决此问题,请使用 &lt;span&gt;&lt;li&gt; 中的文本包装起来。当您的浏览器解析 HTML 时,它会自动修剪 HTML 标记之间的空白并自动修复问题(不会丢失您的格式)

【讨论】:

【参考方案4】:

报废方法和使用背景图片

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 和浏览器兼容性

我提供的代码应用是Css2.0,应该很容易在IE7及以上运行。

    删除了img 标记,并将美学(图像)作为背景实现 必须添加额外的 span,因为 CSS2 只允许每个元素 1 个背景图片 李标签持有箭头背景; span 标签保存辣椒背景 将id="change" 更新为class="change"。除非您 100% 确定您将只有一个 #change 元素,否则请使用类。这纯粹是样式设置,它可以防止您在同一页面上拥有两个菜单列表。 对 CSS 样式进行了如下微调:

移除顶部填充并增加高度。因此,您的 li 元素的高度相同,但随后添加了 line-height: 35px -> 这是垂直居中文本的最佳方式。使用顶部填充可以工作,但容易导致浏览器不一致。

li 元素更改为浮点数。浮动元素是最适合 IE7 的方法!即使 IE6 也不会出错,但我没有那个旧版本来测试你的网页。仅供参考 - ul.menu 必须有 overflow: hidden 才能清除浮动。

position: relative; 
cursor: default;

除非您更改了默认值,否则您可以保留这两个属性。光标应该是默认的。 Position: relative 是不必要的——你没有使用绝对定位或任何需要它的东西。现在,您可以将这些保留在您的声明中。我只是希望代码尽可能“苗条”。

最后的话:

看看我的 CSS。请注意我在所有声明中如何使用ul.menu。您可能希望养成这样做的习惯;这为开发人员提供了一些关于 HTML 外观的见解,更重要的是 - 如果您决定稍后添加 &lt;div class=menu&gt;,您的 css 将不会被覆盖。具体而言,.menu img 将应用于菜单 div 中的任何图像标签。

好的 - 就是这样。如果有任何澄清,请告诉我。

仅供参考 - 鉴于这个问题很有价值,如果你向我提供背景图片,我可以完善我的代码以 100% 满足你的需求 - 或许可以在编辑你的答案时上传它们。

【讨论】:

+1 我喜欢这个解决方案,并且已经得到了很好的解释。使用内部跨度很好地避免了需要多个背景图像的问题,并且对 HTML 没有太大的修改。 +1。 The right approach。对我来说,使用&lt;img&gt;s 进行布局就像使用&lt;table&gt;s 进行布局一样。【参考方案5】:

我认为您的问题在于box modeldisplay:inline-block。当我在水平菜单中使用 display:inline-block 时,我也会对父级使用明确的修复,对子级使用 float:left;。 在这个 css 示例中,我在 .menu 中放置了一些可以继承的值,我使用 overflow:hidden; 来解决明确的问题。然后我在li 中使用float:left; 来强制它们收紧并避免浏览器默认设置导致的任何奇怪间距。然后我将图像的vertical-align 值更改为middle。当将display:none;inline 切换时,对我来说一切都是正确的。我没有在列出的所有浏览器中进行测试。我还为css reset 使用了那里的第一段 CSS,这可能是多余的,但我总是发现它在 JSFiddle 上很有用。

* 
    margin:0;
    padding:0;

.menu 
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 10pt;
    list-style-type: none;
    color: #0091c1;
    overflow:hidden;

.menu li 
    cursor: default; 
    position: relative; 
    text-align:center; 
    /* margin: 0 0 0 -25px; */
    padding: 8px 0 0 0;
    width: 118px;
    height: 20px;
    display: inline-block;
    float:left;
    background-image: url(http://modmyi.com/attachments/forums/iphone-4-4s-new-skins-themes-launches/465481d1282224308-classified-hd-cydia-released-goldborder.png);
    background-repeat: no-repeat;


.menu img 
    display: inline;
    /* vertical-align: -25%; */
    padding-right: 6px;
    vertical-align:middle;

【讨论】:

【参考方案6】:

你弄错了行高 而不是 35px 给 23px

<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>
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: 23px;
  list-style: none;
  height: 35px;
  background: #ccc;
  color: #0091c1;

ul.menu li span 
  background: url(http://i.stack.imgur.com/dmHl0.png) no-repeat 5px 6px;
  display: block;

ul.menu li.change span 
  background-image: url(/red.png);

检查输出

jsfiddle-link

【讨论】:

以上是关于带有 CSS 显示的元素:无;破坏布局 - 导致错位的主要内容,如果未能解决你的问题,请参考以下文章

如何在不破坏布局“流程”的情况下使用 css 旋转元素?

带有水平滚动条的 pre/code 元素破坏了 Firefox 上的 flex 布局

iOS:多行 uilabel 仅显示带有自动布局的一行

带有伪元素的 CSS 波纹效果导致回流

CSS应用的小问题总结

css zoom缩放带有背景图片的元素的时候发现会吃掉1px或2px导致背景图片显示不全,请问怎么解决