【问题标题】:Collapsing margin alignment in Firefox在 Firefox 中折叠边距对齐
【发布时间】:2014-01-31 15:18:18
【问题描述】:

TLDR:this codepen 在 Chrome 中运行良好,但在 Firefox 中对齐已关闭。

我正在构建一个jQuery plugin,它会修改文本输入以在左侧为其提供一个下拉按钮。为了获得正确的定位,我添加了一个包装器 div,它与输入的高度相同,因此按钮可以绝对定位在输入的顶部,但仍然具有相同的高度:

#wrapper {
  position: relative;
}
#overlay {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 30px;
}

这在输入具有垂直边距之前工作正常:然后容器增长到包含边距,因此下拉按钮随之增长。我对此的解决方案是边距折叠:我给出了输入 display:block 这意味着容器忽略了它的边距。都很好。

input {
  margin: 20px 0 40px; /* testing */
  display: block;
}

但现在的问题是,默认情况下,输入是内联元素,例如您可能希望在输入旁边有一个提交按钮。所以我用 display:inline-block 将整个东西包裹在一个容器 div 中,这样另一个像按钮这样的内联元素可以愉快地坐在它旁边。

#container {
  display: inline-block;
}

这在 Chrome 中运行良好,但在 Firefox 中当输入有任何垂直边距时会出现奇怪的对齐问题。下面我添加了最终标记。顶部还有一个 codepen 链接。

<div id="container">
  <div id="wrapper">
    <input>
    <div id="overlay"></div>
  </div>
</div>
<button>Submit</button>

编辑:关键是这是一个插件,我正在尝试使用用户现有的标记和 CSS,例如他们有这个标记:

<input><button>Submit</button>

并且他们现有的 CSS 在输入上具有垂直边距,我希望他们能够在输入上初始化我的插件并且它可以正常工作,而无需强迫他们更改其标记/CSS。现在因为插件需要在输入周围添加大量标记(用于覆盖和下拉列表),所以我将它全部包装在一个容器 div 中。这个容器 div 是我们范围的限制(不包括按钮元素,或者他们选择放在输入旁边的任何其他内容)。

【问题讨论】:

    标签: html css


    【解决方案1】:

    要解决此问题,您需要在父级 div#test2 中定义一个 line-height。没有它,different browsers will give it different values。这会导致 Firefox 出现这种奇怪的结果。

    现在,line-height 不是唯一的问题,vertical-align 的基线值也会为 inline 元素生成不同的结果,而不是对于具有与周围 inline 不同高度的 inline-block 元素内容。要解决此问题,请将 #container 元素的值更改为 top(因为这是 inline-block 元素)。

    最终结果将有以下变化(仅粘贴更改的部分):

    #test2 {
        background-color: green;
        line-height:70px;
        #container {
            // replicate the inline nature of the input
            display: inline-block;
            vertical-align:top;
        }
        //the rest of the #test2 nested code
    }
    

    看起来像this

    回复评论

    我制作了一些符合要求的东西。由于您说额外的代码(因此输入周围的 div)是由插件本身制作的,所以我冒昧地对其进行了一些更改以使其正常工作。

    它可以很容易地工作的方式就是根本不使用内联块,而是坚持使用内联元素。这会将样式更改为以下内容:

    #container {
        // replicate the inline nature of the input
        display: inline;
    }
    #wrapper {
        display: inline;
        position: relative;
    }
    input {
        // you'll want to make sure the typed text doesn't appear behind the overlay
        padding-left:35px;
    }
    #overlay {
        position: absolute;
        top: 0px;
        bottom: 0px;
        left: 1px;
        width: 30px;
        background-color: #00C2FF;
    }
    

    注意事项:

    • 我没有费心让覆盖层覆盖输入的整个高度,因为您的插件无论如何都会让它成为一个标志。要使其覆盖整个高度,只需在叠加层上设置负 topbottom 样式,等于输入上计算的 padding-top 和 padding-bottom (resp.)。在这种情况下,您必须将它们更改为 top:-5px;bottom:-5px;。 (您可以通过 jQuery 的$(input).css('padding-top') 获取计算样式)
    • 您实际上也可以从中删除整个#container,因为它现在唯一的样式是display:inline,它实际上并没有给整个东西添加任何东西。
    • 我在您的输入中添加了一个 padding-left,否则您必须在覆盖层后面输入,这很愚蠢。

    【讨论】:

    • 非常酷的解决方案,但我很遗憾地说这是不可能的。我已经更新了这个问题,非常清楚什么可以改变,什么不能改变。
    • @jackocnr 请查看我的更新答案。这是你要找的吗?
    • 哇!如此简单,如此有效!这是迄今为止最好的答案。唯一阻止我授予赏金的是,您必须知道输入上的填充才能定位叠加层,但填充是由用户设置的(以适应他们现有的样式)。我想解决方法是用 jQuery 破解 CSS,但这是我想要避免的。如果没有人提出更好的答案,我会给你赏金。谢谢!
    【解决方案2】:

    插件生成的 HTML 是否需要保持完全相同?我不确定我能否确切地弄清楚为什么第二个示例不起作用,但是您那里似乎有太多 div 元素。你可以让它变得更简单:

    HTML

    <div id="test1">
      <div id="wrapper">
        <input>
        <div id="overlay"></div>
        <button>submit</button>
      </div>
    </div>
    

    SCSS

    input, button {
      border: 1px solid black;
      padding: 5px;
    }
    
    input {
      display: inline-block;
      padding-left: 35px;
    }
    
    #test1 {
      background-color: yellow;
      padding: 20px 0 40px 0;
      #wrapper {
        position: relative;
        #overlay {
          position: absolute;
          top: 1px;
          left: 1px;
          width: 30px;
          background-color: #00C2FF;
        }
      }
    }
    

    Codepen example

    我已经删除了边距,而是在父级上使用了填充,它达到了同样的效果。您还需要在输入字段中添加一些 padding-left,这样输入的文本就不会消失在覆盖层 div 后面。

    编辑:如果您无法更改标记:

    SCSS:

    #test2 {
      background-color: green;
      #container {
        // replicate the inline nature of the input
        display: inline-block;
        padding: 20px 0 40px 0;
      }
      #wrapper {
        // this is just here to be display:block and ignore the margin on the input
        display: block;
        position: relative;
      }
      input {
        // tell parent to ignore margin
        //display: block;
        margin: 0;
      }
      #overlay {
        position: absolute;
        top: 1px;
        bottom: 1px;
        left: 1px;
        width: 30px;
        background-color: #00C2FF;
      }
    }
    

    codepen demo

    input 字段中删除了blockmargin 声明,并将间距移动到#container 元素的填充。

    【讨论】:

    • 如果问题是关于修复保证金问题,删除它就像作弊......但也许你是对的并且不需要保证金,所以这是the XY problem的情况。
    • 感谢您的建议,但重点是我正在尝试使用用户现有的标记和 CSS,例如他们有 并且他们现有的 CSS 在输入上有垂直边距,我希望他们能够初始化我的插件并且它可以正常工作,而无需更改他们的标记/CSS
    • 因此,请过度覆盖您的默认 css 以满足他们的需求。没有人抱怨它 jQuery 和其他插件不能直接使用。解决这个问题可能反过来会导致另一个问题。也就是说,也许您应该编辑您的问题以准确指定可以更改和不能更改的内容。
    • @jackocnr 最后一次尝试,但不确定它是否符合您的要求codepen.io/anon/pen/wJxDl
    • 再次感谢,但恐怕不行。我已经编辑了这个问题,非常清楚什么可以改变,什么不能改变。
    【解决方案3】:

    免责声明”:首先,我并没有找到导致 Firefox 问题的确切原因,但我确实想到了另一种方法。

    这在 Firefox 和 Chrome 中的工作方式只是使用与 #test1 完全相同的 HTML,但最重要的是,还使用 ​​CSS :before 伪元素(而不是使用#container#wrapper)。我使用的代码是:

    #test2 {
        background-color: green;
        position:relative;
        &:before {
            content:"";
            display:block;
            position:absolute;
            left:1px;
            top:1px;
            bottom:1px;
            margin:20px 0 40px 0;
            width:30px;
            background:#00C2FF;
        }
    }
    

    demo

    其工作方式是简单地将:before 叠加层放置在与之前的 div 完全相同的位置。如您所见,我使用了大部分与您相同的样式,但相反,我将它们放在了:before 伪类中。

    【讨论】:

    • 谢谢。一个有趣的方法,但我不只是需要一个彩色方块来覆盖:我肯定需要使用真实的(相当复杂的)标记,我认为这个解决方案不允许这样做?
    • @jackocnr 好吧,如果我不知道您需要什么标记,我不知道。你能把我链接到你想要它做什么的演示吗?然后我可以尝试看看它是否适用于:before。此外,您可以使用:before 伪元素的content 属性来执行a lot more than what I did
    • 问题中有一个指向插件 Github 页面的链接,其中包含有关该插件的更多详细信息,包括演示链接。
    • here 是我最好的尝试。我不确定是否要为其附加事件处理程序,而且它也不是一个真正的可点击区域,因为它是 2 个可点击元素。如果您要添加类似的内容,您可能最好使用my other answer
    【解决方案4】:

    其他答案不知道为什么它在 Firefox 上不起作用。好吧,我认为 Firefox 的行为是正确的,这是 Chrome 的问题。

    简而言之,您希望将输入与按钮对齐。但是输入在包装器内。然后,您可以使用vertical-align 来控制包装器和按钮之间的垂直对齐,但不能控制输入和按钮之间的垂直对齐。

    这里可以看到不同vertical-align的截图:

    the code

    如果您想对齐输入和按钮(图像中的最后一个大小写),您会遇到问题,因为您可以与 vertical-align 一起使用的任何关键字都可以做到这一点。只有在输入的上边距和下边距相等的情况下,vertical-align: middle 才有效。

    但一般来说,您还有另一种解决方案:vertical-align 也接受 &lt;length&gt; 值。

    而且,为了得到完美的对齐,你应该使用公式

    vertical-align: -(input bottom margin)
    

    或者,如果你想在按钮有下边距的情况下对齐它们,那么

    vertical-align: -(input bottom margin) + (button button margin)
    

    上面的代码公式适用于inline-block&lt;div&gt;,但不适用于&lt;buttons&gt;

    公式必须固定为

    vertical-align: -(input bottom margin) -(input offsetHeight)/2 + 6
    

    在你的例子中

    • (输入底边距)= 40px
    • (输入偏移高度)= 31px

    那么,你需要

    vertical-align: -(input bottom margin) -(input offsetHeight)/2 + 6
    

    Demo

    【讨论】:

    • “其他答案不知道为什么它在 Firefox 上不起作用” - 不正确,请参阅我的第二个答案。
    • 感谢您的启发性回答,但不幸的是,边距是用户设置的未知变量。很抱歉,如果不清楚 - 我已经编辑了问题以澄清这一点。
    • @jackocnr 是的,但是如果它是一个 jQuery 插件,您可以使用 JS 检测边距并根据它设置 vertical-align
    • @Oriol 您的 Demo 链接在 Chrome 中看起来一点也不好看。
    【解决方案5】:

    我可以通过以下方式实现它。Codepen 你必须知道应用于输入的 css 并将其应用于按钮

      button{
       position:absolute;
       margin-left:5px;
      }
      input, button {
       display: inline-block;
       margin: 20px 0 40px 0;
      }
    

    【讨论】:

      【解决方案6】:

      请在下面的代码中更新。

      input, button {
          border: 1px solid #000000;
          margin: 20px 0 40px;
          padding: 5px;
          vertical-align: top;
      }
      

      希望它会起作用

      http://codepen.io/anon/pen/Isycu

      【讨论】:

      • 否 - 阅读问题 - 按钮不在插件的控制范围内。
      猜你喜欢
      • 2012-01-04
      • 2019-08-16
      • 2010-09-11
      • 2011-02-09
      • 2017-07-09
      • 1970-01-01
      • 2017-07-27
      • 1970-01-01
      • 2012-07-28
      相关资源
      最近更新 更多