在高 DPI 显示器上 div 背景和边框之间有 0-1 像素的变化
Varying 0-1px gap between div background and border on High-DPI displays
这是我在 CSS 中创建的按钮的独立示例。它具有带渐变的 1px 边框和背景渐变。背景渐变作为伪元素实现,以允许其不透明度在悬停时淡化。
https://codepen.io/anon/pen/wbYoeo?editors=1100
.Button
{
width: 200px;
height: 30px;
cursor: pointer;
padding: 0.8rem;
border-style: solid;
border-image: linear-gradient(
to right,
green 0%,
blue 100%);
border-image-slice: 1;
border-width: 1px;
position: relative;
margin-top: 10px;
transition: color 0.2s;
}
.Button::before
{
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient(
to right,
green 0%,
blue 100%);
opacity: 0.5;
transition: opacity 0.2s;
}
按钮在不同 DPI 的显示器之间呈现不同。 Chrome 在 Windows 中以不同 DPI 比例呈现的按钮屏幕截图:
100% DPI-scaled monitor, rendering correctly with no gap.
150% DPI-scaled monitor, showing a gap between the background and border.
175% DPI-scaled monitor, showing a gap between the background and border.
200% DPI-scaled monitor, rendering correctly with no gap.
我尝试了几种渲染按钮的策略,但它们都导致了间隙:
- 尝试在
border-image
和 background-image
上使用带渐变的 image 而不是 linear-gradient
。
- 尝试对背景渐变使用显式 div 而不是伪元素。
- 尝试对背景渐变使用显式 div 而不是伪元素,并且还使用了实心左右边框以及具有线性渐变背景的 ::before 和 ::after 伪元素用于顶部和底部边框。
原因?
我会(毫无根据地)猜测这是缩放时 sub-pixels 引起的。它不能是一个像素的零头,所以它选择了一个完整的像素值;在某些比例下,parent 的计算值比 children 的计算值大 1px。
解决方法
去掉按钮 div 本身的边框,然后将其放在 ::after
pseudo-element 上,这样边框和背景都是 children。边框现在似乎与背景渐变一致。
例子
.Button {
width: 200px;
height: 30px;
cursor: pointer;
padding: 0.8rem;
position: relative;
margin-top: 10px;
transition: color 0.2s;
}
.Button::before {
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient( to right, green 0%, blue 100%);
opacity: 0.2;
transition: opacity 0.2s;
}
.Button:hover::before {
opacity: 0.5;
}
.Button:active::before {
opacity: 1;
}
.Button::after {
content: '';
border-style: solid;
border-image: linear-gradient( to right, green 0%, blue 100%);
border-image-slice: 1;
border-width: 1px;
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
}
html {
height: 100%;
display: table;
margin: auto;
}
body {
background: black;
display: table-cell;
vertical-align: middle;
color: white;
font-family: sans-serif;
}
Click it:
<div class="Button"></div>
这是我在 CSS 中创建的按钮的独立示例。它具有带渐变的 1px 边框和背景渐变。背景渐变作为伪元素实现,以允许其不透明度在悬停时淡化。
https://codepen.io/anon/pen/wbYoeo?editors=1100
.Button
{
width: 200px;
height: 30px;
cursor: pointer;
padding: 0.8rem;
border-style: solid;
border-image: linear-gradient(
to right,
green 0%,
blue 100%);
border-image-slice: 1;
border-width: 1px;
position: relative;
margin-top: 10px;
transition: color 0.2s;
}
.Button::before
{
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient(
to right,
green 0%,
blue 100%);
opacity: 0.5;
transition: opacity 0.2s;
}
按钮在不同 DPI 的显示器之间呈现不同。 Chrome 在 Windows 中以不同 DPI 比例呈现的按钮屏幕截图:
100% DPI-scaled monitor, rendering correctly with no gap.
150% DPI-scaled monitor, showing a gap between the background and border.
175% DPI-scaled monitor, showing a gap between the background and border.
200% DPI-scaled monitor, rendering correctly with no gap.
我尝试了几种渲染按钮的策略,但它们都导致了间隙:
- 尝试在
border-image
和background-image
上使用带渐变的 image 而不是linear-gradient
。 - 尝试对背景渐变使用显式 div 而不是伪元素。
- 尝试对背景渐变使用显式 div 而不是伪元素,并且还使用了实心左右边框以及具有线性渐变背景的 ::before 和 ::after 伪元素用于顶部和底部边框。
原因?
我会(毫无根据地)猜测这是缩放时 sub-pixels 引起的。它不能是一个像素的零头,所以它选择了一个完整的像素值;在某些比例下,parent 的计算值比 children 的计算值大 1px。
解决方法
去掉按钮 div 本身的边框,然后将其放在 ::after
pseudo-element 上,这样边框和背景都是 children。边框现在似乎与背景渐变一致。
例子
.Button {
width: 200px;
height: 30px;
cursor: pointer;
padding: 0.8rem;
position: relative;
margin-top: 10px;
transition: color 0.2s;
}
.Button::before {
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient( to right, green 0%, blue 100%);
opacity: 0.2;
transition: opacity 0.2s;
}
.Button:hover::before {
opacity: 0.5;
}
.Button:active::before {
opacity: 1;
}
.Button::after {
content: '';
border-style: solid;
border-image: linear-gradient( to right, green 0%, blue 100%);
border-image-slice: 1;
border-width: 1px;
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
}
html {
height: 100%;
display: table;
margin: auto;
}
body {
background: black;
display: table-cell;
vertical-align: middle;
color: white;
font-family: sans-serif;
}
Click it:
<div class="Button"></div>