【问题标题】:Sub-Pixels calculated and rendered differently among browsers不同浏览器计算和渲染的子像素不同
【发布时间】:2016-04-13 02:09:09
【问题描述】:

目的:

我正在编写与此类似的代码来创建 其中输入字段具有嵌入式按钮的组件

http://codepen.io/anon/pen/pgwbWG?editors=110

如您所见,按钮绝对定位,topbottom 设置为 0,以实现 100% 高度元素。

还要注意的是,text-input 的边框必须保持可见,并且还必须包裹 button。 为了实现这一点,我在 button 中添加了一个margin: 1px,以便(应该)有空间来显示周围的 text-input 红色边框(通常在输入字段时内容无效)。

问题:

是在 Firefox 上它(大部分)正确呈现,而在 Chrome 上(显然在最新的 Safari 上)它会在 按钮的底部有一个 1px 的间隙强>。

CSS 看起来不错,但它似乎是渲染中的计算/舍入问题,按钮的底部或顶部边距并不是真正的 1px(可以看到它检查元素)。 而且输入的填充似乎也有影响。

在不同的缩放率下,它会在按钮的顶部或底部添加或删除 1px 的边距,从而产生 1px 的间隙或覆盖的边框强>。

当我将 button 边距设置为 0px 时,底部边距是固定的,但我在顶部松开了 1px 边距,最终覆盖了 text-input 的红色边框.

例子:

可能我解释不清楚或过于冗长,所以这里是一些错误的截图,来自 Chrome 上的不同缩放(注意 CSS 总是相同的):

解决办法:

我找不到跨浏览器解决方案。 如何处理它并获得一致的组件? (请不要使用 Javascript)

【问题讨论】:

  • 在包装上设置边框可以吗?
  • 实际上不是,因为样式(边框和其他规则)取决于来自浏览器验证 API 并在包含的 input 上执行的 :valid 状态。只要没有 CSS4 父选择器 (>),我就无法设置包装器的样式。我也有兴趣了解如何在其他情况下处理子像素。
  • 防止子像素渲染问题的一种方法是确保所有与大小、边距和填充相关的 css 属性都是可被 2 整除的固定像素数量。这并不适用于所有场景,但当它适用时,它会有所帮助。
  • 是的,但是固定数量的像素然后我们可以完全丢弃响应能力。缩放页面可能会破坏这些计算。

标签: css cross-browser rendering subpixel


【解决方案1】:

如您所知,问题源于浏览器之间亚像素计算的不同方法

例如,在 Chrome 中,边框可以具有小数大小,但边距的处理方式不同(作为整数)。

我没有来自 Chrome 团队的文档,但可以在开发工具中看到:

AFAIK,没有办法改变它。

相反,您可以将按钮中边距的使用转移到边框。

由于您需要为输入的 1px 边框获取空间,因此在按钮中执行相同操作,设置 1px 边框(而不是边距),并将其设置为透明。

剩下的窍门就是把 background-clip 属性设置为 padding box,这样这个透明度就不受背景的影响了

Chrome 中还有一个 bug,当浏览器缩放时,以 em 表示的填充在这种精度级别上并不可靠。我在sn-p中改变了这个。

由于我们使用边框按钮来确定尺寸,我们可以使用嵌入阴影来设置边框样式。

* {
  margin: 0; padding: 0; box-sizing: border-box;
}
button, input, wrapper {
  display: inline-block; border-radius: 3px;
}

.wrapper {
  position: relative;
  
  width: 60%;
  margin: 1em;
  background-color: #ccc;
}

input {
  border: 1px solid red;
  width: 100%;
  
  background-color: limegreen;
  line-height: 3em;
/*  padding: 0.75em; */
  padding: 10px;
}

button {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  border: 1px solid transparent;
  width: 7em;
  margin: 0px;
  background-clip: padding-box;
  box-shadow:  inset 0px 0px 0px 2px  black;
}
<div class="wrapper">
  <input type="text">
  <button>Test</button>
</div>

另一个例子,按钮边框。但是我们需要一个包装器来确定尺寸。

* {
  margin: 0; padding: 0; box-sizing: border-box;
}
button, input, wrapper {
  display: inline-block; border-radius: 3px;
}

.wrapper {
  position: relative;
  
  width: 60%;
  margin: 1em;
  background-color: #ccc;
}

input {
  border: 1px solid red;
  width: 100%;
  
  background-color: limegreen;
  line-height: 3em;
/*  padding: 0.75em; */
  padding: 10px;
}

.buttonwrap {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  border: 1px solid transparent;
  width: 7em;
  margin: 0px;
  background-clip: padding-box;
}
button {
  position: absolute;
  right: 0px;
  top: 0;
  bottom: 0;
  width: 100%;
  border: 2px solid blue;
  margin: 0px;
}
<div class="wrapper">
  <input type="text">
  <div class="buttonwrap">
      <button>Test</button>
  </div>
</div>

【讨论】:

  • 感谢您的建议!我正在考虑使用 border 属性,但不幸的是,它已经用于样式设置(抱歉没有让问题变得明显)。无论如何,有趣的是知道小数和整数的计算对于 bordermargin 的处理方式不同(你有一些关于它的链接吗?)。此外,不幸的是,在 Chrome 47 上运行你的 sn-p 它仍然有底部不需要的像素间距。
  • 天哪!还有另一个错误。我已经修改了 sn-ps 来解决这个问题(填充相关)。我添加了 2 种方法来设置按钮边框样式。
  • 是的,我还发现填充造成了一半的问题;将其更改为 px 有很大帮助。使用box-shadowas 边框的好方法(即使我从 SASS mixin 继承按钮的边框样式并且我试图不必指定它;但我想这种情况必须是一个例外)。顺便说一句,如果您可以参考一篇文章/链接/参考并解释 bordermargin 计算中的差异(我找不到),那就太好了;主要是为了将来和社区参考。但是感谢您的解决方案,并享受您的赏金:)
  • 谢谢!我已经添加了一些解释......我没有更多的:-)
  • 这很公平。我只是想让尽可能多的细节以供将来参考(对这个问题的看法正在迅速提高!)。谢谢; +50 给你! ;)
【解决方案2】:

使用http://autoprefixer.github.io/ 获得显示所需的跨浏览器支持:flex;

button, input, wrapper {
  display: inline-block; <----- Remove "display: inline-block;"
  border-radius: 3px;
}

.wrapper {
  position: relative;
  display: -webkit-box;<----- Add "display: flex;"
  display: -webkit-flex;<----- Add "display: flex;"
  display: -ms-flexbox;<----- Add "display: flex;"
  display: flex;<----- Add "display: flex;"
  width: 60%;
  margin: 1em;
  background-color: #ccc;
}

额外的阅读和学习材料:

https://css-tricks.com/snippets/css/a-guide-to-flexbox/

http://flexbox.io/#/

https://philipwalton.github.io/solved-by-flexbox/demos/holy-grail/

http://www.sketchingwithcss.com/samplechapter/cheatsheet.html

注意:要覆盖 flex 规则,您需要使用 flex 简写而不是特定的覆盖,因为当前浏览器存在缺陷,例如。

.item {
  flex: 0 0 300px;
}

/* overide for some reason */

.item {
  flex: 1 0 300px;
}

/* NOT */

.item {
  flex-grow: 1;
}

您可能需要对 ie11 进行覆盖:

.ie11std .wrapper {
  display:table;
}

.ie11std .item {
  display:table-cell;
}

虽然这不会响应。

【讨论】:

  • 感谢您提供的所有 Flexbox 提示!但答案并不明确;您能否提供更多关于为什么这会解决我的渲染问题的见解?
  • 另外,不幸的是,在我的 sn-p 上尝试您的更改似乎并没有使子像素渲染更好。您是否有修复不需要的间距的工作示例?
猜你喜欢
  • 2014-09-22
  • 2021-07-06
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 2011-10-06
  • 1970-01-01
  • 2013-01-11
  • 2013-08-18
相关资源
最近更新 更多